Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of BCP Golmon v1.0.0
BrutalCompanyPlus.dll
Decompiled 2 years agousing System; 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 BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using BrutalCompanyPlus.Api; using BrutalCompanyPlus.Config; using BrutalCompanyPlus.Events; using BrutalCompanyPlus.Objects; using BrutalCompanyPlus.Utils; using DunGen; using GameNetcodeStuff; using HarmonyLib; using JetBrains.Annotations; using Microsoft.CodeAnalysis; using Unity.Netcode; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("BrutalCompanyPlus")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyDescription("A CUSTOMIZABLE hardcore mod that randomizes events ranging between insanity and normal.")] [assembly: AssemblyFileVersion("4.0.0.0")] [assembly: AssemblyInformationalVersion("4.0.0")] [assembly: AssemblyProduct("BrutalCompanyPlus")] [assembly: AssemblyTitle("BrutalCompanyPlus")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("4.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] internal class <Module> { static <Module>() { } } namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [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 BrutalCompanyPlus { [BepInPlugin("BrutalCompanyPlus", "BrutalCompanyPlus", "4.0.0")] [BepInProcess("Lethal Company.exe")] public class Plugin : BaseUnityPlugin { internal static ManualLogSource Logger; internal static GameObject BCNetworkManagerPrefab; private void Awake() { Logger = ((BaseUnityPlugin)this).Logger; PluginConfig.Bind(this); EventRegistry.AutoRegister((BaseUnityPlugin)(object)this); BcpUtils.InitializeNetcode(); InitializeBCNetworkManager(); Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), (string)null); Logger.LogWarning((object)"BrutalCompanyPlus initialized..."); } private static void InitializeBCNetworkManager() { Logger.LogWarning((object)"Initializing BCNetworkManager..."); AssetBundle val = AssetBundle.LoadFromStream(Assembly.GetExecutingAssembly().GetManifestResourceStream("BrutalCompanyPlus.Assets.brutalcompanyplus")); BCNetworkManagerPrefab = val.LoadAsset<GameObject>("Assets/BCNetworkManager.prefab"); BCNetworkManagerPrefab.AddComponent<BCNetworkManager>(); val.Unload(false); } } public static class PluginInfo { public const string PLUGIN_GUID = "BrutalCompanyPlus"; public const string PLUGIN_NAME = "BrutalCompanyPlus"; public const string PLUGIN_VERSION = "4.0.0"; } } namespace BrutalCompanyPlus.Utils { public static class BcpUtils { internal static void InitializeNetcode() { Type[] types = Assembly.GetExecutingAssembly().GetTypes(); foreach (Type type in types) { MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic); MethodInfo[] array = methods; foreach (MethodInfo methodInfo in array) { object[] customAttributes = methodInfo.GetCustomAttributes(typeof(RuntimeInitializeOnLoadMethodAttribute), inherit: false); if (!customAttributes.IsEmpty()) { Plugin.Logger.LogWarning((object)("Initializing RPCs for " + type.Name + "...")); methodInfo.Invoke(null, null); } } } } public static void AddCredits(this Terminal Terminal, int Amount) { Terminal.groupCredits += Amount; Terminal.SyncGroupCreditsServerRpc(Terminal.groupCredits, Terminal.numberOfItemsInDropship); } public static Vector3 GetNearbyLocation(Vector3 Location) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) Vector3 val = Random.insideUnitSphere * 10f; return Location + val; } public static GameObject FindObjectPrefab<T>(this SelectableLevel Level) where T : MonoBehaviour { SpawnableMapObject[] spawnableMapObjects = Level.spawnableMapObjects; foreach (SpawnableMapObject val in spawnableMapObjects) { if (val.IsObjectTypeOf<T>(out var _)) { return val.prefabToSpawn; } } throw new Exception("Unable to find prefab of type " + typeof(T).Name + " in level " + ((Object)Level).name + "."); } public static bool IsObjectTypeOf<T>(this SpawnableMapObject MapObject, out T Component) { Component = MapObject.prefabToSpawn.GetComponentInChildren<T>(); return Component != null; } public static bool IntInRange(this IntRange Range, int Value) { if (Value >= Range.Min) { return Value <= Range.Max; } return false; } public static bool IsEmpty<T>(this IEnumerable<T> Collection) { return !Collection.Any(); } public static List<T> TakeIf<T>(this List<T> List, Func<T, bool> Predicate) { List<T> result = List.Where(Predicate).ToList(); List.RemoveAll((T E) => Predicate(E)); return result; } public static bool Random<T>(this List<T> List, out T Value) { if (List.IsEmpty()) { Value = default(T); return false; } Value = List[Random.Range(0, List.Count)]; return true; } public static bool Random<T>(this T[] Array, out T Value) { if (Array.IsEmpty()) { Value = default(T); return false; } Value = Array[Random.Range(0, Array.Length)]; return true; } public static bool Random<T>(this IEnumerable<T> Enumerable, out T Value) { return Enumerable.ToList().Random(out Value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ForEach<T, TResult>(this IEnumerable<T> Collection, Func<T, TResult> Action) { foreach (T item in Collection) { Action(item); } } } public static class ChatUtils { public static void Send(string Message, bool Clear = false) { if (Clear) { ChatUtils.Clear(); } HUDManager.Instance.AddTextToChatOnServer(Message, -1); } public static void SendLocal(string Message, bool Clear = false) { if (Clear) { ChatUtils.Clear(); } HUDManager.Instance.AddChatMessage(Message, ""); } private static void Clear() { Send("\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"); } internal static void NotifyError() { SendLocal("An error occurred in BrutalCompanyPlus. Check the console for more information."); } } public static class ConfigUtils { public static bool GetIfSet<T>(this ConfigEntry<T> Entry, out T Value) where T : notnull { T value = Entry.Value; if (value is int && (int)(object)/*isinst with value type is only supported in some contexts*/ == -1) { Value = default(T); return false; } Value = Entry.Value; return true; } internal static Dictionary<string, int> GetEnemyRarityValues(string LevelName) { string[] array = ((ConfigEntry<string>)(LevelName switch { "ExperimentationLevel" => PluginConfig.EnemyRarityValues.ExperimentationLevel, "AssuranceLevel" => PluginConfig.EnemyRarityValues.AssuranceLevel, "VowLevel" => PluginConfig.EnemyRarityValues.VowLevel, "OffenseLevel" => PluginConfig.EnemyRarityValues.OffenseLevel, "MarchLevel" => PluginConfig.EnemyRarityValues.MarchLevel, "RendLevel" => PluginConfig.EnemyRarityValues.RendLevel, "DineLevel" => PluginConfig.EnemyRarityValues.DineLevel, "TitanLevel" => PluginConfig.EnemyRarityValues.TitanLevel, _ => PluginConfig.EnemyRarityValues.CustomLevel, })).Value.Split(','); Dictionary<string, int> dictionary = new Dictionary<string, int>(); string[] array2 = array; foreach (string text in array2) { try { var (key, value) = ParseHelpers.ParseEnemyRarityEntry(text); dictionary.Add(key, value); } catch (ParseException arg) { Diagnostics.AddError($"Bad entry in enemy rarity values ({text}): {arg}"); } } if (!dictionary.IsEmpty()) { return dictionary; } Plugin.Logger.LogError((object)("Invalid enemy rarity values: " + PluginConfig.MoonHeat.HeatCurve.Value)); return dictionary; } internal static (int, int, int, int) GetScrapValues(string LevelName) { string text = ((ConfigEntry<string>)(LevelName switch { "ExperimentationLevel" => PluginConfig.ScrapValues.ExperimentationLevel, "AssuranceLevel" => PluginConfig.ScrapValues.AssuranceLevel, "VowLevel" => PluginConfig.ScrapValues.VowLevel, "OffenseLevel" => PluginConfig.ScrapValues.OffenseLevel, "MarchLevel" => PluginConfig.ScrapValues.MarchLevel, "RendLevel" => PluginConfig.ScrapValues.RendLevel, "DineLevel" => PluginConfig.ScrapValues.DineLevel, "TitanLevel" => PluginConfig.ScrapValues.TitanLevel, _ => PluginConfig.ScrapValues.CustomLevel, })).Value.Trim(); if (text == "-1,-1,-1,-1") { Plugin.Logger.LogWarning((object)("Using default scrap values for " + LevelName)); return (-1, -1, -1, -1); } try { return ParseHelpers.ParseScrapValues(text); } catch (ParseException arg) { Diagnostics.AddError($"Invalid scrap values ({text}): {arg}"); return (-1, -1, -1, -1); } } internal static List<(int, int, LevelWeatherType)> GetMoonHeatCurve() { List<(int, int, LevelWeatherType)> list = new List<(int, int, LevelWeatherType)>(); string[] array = PluginConfig.MoonHeat.HeatCurve.Value.Split(','); foreach (string text in array) { try { (int, int, LevelWeatherType) item = ParseHelpers.ParseHeatCurvePoint(text); list.Add(item); } catch (ParseException arg) { Diagnostics.AddError($"Bad point in moon heat curve ({text}): {arg}"); } } if (!list.IsEmpty()) { return list; } Plugin.Logger.LogError((object)("Invalid moon heat curve: " + PluginConfig.MoonHeat.HeatCurve.Value)); Plugin.Logger.LogError((object)"Using fallback curve instead (0-100%: no weather)"); list.Add((0, 101, (LevelWeatherType)(-1))); return list; } } internal static class Diagnostics { private static readonly List<string> Errors = new List<string>(); internal static bool HasErrors => !Errors.IsEmpty(); internal static void AddError(string Error) { Errors.Add(Error); Plugin.Logger.LogError((object)Error); } internal static string CollectErrors() { string result = string.Join("\n", Errors); Errors.Clear(); return result; } } internal static class EnemyUtils { private static readonly Dictionary<string, EnemyType> InsideEnemyTypes = new Dictionary<string, EnemyType>(); private static readonly Dictionary<string, EnemyType> OutsideEnemyTypes = new Dictionary<string, EnemyType>(); internal static void SpawnInsideEnemy(RoundManager Instance, GameObject EnemyPrefab) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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_003d: 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_0082: Unknown result type (might be due to invalid IL or missing references) if (Instance.allEnemyVents.Random(out var Value)) { Vector3 position = Value.floorNode.position; Quaternion val = Quaternion.Euler(0f, Value.floorNode.eulerAngles.y, 0f); GameObject val2 = Object.Instantiate<GameObject>(EnemyPrefab, position, val); val2.GetComponentInChildren<NetworkObject>().Spawn(true); EnemyAI component = val2.GetComponent<EnemyAI>(); if (component.enemyType.isOutsideEnemy) { component.enemyType = SetOutsideEnemy(component.enemyType, IsOutside: false); BCNetworkManager.Instance.SyncEnemyTypeClientRpc(NetworkBehaviourReference.op_Implicit((NetworkBehaviour)(object)component), IsOutside: false); } Instance.SpawnedEnemies.Add(component); } } internal static void SpawnOutsideEnemy(RoundManager Instance, GameObject EnemyPrefab) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) if (GameObject.FindGameObjectsWithTag("OutsideAINode").Random(out var Value)) { GameObject val = Object.Instantiate<GameObject>(EnemyPrefab, Value.transform.position, Quaternion.identity); val.GetComponentInChildren<NetworkObject>().Spawn(true); EnemyAI component = val.GetComponent<EnemyAI>(); if (!component.enemyType.isOutsideEnemy) { component.enemyType = SetOutsideEnemy(component.enemyType, IsOutside: true); BCNetworkManager.Instance.SyncEnemyTypeClientRpc(NetworkBehaviourReference.op_Implicit((NetworkBehaviour)(object)component), IsOutside: true); } Instance.SpawnedEnemies.Add(component); } } internal static EnemyType SetOutsideEnemy(EnemyType OriginalType, bool IsOutside) { EnemyType value2; if (IsOutside) { if (OutsideEnemyTypes.TryGetValue(OriginalType.enemyName, out var value)) { return value; } } else if (InsideEnemyTypes.TryGetValue(OriginalType.enemyName, out value2)) { return value2; } EnemyType val = Object.Instantiate<EnemyType>(OriginalType); val.isOutsideEnemy = IsOutside; if (IsOutside) { OutsideEnemyTypes.Add(OriginalType.enemyName, val); } else { InsideEnemyTypes.Add(OriginalType.enemyName, val); } return val; } } internal static class LevelDefaults { internal static readonly Dictionary<string, Dictionary<string, int>> DefaultEnemyRarityValues = new Dictionary<string, Dictionary<string, int>> { { "ExperimentationLevel", new Dictionary<string, int> { { "Centipede", 50 }, { "Bunker Spider", 75 }, { "Hoarding bug", 80 }, { "Flowerman", 30 }, { "Crawler", 15 }, { "Blob", 25 }, { "Girl", 2 }, { "Puffer", 10 }, { "Nutcracker", 15 }, { "Spring", 5 }, { "Jester", 1 }, { "Masked", 1 }, { "Lasso", 1 } } }, { "AssuranceLevel", new Dictionary<string, int> { { "Centipede", 50 }, { "Bunker Spider", 40 }, { "Hoarding bug", 50 }, { "Flowerman", 30 }, { "Crawler", 15 }, { "Blob", 25 }, { "Girl", 2 }, { "Puffer", 40 }, { "Nutcracker", 15 }, { "Spring", 25 }, { "Jester", 3 }, { "Masked", 3 }, { "Lasso", 1 } } }, { "VowLevel", new Dictionary<string, int> { { "Centipede", 50 }, { "Bunker Spider", 40 }, { "Hoarding bug", 50 }, { "Flowerman", 30 }, { "Crawler", 20 }, { "Blob", 25 }, { "Girl", 5 }, { "Puffer", 40 }, { "Nutcracker", 20 }, { "Spring", 40 }, { "Jester", 15 }, { "Masked", 10 }, { "Lasso", 0 } } }, { "OffenseLevel", new Dictionary<string, int> { { "Centipede", 50 }, { "Bunker Spider", 40 }, { "Hoarding bug", 50 }, { "Flowerman", 30 }, { "Crawler", 20 }, { "Blob", 25 }, { "Girl", 5 }, { "Puffer", 40 }, { "Nutcracker", 20 }, { "Spring", 40 }, { "Jester", 15 }, { "Masked", 10 }, { "Lasso", 0 } } }, { "MarchLevel", new Dictionary<string, int> { { "Centipede", 50 }, { "Bunker Spider", 40 }, { "Hoarding bug", 50 }, { "Flowerman", 30 }, { "Crawler", 20 }, { "Blob", 25 }, { "Girl", 10 }, { "Puffer", 40 }, { "Nutcracker", 20 }, { "Spring", 40 }, { "Jester", 15 }, { "Masked", 10 }, { "Lasso", 0 } } }, { "RendLevel", new Dictionary<string, int> { { "Centipede", 35 }, { "Bunker Spider", 25 }, { "Hoarding bug", 30 }, { "Flowerman", 56 }, { "Crawler", 50 }, { "Blob", 40 }, { "Girl", 25 }, { "Puffer", 40 }, { "Nutcracker", 30 }, { "Spring", 58 }, { "Jester", 40 }, { "Masked", 10 }, { "Lasso", 2 } } }, { "DineLevel", new Dictionary<string, int> { { "Centipede", 35 }, { "Bunker Spider", 25 }, { "Hoarding bug", 30 }, { "Flowerman", 56 }, { "Crawler", 50 }, { "Blob", 40 }, { "Girl", 25 }, { "Puffer", 40 }, { "Nutcracker", 30 }, { "Spring", 58 }, { "Jester", 40 }, { "Masked", 10 }, { "Lasso", 2 } } }, { "TitanLevel", new Dictionary<string, int> { { "Centipede", 35 }, { "Bunker Spider", 25 }, { "Hoarding bug", 30 }, { "Flowerman", 56 }, { "Crawler", 60 }, { "Blob", 40 }, { "Girl", 25 }, { "Puffer", 40 }, { "Nutcracker", 30 }, { "Spring", 58 }, { "Jester", 40 }, { "Masked", 10 }, { "Lasso", 2 } } }, { "???_custom_???", new Dictionary<string, int> { { "Centipede", 35 }, { "Bunker Spider", 25 }, { "Hoarding bug", 30 }, { "Flowerman", 56 }, { "Crawler", 60 }, { "Blob", 40 }, { "Girl", 25 }, { "Puffer", 40 }, { "Nutcracker", 30 }, { "Spring", 58 }, { "Jester", 40 }, { "Masked", 10 }, { "Lasso", 2 } } } }; } public static class LevelNames { public const string CompanyBuilding = "CompanyBuildingLevel"; public const string Experimentation = "ExperimentationLevel"; public const string Assurance = "AssuranceLevel"; public const string Vow = "VowLevel"; public const string Offense = "OffenseLevel"; public const string March = "MarchLevel"; public const string Rend = "RendLevel"; public const string Dine = "DineLevel"; public const string Titan = "TitanLevel"; internal const string Custom = "???_custom_???"; public static readonly string[] All = new string[8] { "ExperimentationLevel", "AssuranceLevel", "VowLevel", "OffenseLevel", "MarchLevel", "RendLevel", "DineLevel", "TitanLevel" }; internal static readonly string[] AllCustom = All.Concat(new string[1] { "???_custom_???" }).ToArray(); public static bool IsCustom(string LevelName) { return !All.Contains(LevelName); } } internal static class ParseHelpers { private static readonly string RangeError = $"must be between {MoonHeatManager.MoonHeatRange.Min} and {MoonHeatManager.MoonHeatRange.Max}"; internal static (int, int, LevelWeatherType) ParseHeatCurvePoint(string Point) { //IL_00ae: Unknown result type (might be due to invalid IL or missing references) string[] array = Point.Split(':'); if (array.Length != 3) { throw new ParseException("invalid format"); } if (!int.TryParse(array[0], out var result)) { throw new ParseException("invalid start value"); } if (!MoonHeatManager.MoonHeatRange.IntInRange(result)) { throw new ParseException("start value out of range, " + RangeError); } if (!int.TryParse(array[1], out var result2)) { throw new ParseException("invalid end value"); } if (!MoonHeatManager.MoonHeatRange.IntInRange(Math.Max(0, result2 - 1))) { throw new ParseException("end value out of range, " + RangeError); } if (!Enum.TryParse<LevelWeatherType>(array[2], out LevelWeatherType result3)) { throw new ParseException("invalid weather type"); } return (result, result2, result3); } internal static (int, int, int, int) ParseScrapValues(string Entries) { string[] array = Entries.Split(','); if (array.Length != 4) { throw new ParseException("invalid format"); } if (!int.TryParse(array[0], out var result)) { throw new ParseException("invalid minScrap value"); } if (!int.TryParse(array[1], out var result2)) { throw new ParseException("invalid maxScrap value"); } if (!int.TryParse(array[2], out var result3)) { throw new ParseException("invalid minTotalScrapValue value"); } if (!int.TryParse(array[3], out var result4)) { throw new ParseException("invalid maxTotalScrapValue value"); } return (result, result2, result3, result4); } internal static (string, int) ParseEnemyRarityEntry(string Entry) { string[] array = Entry.Split(':'); if (array.Length != 2) { throw new ParseException("invalid format"); } string item; if (string.IsNullOrEmpty(item = array[0])) { throw new ParseException("invalid enemy name"); } if (!int.TryParse(array[1], out var result)) { throw new ParseException("invalid rarity value"); } return (item, result); } } internal class ParseException : Exception { public ParseException(string Message) : base(Message) { } public override string ToString() { return Message; } } public static class PlayerUtils { public static IEnumerable<PlayerControllerB> AllPlayers => StartOfRound.Instance.allPlayerScripts.Where((PlayerControllerB Player) => Player.isPlayerControlled); public static IEnumerable<PlayerControllerB> AlivePlayers => AllPlayers.Where((PlayerControllerB Player) => !Player.isPlayerDead); public static IEnumerable<PlayerControllerB> OutsidePlayers => AlivePlayers.Where((PlayerControllerB Player) => !Player.isInHangarShipRoom && !Player.isInsideFactory); } public static class Singleton { public static Terminal Terminal => Object.FindObjectOfType<Terminal>(); } } namespace BrutalCompanyPlus.Patches { [HarmonyPatch] internal static class EnemyPatches { private const string Tag = "[EnemyPatches]"; [HarmonyPrefix] [HarmonyPatch(typeof(RoundManager), "BeginEnemySpawning")] private static void SpawnPendingEnemiesImmediately(ref RoundManager __instance) { if (EnemySpawnManager.PendingSpawns.IsEmpty()) { return; } foreach (var (val, spawnInfo) in EnemySpawnManager.PendingSpawns.TakeIf(((EnemyType EnemyType, EnemySpawnManager.SpawnInfo SpawnInfo) si) => si.SpawnInfo.Immediate)) { Plugin.Logger.LogInfo((object)string.Format("{0} Spawning {1} {2} (outside: {3}) enemies... (immediate)", "[EnemyPatches]", spawnInfo.Amount, val.enemyName, spawnInfo.Outside)); for (int i = 0; i < spawnInfo.Amount; i++) { if (spawnInfo.Outside) { EnemyUtils.SpawnOutsideEnemy(__instance, val.enemyPrefab); } else { EnemyUtils.SpawnInsideEnemy(__instance, val.enemyPrefab); } } } } [HarmonyPrefix] [HarmonyPatch(typeof(RoundManager), "SpawnInsideEnemiesFromVentsIfReady")] private static void SpawnPendingEnemiesDelayed(ref RoundManager __instance) { if (EnemySpawnManager.PendingSpawns.IsEmpty() || !StartOfRound.Instance.allPlayerScripts.Any((PlayerControllerB player) => player.isInsideFactory)) { return; } foreach (var (val, spawnInfo) in EnemySpawnManager.PendingSpawns.TakeIf(((EnemyType EnemyType, EnemySpawnManager.SpawnInfo SpawnInfo) si) => !si.SpawnInfo.Immediate)) { Plugin.Logger.LogInfo((object)string.Format("{0} Spawning {1} {2} (outside: {3}) enemies... (delayed)", "[EnemyPatches]", spawnInfo.Amount, val.enemyName, spawnInfo.Outside)); for (int i = 0; i < spawnInfo.Amount; i++) { if (spawnInfo.Outside) { EnemyUtils.SpawnOutsideEnemy(__instance, val.enemyPrefab); } else { EnemyUtils.SpawnInsideEnemy(__instance, val.enemyPrefab); } } } } } [HarmonyPatch] internal static class LevelPatches { [HarmonyPostfix] [HarmonyPriority(0)] [HarmonyPatch(typeof(StartOfRound), "Start")] private static void ModifyLevelsPatch(ref StartOfRound __instance) { if (!((NetworkBehaviour)__instance).IsHost) { return; } LevelManager.AddAllEnemiesToAllLevels(__instance.levels); SelectableLevel[] levels = __instance.levels; foreach (SelectableLevel val in levels) { if (!(((Object)val).name == "CompanyBuildingLevel")) { MoonHeatManager.InitializeFor(val); LevelManager.ApplyEnemyRarityValues(val); LevelManager.ApplyEnemySpawnChances(val); LevelManager.ApplyEnemySpawnRates(val); LevelManager.ApplyLevelProperties(val); } } } [HarmonyPrefix] [HarmonyPriority(0)] [HarmonyPatch(typeof(RoundManager), "LoadNewLevel")] private static void SelectLevelEventPatch(ref RoundManager __instance, ref SelectableLevel newLevel) { if (((NetworkBehaviour)__instance).IsHost) { if (((Object)newLevel).name == "CompanyBuildingLevel") { Plugin.Logger.LogWarning((object)"Landed at the Company Building, forcing no event..."); ChatUtils.Send("<color=green>Welcome to the Company Building!</color>", Clear: true); } else { MoonHeatManager.AdjustHeatValues(newLevel); EventManager.StartEventServer(newLevel); } } } [HarmonyPostfix] [HarmonyPatch(typeof(RoundManager), "DespawnPropsAtEndOfRound")] private static void HandleLevelEventEndPatch(ref RoundManager __instance) { if (((NetworkBehaviour)__instance).IsHost) { EventManager.EndEventServer(__instance.currentLevel); } } } [HarmonyPatch] internal static class MoneyPatches { [HarmonyPostfix] [HarmonyPatch(typeof(TimeOfDay), "Awake")] private static void AdjustQuotaValues(ref TimeOfDay __instance) { Plugin.Logger.LogWarning((object)"Adjusting starting quota values..."); if (PluginConfig.QuotaAdjustments.DeadlineDays.GetIfSet<int>(out var Value)) { __instance.quotaVariables.deadlineDaysAmount = Value; } if (PluginConfig.QuotaAdjustments.StartingCredits.GetIfSet<int>(out Value)) { __instance.quotaVariables.startingCredits = Value; } if (PluginConfig.QuotaAdjustments.StartingQuota.GetIfSet<int>(out Value)) { __instance.quotaVariables.startingQuota = Value; } if (PluginConfig.QuotaAdjustments.BaseIncrease.GetIfSet<int>(out Value)) { __instance.quotaVariables.baseIncrease = Value; } } [HarmonyPrefix] [HarmonyPatch(typeof(RoundManager), "DetectElevatorIsRunning")] private static void CompensatePlayersPatch(ref RoundManager __instance) { if (((NetworkBehaviour)__instance).IsServer) { if (StartOfRound.Instance.allPlayersDead) { ChatUtils.Send("<size=10><color=red>That was brutal! No compensation today :c</color></size>", Clear: true); return; } int value = PluginConfig.CreditsAdjustments.FreeMoneyAmount.Value; Singleton.Terminal.AddCredits(value); ChatUtils.Send("<size=10><color=green>You survived another day! Here's your compensation :)\n" + $"<color=orange>+{value} credits</color></size>", Clear: true); } } } [HarmonyPatch] internal static class NetcodePatches { [HarmonyPatch(typeof(GameNetworkManager), "Start")] [HarmonyPostfix] private static void InjectNetworkManager() { NetworkManager.Singleton.AddNetworkPrefab(Plugin.BCNetworkManagerPrefab); } [HarmonyPatch(typeof(StartOfRound), "Awake")] [HarmonyPostfix] private static void SpawnNetworkManager() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) if (NetworkManager.Singleton.IsHost || NetworkManager.Singleton.IsServer) { Object.Instantiate<GameObject>(Plugin.BCNetworkManagerPrefab, Vector3.zero, Quaternion.identity).GetComponent<NetworkObject>().Spawn(false); } } } [HarmonyPatch(typeof(PlayerControllerB))] internal static class PlayerPatches { [HarmonyPostfix] [HarmonyPatch("Start")] private static void ShowDiagnosticsPatch(PlayerControllerB __instance) { __instance.movementAudio.priority = 127; } } [HarmonyPatch] internal class SharedEnemyAIPatches { private static Vector3 ShipLocation => StartOfRound.Instance.playerSpawnPositions[0].position; [HarmonyPrefix] [HarmonyPriority(800)] [HarmonyPatch(typeof(EnemyAI), "StartSearch")] private static void SpringManSearchFromShipPatch(ref EnemyAI __instance, ref Vector3 startOfSearch) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) if (__instance is SpringManAI && __instance.isOutside) { startOfSearch = BcpUtils.GetNearbyLocation(ShipLocation); } } [HarmonyPostfix] [HarmonyPatch(typeof(FlowermanAI), "Start")] private static void FlowermanOutsideFavoritePositionPatch(ref FlowermanAI __instance) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) if (((EnemyAI)__instance).isOutside) { __instance.mainEntrancePosition = ShipLocation; } } [HarmonyPrefix] [HarmonyPatch(typeof(BlobAI), "HitEnemy")] private static bool BlobDamageLagPatch(ref PlayerControllerB playerWhoHit) { return (Object)(object)playerWhoHit != (Object)null; } } [HarmonyPatch(typeof(MenuManager))] internal static class UIPatches { [HarmonyPostfix] [HarmonyPatch("Start")] private static void ShowDiagnosticsPatch(MenuManager __instance) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown if (!__instance.isInitScene && Diagnostics.HasErrors) { __instance.DisplayMenuNotification("[BrutalCompanyPlus]\nOne or more errors occurred during startup:\n" + Diagnostics.CollectErrors() + "\n\n", "[ Quit ]"); ((UnityEvent)__instance.menuNotification.GetComponentInChildren<Button>().onClick).AddListener(new UnityAction(__instance.ClickQuitButton)); } } } } namespace BrutalCompanyPlus.Objects { public class BCNetworkManager : NetworkBehaviour { private const string Tag = "[BCNetworkManager]"; private const string DisconnectMessage = "BrutalCompanyPlus\nServer sent invalid enemy reference!\nThis is a bug, please report it!"; public static BCNetworkManager Instance { get; private set; } private void Awake() { Instance = this; Log("BCNetworkManager initialized!"); } private void Update() { if (((NetworkBehaviour)this).IsServer && ((NetworkBehaviour)this).IsHost && EventManager.CurrentEvent != null) { EventManager.CurrentEvent.UpdateServer(); } } [ClientRpc] public void SyncEnemyTypeClientRpc(NetworkBehaviourReference Reference, bool IsOutside) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)base.__rpc_exec_stage != 2 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val = default(ClientRpcParams); FastBufferWriter val2 = ((NetworkBehaviour)this).__beginSendClientRpc(2971397334u, val, (RpcDelivery)0); ((FastBufferWriter)(ref val2)).WriteValueSafe<NetworkBehaviourReference>(ref Reference, default(ForNetworkSerializable)); ((FastBufferWriter)(ref val2)).WriteValueSafe<bool>(ref IsOutside, default(ForPrimitives)); ((NetworkBehaviour)this).__endSendClientRpc(ref val2, 2971397334u, val, (RpcDelivery)0); } if ((int)base.__rpc_exec_stage != 2 || (!networkManager.IsClient && !networkManager.IsHost) || ((NetworkBehaviour)this).IsServer || ((NetworkBehaviour)this).IsHost) { return; } Log($"Syncing enemy type (outside: {IsOutside})... (client)"); EnemyAI val3 = default(EnemyAI); if (!((NetworkBehaviourReference)(ref Reference)).TryGet<EnemyAI>(ref val3, (NetworkManager)null)) { Log("Bad enemy received from server! Disconnecting client to prevent further issues... (client)"); GameNetworkManager.Instance.disconnectionReasonMessage = "BrutalCompanyPlus\nServer sent invalid enemy reference!\nThis is a bug, please report it!"; GameNetworkManager.Instance.Disconnect(); return; } val3.enemyType = EnemyUtils.SetOutsideEnemy(val3.enemyType, IsOutside); if (val3.path1 != null) { Plugin.Logger.LogWarning((object)("Received SyncEnemyType RPC for " + ((Object)val3).name + " too late, catching up...")); val3.isOutside = IsOutside; val3.allAINodes = GameObject.FindGameObjectsWithTag(IsOutside ? "OutsideAINode" : "AINode"); if ((Object)(object)GameNetworkManager.Instance.localPlayerController != (Object)null) { val3.EnableEnemyMesh(!StartOfRound.Instance.hangarDoorsClosed || !GameNetworkManager.Instance.localPlayerController.isInHangarShipRoom, false); } } } [ClientRpc] public void StartEventClientRpc(int EventId, int LevelId) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)base.__rpc_exec_stage != 2 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val = default(ClientRpcParams); FastBufferWriter val2 = ((NetworkBehaviour)this).__beginSendClientRpc(554658467u, val, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val2, EventId); BytePacker.WriteValueBitPacked(val2, LevelId); ((NetworkBehaviour)this).__endSendClientRpc(ref val2, 554658467u, val, (RpcDelivery)0); } if ((int)base.__rpc_exec_stage != 2 || (!networkManager.IsClient && !networkManager.IsHost) || ((NetworkBehaviour)this).IsServer || ((NetworkBehaviour)this).IsHost) { return; } Log($"Received start event request: eid = {EventId}, lid = {LevelId}"); IEvent @event = EventRegistry.GetEvent(EventId); if (@event == null) { Log($"Bad event id {EventId} received from server."); return; } SelectableLevel val3 = StartOfRound.Instance.levels.ElementAtOrDefault(LevelId); if ((Object)(object)val3 == (Object)null) { Log($"Bad level id {LevelId} received from server."); } else { EventManager.StartEventClient(val3, @event); } } [ClientRpc] public void EndEventClientRpc() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager != null && networkManager.IsListening) { if ((int)base.__rpc_exec_stage != 2 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val = default(ClientRpcParams); FastBufferWriter val2 = ((NetworkBehaviour)this).__beginSendClientRpc(3012541483u, val, (RpcDelivery)0); ((NetworkBehaviour)this).__endSendClientRpc(ref val2, 3012541483u, val, (RpcDelivery)0); } if ((int)base.__rpc_exec_stage == 2 && (networkManager.IsClient || networkManager.IsHost) && !((NetworkBehaviour)this).IsServer && !((NetworkBehaviour)this).IsHost) { Log("Received end event request... (client)"); EventManager.EndEventClient(RoundManager.Instance.currentLevel); } } } [ClientRpc] public void SyncWeatherClientRpc(int LevelId, LevelWeatherType WeatherType) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)base.__rpc_exec_stage != 2 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val = default(ClientRpcParams); FastBufferWriter val2 = ((NetworkBehaviour)this).__beginSendClientRpc(4219652153u, val, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val2, LevelId); ((FastBufferWriter)(ref val2)).WriteValueSafe<LevelWeatherType>(ref WeatherType, default(ForEnums)); ((NetworkBehaviour)this).__endSendClientRpc(ref val2, 4219652153u, val, (RpcDelivery)0); } if ((int)base.__rpc_exec_stage == 2 && (networkManager.IsClient || networkManager.IsHost)) { Log($"Syncing weather type {WeatherType} on level {LevelId}..."); SelectableLevel val3 = StartOfRound.Instance.levels.ElementAtOrDefault(LevelId); if ((Object)(object)val3 == (Object)null) { Log($"Bad level id {LevelId} received from server."); } else { val3.currentWeather = WeatherType; } } } private static void Log(string Message) { Plugin.Logger.LogWarning((object)("[BCNetworkManager] " + Message)); } protected override void __initializeVariables() { ((NetworkBehaviour)this).__initializeVariables(); } [RuntimeInitializeOnLoadMethod] internal static void InitializeRPCS_BCNetworkManager() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected O, but got Unknown //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Expected O, but got Unknown NetworkManager.__rpc_func_table.Add(2971397334u, new RpcReceiveHandler(__rpc_handler_2971397334)); NetworkManager.__rpc_func_table.Add(554658467u, new RpcReceiveHandler(__rpc_handler_554658467)); NetworkManager.__rpc_func_table.Add(3012541483u, new RpcReceiveHandler(__rpc_handler_3012541483)); NetworkManager.__rpc_func_table.Add(4219652153u, new RpcReceiveHandler(__rpc_handler_4219652153)); } private static void __rpc_handler_2971397334(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005f: 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_007d: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = target.NetworkManager; if (networkManager != null && networkManager.IsListening) { NetworkBehaviourReference reference = default(NetworkBehaviourReference); ((FastBufferReader)(ref reader)).ReadValueSafe<NetworkBehaviourReference>(ref reference, default(ForNetworkSerializable)); bool isOutside = default(bool); ((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref isOutside, default(ForPrimitives)); target.__rpc_exec_stage = (__RpcExecStage)2; ((BCNetworkManager)(object)target).SyncEnemyTypeClientRpc(reference, isOutside); target.__rpc_exec_stage = (__RpcExecStage)0; } } private static void __rpc_handler_554658467(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = target.NetworkManager; if (networkManager != null && networkManager.IsListening) { int eventId = default(int); ByteUnpacker.ReadValueBitPacked(reader, ref eventId); int levelId = default(int); ByteUnpacker.ReadValueBitPacked(reader, ref levelId); target.__rpc_exec_stage = (__RpcExecStage)2; ((BCNetworkManager)(object)target).StartEventClientRpc(eventId, levelId); target.__rpc_exec_stage = (__RpcExecStage)0; } } private static void __rpc_handler_3012541483(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = target.NetworkManager; if (networkManager != null && networkManager.IsListening) { target.__rpc_exec_stage = (__RpcExecStage)2; ((BCNetworkManager)(object)target).EndEventClientRpc(); target.__rpc_exec_stage = (__RpcExecStage)0; } } private static void __rpc_handler_4219652153(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0060: 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) NetworkManager networkManager = target.NetworkManager; if (networkManager != null && networkManager.IsListening) { int levelId = default(int); ByteUnpacker.ReadValueBitPacked(reader, ref levelId); LevelWeatherType weatherType = default(LevelWeatherType); ((FastBufferReader)(ref reader)).ReadValueSafe<LevelWeatherType>(ref weatherType, default(ForEnums)); target.__rpc_exec_stage = (__RpcExecStage)2; ((BCNetworkManager)(object)target).SyncWeatherClientRpc(levelId, weatherType); target.__rpc_exec_stage = (__RpcExecStage)0; } } protected internal override string __getTypeName() { return "BCNetworkManager"; } } public static class EnemySpawnManager { public readonly struct SpawnInfo { public readonly int Amount; public readonly bool Outside; public readonly bool Immediate; public SpawnInfo(int Amount, bool Outside = false, bool Immediate = true) { this.Amount = Amount; this.Outside = Outside; this.Immediate = Immediate; } } internal static readonly List<(EnemyType EnemyType, SpawnInfo SpawnInfo)> PendingSpawns = new List<(EnemyType, SpawnInfo)>(); public static void DraftEnemySpawn<T>(SpawnInfo Info) where T : EnemyAI { if (!LevelManager.TryGetEnemy<T>(out var EnemyType)) { throw new ArgumentException("Failed to get EnemyType for " + typeof(T).Name + "!"); } PendingSpawns.Add((EnemyType, Info)); } public static void DraftEnemySpawn(EnemyType Type, SpawnInfo Info) { PendingSpawns.Add((Type, Info)); } } public static class EventManager { internal static IEvent CurrentEvent; public static bool IsActive<T>() where T : IEvent { return CurrentEvent is T; } public static void StartEventServer(SelectableLevel Level) { if (CurrentEvent != null) { Plugin.Logger.LogError((object)"StartEventServer called twice, this shouldn't happen! (do you have LE installed?)"); return; } IEvent @event = SelectRandomEvent(Level); if (@event != null) { Plugin.Logger.LogWarning((object)("Starting event " + @event.Name + "... (server)")); BCNetworkManager.Instance.StartEventClientRpc(@event.GetId(), Level.levelID); @event.ExecuteServer(Level); NotifyEventStarted(@event); CurrentEvent = @event; } } public static void EndEventServer(SelectableLevel Level) { if (CurrentEvent == null) { Plugin.Logger.LogError((object)"EndEventServer called without an active event, please report this!"); ChatUtils.NotifyError(); return; } Plugin.Logger.LogWarning((object)("Ending event " + CurrentEvent.Name + "... (server)")); BCNetworkManager.Instance.EndEventClientRpc(); CurrentEvent.OnEnd(Level); LevelManager.UndoLevelPropertyChanges(); CurrentEvent = null; } public static void StartEventClient(SelectableLevel Level, IEvent Event) { if (CurrentEvent != null) { Plugin.Logger.LogError((object)"StartEventClient called twice, this shouldn't happen! (did the server start an event twice?)"); ChatUtils.NotifyError(); } else { Plugin.Logger.LogWarning((object)("Starting event " + Event.Name + "... (client)")); Event.ExecuteClient(Level); CurrentEvent = Event; } } public static void EndEventClient(SelectableLevel Level) { if (CurrentEvent == null) { Plugin.Logger.LogError((object)"EndEventClient called without an active event, please report this!"); ChatUtils.NotifyError(); } else { Plugin.Logger.LogWarning((object)("Ending event " + CurrentEvent.Name + "... (client)")); CurrentEvent.OnEnd(Level); CurrentEvent = null; } } private static IEvent SelectRandomEvent(SelectableLevel Level) { int num = 0; while (true) { int num2 = Random.Range(0, 101); object obj; if (num2 <= PluginConfig.EventSettings.GlobalChance.Value) { obj = (PluginConfig.EventSettings.EqualChance.Value ? EventRegistry.GetRandomEventWithoutRarity() : EventRegistry.GetRandomEvent()); } else { IEvent @event = EventRegistry.GetEvent<NoneEvent>(); obj = @event; } IEvent event2 = (IEvent)obj; if (event2.CanRun(Level)) { return event2; } if (++num > 20) { break; } Plugin.Logger.LogWarning((object)$"Event {event2.Name} cannot be ran, rerolling... (attempt {num} / {20})"); } Plugin.Logger.LogWarning((object)$"Failed to select an event ({num} > {20}), forcing no event..."); return EventRegistry.GetEvent<NoneEvent>(); } private static void NotifyEventStarted(IEvent Event) { string text = Event.Positivity switch { EventPositivity.Positive => "green", EventPositivity.Neutral => "white", EventPositivity.Negative => "red", EventPositivity.Golden => "orange", _ => "white", }; ChatUtils.Send("<color=yellow>EVENT<color=white>:</color></color>\n<color=" + text + ">" + Event.Name + "</color>\n<color=white><size=70%>" + Event.Description + "</size></color>"); } } internal static class LevelManager { private static readonly Dictionary<string, Action> UndoPropertyCallbacks = new Dictionary<string, Action>(); public static List<SpawnableEnemyWithRarity> AllInsideEnemies; public static List<SpawnableEnemyWithRarity> AllOutsideEnemies; public static List<SpawnableEnemyWithRarity> AllDaytimeEnemies; public static IEnumerable<SpawnableEnemyWithRarity> AllEnemies => AllInsideEnemies.Concat(AllOutsideEnemies).Concat(AllDaytimeEnemies); public static bool TryGetEnemy<T>(out EnemyType EnemyType) where T : EnemyAI { EnemyType = AllEnemies.FirstOrDefault((Func<SpawnableEnemyWithRarity, bool>)((SpawnableEnemyWithRarity Enemy) => (Object)(object)Enemy.enemyType.enemyPrefab.GetComponent<T>() != (Object)null))?.enemyType; return (Object)(object)EnemyType != (Object)null; } public static void ModifyLevelProperties(SelectableLevel Level, Action<SelectableLevel> Effect, params string[] Dependencies) { Dictionary<string, object> dictionary = new Dictionary<string, object>(); foreach (string text in Dependencies) { FieldInfo field = ((object)Level).GetType().GetField(text); if (!dictionary.TryAdd(text, field.GetValue(Level))) { throw new Exception("Property '" + text + "' mentioned twice in dependencies array!"); } } Effect(Level); foreach (string text2 in Dependencies) { FieldInfo property = ((object)Level).GetType().GetField(text2); object originalValue = dictionary[text2]; object value = property.GetValue(Level); if (!originalValue.Equals(value) && !UndoPropertyCallbacks.TryAdd(text2, delegate { property.SetValue(Level, originalValue); })) { throw new Exception("Property '" + text2 + "' already contains an undo callback! Did you call ModifyLevelProperties twice on the same property?"); } } } public static void SpawnMapObject(GameObject Prefab, Vector3 Position, Quaternion Rotation) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) Object.Instantiate<GameObject>(Prefab, Position, Rotation, RoundManager.Instance.mapPropsContainer.transform).GetComponent<NetworkObject>().Spawn(true); } public static T SpawnMapObject<T>(GameObject Prefab, Vector3 Position, Quaternion Rotation) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) GameObject val = Object.Instantiate<GameObject>(Prefab, Position, Rotation, RoundManager.Instance.mapPropsContainer.transform); val.GetComponent<NetworkObject>().Spawn(true); return val.GetComponentInChildren<T>(); } internal static void UndoLevelPropertyChanges() { Plugin.Logger.LogDebug((object)"Undoing level property changes... (server)"); foreach (Action value in UndoPropertyCallbacks.Values) { value(); } UndoPropertyCallbacks.Clear(); } internal static void AddAllEnemiesToAllLevels(SelectableLevel[] Levels) { AllInsideEnemies = Levels.SelectMany((SelectableLevel Level) => Level.Enemies).SortEnemies(); AllOutsideEnemies = Levels.SelectMany((SelectableLevel Level) => Level.OutsideEnemies).SortEnemies(); AllDaytimeEnemies = Levels.SelectMany((SelectableLevel Level) => Level.DaytimeEnemies).SortEnemies(); if (!PluginConfig.EnemyAdjustments.SpawnOnAllMoons.Value) { return; } foreach (SelectableLevel level in Levels) { level.Enemies.AddRange(AllInsideEnemies.Where((SpawnableEnemyWithRarity InsideEnemy) => level.Enemies.All((SpawnableEnemyWithRarity Enemy) => Enemy.enemyType.enemyName != InsideEnemy.enemyType.enemyName))); } } internal static void ApplyEnemyRarityValues(SelectableLevel Level) { if (!PluginConfig.EnemyRarityValues.Enabled.Value) { return; } Dictionary<string, int> enemyRarityValues = ConfigUtils.GetEnemyRarityValues(((Object)Level).name); string text = ((Object)Level).name; if (LevelNames.IsCustom(text)) { text = "???_custom_???"; } if (!LevelDefaults.DefaultEnemyRarityValues.TryGetValue(text, out var value)) { Plugin.Logger.LogError((object)("No default rarity values found for level: " + ((Object)Level).name)); return; } foreach (SpawnableEnemyWithRarity enemy in Level.Enemies) { string enemyName = enemy.enemyType.enemyName; if ((!enemyRarityValues.TryGetValue(enemyName, out var value2) || value2 == -1) && !value.TryGetValue(enemyName, out value2)) { Plugin.Logger.LogError((object)("No default rarity value found for enemy: " + enemyName)); } else { enemy.rarity = value2; } } } internal static void ApplyEnemySpawnChances(SelectableLevel Level) { MultiplyCurvePoints(ref Level.enemySpawnChanceThroughoutDay, 3, PositiveOnly: true); MultiplyCurvePoints(ref Level.outsideEnemySpawnChanceThroughDay, 3, PositiveOnly: true); } internal static void ApplyEnemySpawnRates(SelectableLevel Level) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Expected O, but got Unknown SpawnableMapObject[] spawnableMapObjects = Level.spawnableMapObjects; foreach (SpawnableMapObject val in spawnableMapObjects) { if (val.IsObjectTypeOf<Turret>(out var _) && PluginConfig.MapHazards.TurretSpawnRate.GetIfSet<int>(out var Value)) { val.numberToSpawn = new AnimationCurve((Keyframe[])(object)new Keyframe[2] { new Keyframe(0f, 0f), new Keyframe(1f, (float)Value) }); } if (val.IsObjectTypeOf<Landmine>(out var _) && PluginConfig.MapHazards.LandmineSpawnRate.GetIfSet<int>(out Value)) { val.numberToSpawn = new AnimationCurve((Keyframe[])(object)new Keyframe[2] { new Keyframe(0f, 0f), new Keyframe(1f, (float)Value) }); } } } internal static void ApplyLevelProperties(SelectableLevel Level) { var (newValue, newValue2, newValue3, newValue4) = ConfigUtils.GetScrapValues(((Object)Level).name); ApplyIfSet(ref Level.minScrap, newValue); ApplyIfSet(ref Level.maxScrap, newValue2); ApplyIfSet(ref Level.minTotalScrapValue, newValue3); ApplyIfSet(ref Level.maxTotalScrapValue, newValue4); Level.maxEnemyPowerCount += 150; Level.maxOutsideEnemyPowerCount += 10; Level.maxDaytimeEnemyPowerCount += 150; } private static void ApplyIfSet(ref int Value, int NewValue) { if (NewValue != -1) { Value = NewValue; } } private static void MultiplyCurvePoints(ref AnimationCurve Curve, int Multiplier, bool PositiveOnly = false) { Keyframe[] keys = Curve.keys; for (int i = 0; i < keys.Length; i++) { if (!PositiveOnly || !(((Keyframe)(ref keys[i])).value < 0f)) { ref Keyframe reference = ref keys[i]; ((Keyframe)(ref reference)).value = ((Keyframe)(ref reference)).value * (float)Multiplier; } } Curve.keys = keys; } private static List<SpawnableEnemyWithRarity> SortEnemies(this IEnumerable<SpawnableEnemyWithRarity> Enemies) { return (from Enemy in Enemies orderby Enemy.rarity descending group Enemy by Enemy.enemyType.enemyName into Group select Group.First()).ToList(); } } public static class MoonHeatManager { public static readonly IntRange MoonHeatRange = new IntRange(0, 100); private static readonly Dictionary<SelectableLevel, float> LevelHeatValues = new Dictionary<SelectableLevel, float>(); public static void InitializeFor(SelectableLevel Level) { LevelHeatValues.TryAdd(Level, 0f); } public static void ResetHeatValues() { foreach (SelectableLevel item in LevelHeatValues.Keys.ToList()) { LevelHeatValues[item] = 0f; } } public static void AdjustHeatValues(SelectableLevel CurrentLevel) { float heat = IncreaseHeatValueOf(CurrentLevel); foreach (SelectableLevel item in LevelHeatValues.Keys.ToList()) { if (!((Object)(object)CurrentLevel == (Object)(object)item)) { DecreaseHeatValueOf(item); } } NotifyPlayersAndSetWeather(CurrentLevel, heat); } private static float IncreaseHeatValueOf(SelectableLevel Level) { if (!LevelHeatValues.TryGetValue(Level, out var value)) { return 0f; } LevelHeatValues[Level] = Mathf.Clamp(value + PluginConfig.MoonHeat.IncreaseRate.Value, (float)MoonHeatRange.Min, (float)MoonHeatRange.Max); return value; } private static void DecreaseHeatValueOf(SelectableLevel Level) { if (LevelHeatValues.TryGetValue(Level, out var value)) { LevelHeatValues[Level] = Mathf.Clamp(value - PluginConfig.MoonHeat.DecreaseRate.Value, (float)MoonHeatRange.Min, (float)MoonHeatRange.Max); } } private static void NotifyPlayersAndSetWeather(SelectableLevel CurrentLevel, float Heat) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Expected I4, but got Unknown //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Expected I4, but got Unknown ChatUtils.Send("<color=orange>MOON IS AT " + Heat + "% HEAT</color>", Clear: true); foreach (var (num, num2, val) in ConfigUtils.GetMoonHeatCurve()) { if (!(Heat < (float)num) && !(Heat >= (float)num2)) { BCNetworkManager.Instance.SyncWeatherClientRpc(CurrentLevel.levelID, val); NotifyChat((val - 1) switch { 0 => "blue", 2 => "purple", 3 => "yellow", 1 => "orange", 4 => "red", _ => "white", }, (val - 1) switch { 0 => "Heat is rising and caused it to rain...", 2 => "Heat is rising, causing a layer of fog...", 3 => "Moon is getting hot, causing a flood...", 1 => "Extreme heat is causing a dangerous weather...", 4 => "Moon is at max heat, causing hostile creatures to roam it...", _ => "Heat is rising...", }); break; } } } private static void NotifyChat(string Color, string Title) { ChatUtils.Send("<size=11><color=" + Color + ">" + Title + "</color>\n<color=white>Visit other moons to decrease the heat!</color></size>"); } } } namespace BrutalCompanyPlus.Events { [UsedImplicitly] [HarmonyPatch] public class BlobEvolutionEvent : IEvent { private const float NormalSpeed = 3.8f; private const float OpenDoorSpeedMultiplier = 1.5f; public string Name => "They are EVOLVING?!"; public string Description => "Here I was, thinking that Pokémon was the only game with evolutions."; public EventPositivity Positivity => EventPositivity.Negative; public EventRarity DefaultRarity => EventRarity.Uncommon; public void ExecuteServer(SelectableLevel Level) { SetBlobEnemyTag(); EnemySpawnManager.DraftEnemySpawn<BlobAI>(new EnemySpawnManager.SpawnInfo(3)); EnemySpawnManager.DraftEnemySpawn<BlobAI>(new EnemySpawnManager.SpawnInfo(1, Outside: true)); } public void ExecuteClient(SelectableLevel Level) { SetBlobEnemyTag(); } public void OnEnd(SelectableLevel Level) { SetBlobEnemyTag(Unset: true); } private static void SetBlobEnemyTag(bool Unset = false) { if (LevelManager.TryGetEnemy<BlobAI>(out EnemyType EnemyType)) { string tag = (Unset ? "Untagged" : "Enemy"); Transform val = EnemyType.enemyPrefab.transform.Find("Armature"); ((Component)val).gameObject.tag = tag; EnemyAICollisionDetect[] componentsInChildren = ((Component)val).GetComponentsInChildren<EnemyAICollisionDetect>(); foreach (EnemyAICollisionDetect val2 in componentsInChildren) { ((Component)val2).gameObject.tag = tag; } } } [HarmonyPostfix] [HarmonyPatch(typeof(BlobAI), "Update")] private static void EnemyAIPatch(ref BlobAI __instance) { if (((NetworkBehaviour)__instance).IsOwner && EventManager.IsActive<BlobEvolutionEvent>()) { ((EnemyAI)__instance).agent.speed = 3.8f; ((EnemyAI)__instance).openDoorSpeedMultiplier = 1.5f; } } } [UsedImplicitly] public class DeliveryEvent : IEvent { private const int MinItems = 2; private const int MaxItems = 9; public string Name => "ICE SCREAM!!!"; public string Description => "Mommy, the ice cream truck is here!"; public EventPositivity Positivity => EventPositivity.Positive; public EventRarity DefaultRarity => EventRarity.Rare; public void ExecuteServer(SelectableLevel Level) { int num = Singleton.Terminal.buyableItemsList.Length; int num2 = Random.Range(2, 9); for (int i = 0; i < num2; i++) { Singleton.Terminal.orderedItemsFromTerminal.Add(Random.Range(0, num)); } } public void ExecuteClient(SelectableLevel Level) { } } [UsedImplicitly] public class FaceHuggersEvent : IEvent { public string Name => "Bring a shovel!"; public string Description => "They just want a hug..."; public EventPositivity Positivity => EventPositivity.Negative; public EventRarity DefaultRarity => EventRarity.Uncommon; public void ExecuteServer(SelectableLevel Level) { EnemySpawnManager.DraftEnemySpawn<CentipedeAI>(new EnemySpawnManager.SpawnInfo(15, Outside: false, Immediate: false)); } public void ExecuteClient(SelectableLevel Level) { } } [UsedImplicitly] public class GuardsEvent : IEvent { public string Name => "They guard this place!"; public string Description => "Better not get kicked out again..."; public EventPositivity Positivity => EventPositivity.Negative; public EventRarity DefaultRarity => EventRarity.Uncommon; public void ExecuteServer(SelectableLevel Level) { EnemySpawnManager.DraftEnemySpawn<NutcrackerEnemyAI>(new EnemySpawnManager.SpawnInfo(4, Outside: true)); } public void ExecuteClient(SelectableLevel Level) { } } [UsedImplicitly] public class HideAndSeekEvent : IEvent { public string Name => "Hide and Seek"; public string Description => "She's gonna find you..."; public EventPositivity Positivity => EventPositivity.Negative; public EventRarity DefaultRarity => EventRarity.Uncommon; public void ExecuteServer(SelectableLevel Level) { EnemySpawnManager.DraftEnemySpawn<DressGirlAI>(new EnemySpawnManager.SpawnInfo(5)); } public void ExecuteClient(SelectableLevel Level) { } } [UsedImplicitly] public class HoarderTownEvent : IEvent { public string Name => "Hoarder Town"; public string Description => "Come on, those are mine!"; public EventPositivity Positivity => EventPositivity.Negative; public EventRarity DefaultRarity => EventRarity.Rare; public void ExecuteServer(SelectableLevel Level) { EnemySpawnManager.DraftEnemySpawn<HoarderBugAI>(new EnemySpawnManager.SpawnInfo(6)); EnemySpawnManager.DraftEnemySpawn<HoarderBugAI>(new EnemySpawnManager.SpawnInfo(3, Outside: true)); } public void ExecuteClient(SelectableLevel Level) { } } [UsedImplicitly] public class HungerGamesEvent : IEvent { private PlayerControllerB _currentTarget; private bool _playerKilled; public string Name => "The Hunger Games"; public string Description => "May the odds be ever in your favor."; public EventPositivity Positivity => EventPositivity.Negative; public EventRarity DefaultRarity => EventRarity.Rare; public bool CanRun(SelectableLevel Level) { return StartOfRound.Instance.connectedPlayersAmount > 0; } public void ExecuteServer(SelectableLevel Level) { PickNewTarget(); } public void ExecuteClient(SelectableLevel Level) { } public void UpdateServer() { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) if (!_playerKilled && !((Object)(object)_currentTarget == (Object)null)) { if (_currentTarget.isPlayerDead && !StartOfRound.Instance.allPlayersDead) { PickNewTarget(); } if (_currentTarget.isInsideFactory) { _playerKilled = true; _currentTarget.DamagePlayerFromOtherClientServerRpc(_currentTarget.health, default(Vector3), (int)_currentTarget.playerClientId); ChatUtils.Send("<color=purple>" + _currentTarget.playerUsername + "</color> <color=orange>volunteered as Tribute!</color>"); } } } public void OnEnd(SelectableLevel Level) { _currentTarget = null; _playerKilled = false; } private void PickNewTarget() { if (PlayerUtils.AlivePlayers.Random(out _currentTarget)) { this.Log("New target chosen: " + _currentTarget.playerUsername); } } } [UsedImplicitly] [HarmonyPatch] public class InstaJesterEvent : IEvent { private const float MinTimer = 1f; private const float MaxTimer = 5f; public string Name => "Pop goes the.. HOLY FUC-"; public string Description => "Lord have mercy on your soul."; public EventPositivity Positivity => EventPositivity.Negative; public EventRarity DefaultRarity => EventRarity.Rare; public void ExecuteServer(SelectableLevel Level) { EnemySpawnManager.DraftEnemySpawn<JesterAI>(new EnemySpawnManager.SpawnInfo(2)); } public void ExecuteClient(SelectableLevel Level) { } [HarmonyPostfix] [HarmonyPatch(typeof(JesterAI), "SetJesterInitialValues")] private static void EnemyAIPatch(ref JesterAI __instance) { if (EventManager.IsActive<InstaJesterEvent>()) { __instance.popUpTimer = Random.Range(1f, 5f); } } } [UsedImplicitly] public class NoneEvent : IEvent { public string Name => "Nothing happened today!"; public string Description => "Just another Tuesday."; public EventPositivity Positivity => EventPositivity.Positive; public EventRarity DefaultRarity => EventRarity.Uncommon; public void ExecuteServer(SelectableLevel Level) { } public void ExecuteClient(SelectableLevel Level) { } } [UsedImplicitly] [HarmonyPatch] public class OutsideTheBoxEvent : IEvent { public string Name => "Outside the box!"; public string Description => "Creepy..."; public EventPositivity Positivity => EventPositivity.Negative; public EventRarity DefaultRarity => EventRarity.Rare; public void ExecuteServer(SelectableLevel Level) { EnemySpawnManager.DraftEnemySpawn<JesterAI>(new EnemySpawnManager.SpawnInfo(2, Outside: true)); } public void ExecuteClient(SelectableLevel Level) { } private static bool HookResetFlag(PlayerControllerB player, EnemyAI Instance) { if (EventManager.IsActive<OutsideTheBoxEvent>() && Instance.isOutside) { return !player.isInsideFactory; } return player.isInsideFactory; } [HarmonyTranspiler] [HarmonyPatch(typeof(JesterAI), "Update")] private static IEnumerable<CodeInstruction> EnemyAIPatch(IEnumerable<CodeInstruction> instructions) { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Expected O, but got Unknown FieldInfo fieldInfo = AccessTools.Field(typeof(PlayerControllerB), "isInsideFactory"); MethodInfo methodInfo = AccessTools.Method(typeof(OutsideTheBoxEvent), "HookResetFlag", (Type[])null, (Type[])null); bool flag = false; List<CodeInstruction> list = instructions.ToList(); for (int i = 1; i < list.Count; i++) { if (CodeInstructionExtensions.LoadsField(list[i - 1], fieldInfo, false) && !(list[i].opcode != OpCodes.Brfalse)) { list[i - 1] = new CodeInstruction(OpCodes.Ldarg_0, (object)null); list.Insert(i, new CodeInstruction(OpCodes.Call, (object)methodInfo)); flag = true; break; } } if (!flag) { Diagnostics.AddError("Failed to patch JesterAI.Update()! (event: OutsideTheBoxEvent, ver: 4.0.0)"); } return list.AsEnumerable(); } } [UsedImplicitly] public class ResetHeatEvent : IEvent { public string Name => "All moon heat has been reset!"; public string Description => "Seems like Pluto just passed by."; public EventPositivity Positivity => EventPositivity.Positive; public EventRarity DefaultRarity => EventRarity.Uncommon; public void ExecuteServer(SelectableLevel Level) { MoonHeatManager.ResetHeatValues(); } public void ExecuteClient(SelectableLevel Level) { } } [UsedImplicitly] public class ShadowRealmEvent : IEvent { public string Name => "The shadows are roaming"; public string Description => "Did you hear that?"; public EventPositivity Positivity => EventPositivity.Negative; public EventRarity DefaultRarity => EventRarity.Rare; public void ExecuteServer(SelectableLevel Level) { EnemySpawnManager.DraftEnemySpawn<FlowermanAI>(new EnemySpawnManager.SpawnInfo(6, Outside: true)); } public void ExecuteClient(SelectableLevel Level) { } } [UsedImplicitly] public class ShipTurretEvent : IEvent { private static readonly Vector3 TurretPosition = new Vector3(3.87f, 0.84f, -14.23f); private GameObject _prefab; private GameObject _turret; private bool _shouldSpawn; private bool _spawned; public string Name => "When did we get this installed?!"; public string Description => "I'm innocent, I swear!"; public EventPositivity Positivity => EventPositivity.Negative; public EventRarity DefaultRarity => EventRarity.Uncommon; public void ExecuteServer(SelectableLevel Level) { if (_prefab == null) { _prefab = Level.FindObjectPrefab<Turret>(); } _shouldSpawn = true; } public void ExecuteClient(SelectableLevel Level) { } public void UpdateServer() { //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_004b: Unknown result type (might be due to invalid IL or missing references) if (_shouldSpawn) { _shouldSpawn = false; _spawned = true; _turret = Object.Instantiate<GameObject>(_prefab, TurretPosition, Quaternion.identity); _turret.transform.forward = new Vector3(1f, 0f, 0f); _turret.GetComponent<NetworkObject>().Spawn(true); } else if (_spawned && StartOfRound.Instance.shipIsLeaving) { _spawned = false; _turret.GetComponent<NetworkObject>().Despawn(true); ChatUtils.Send("<color=green>Turret removal procedure complete.</color>"); } } public void OnEnd(SelectableLevel Level) { _shouldSpawn = false; _spawned = false; } } [UsedImplicitly] public class SpringbreakEvent : IEvent { public string Name => "Springbreak"; public string Description => "Don't get a concussion!"; public EventPositivity Positivity => EventPositivity.Negative; public EventRarity DefaultRarity => EventRarity.Rare; public void ExecuteServer(SelectableLevel Level) { EnemySpawnManager.DraftEnemySpawn<SpringManAI>(new EnemySpawnManager.SpawnInfo(3, Outside: true)); } public void ExecuteClient(SelectableLevel Level) { } } [UsedImplicitly] public class SurfaceExplosionEvent : IEvent { private static readonly Vector3 MineDistance = new Vector3(9.33f, 5.2f, 1021f); private const int StartSpawnInterval = 10; private const int MinSpawnInterval = 1; private const int MaxSpawnInterval = 4; private GameObject _prefab; private float _spawnTimer; public string Name => "The surface is explosive!"; public string Description => "EXPLOSION!!!"; public EventPositivity Positivity => EventPositivity.Negative; public EventRarity DefaultRarity => EventRarity.Uncommon; public void ExecuteServer(SelectableLevel Level) { _spawnTimer = 10f; if (_prefab == null) { _prefab = Level.FindObjectPrefab<Landmine>(); } } public void ExecuteClient(SelectableLevel Level) { } public void UpdateServer() { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) if (StartOfRound.Instance.allPlayersDead) { return; } if (_spawnTimer >= 0f) { _spawnTimer -= Time.deltaTime; return; } _spawnTimer = Random.Range(1, 4); if (PlayerUtils.OutsidePlayers.Random(out var Value)) { Vector3 position = ((Component)Value).transform.position; if (Vector3.Distance(position, MineDistance) < 1f) { _spawnTimer = -1f; } else { LevelManager.SpawnMapObject<Landmine>(_prefab, position, Quaternion.identity).TriggerMineOnLocalClientByExiting(); } } } } [UsedImplicitly] public class TheBeastsInsideEvent : IEvent { public string Name => "The Beasts Inside"; public string Description => "Ssshhhh..."; public EventPositivity Positivity => EventPositivity.Negative; public EventRarity DefaultRarity => EventRarity.Uncommon; public void ExecuteServer(SelectableLevel Level) { EnemySpawnManager.DraftEnemySpawn<MouthDogAI>(new EnemySpawnManager.SpawnInfo(((Object)Level).name switch { "ExperimentationLevel" => 2, "AssuranceLevel" => 2, "VowLevel" => 2, "OffenseLevel" => 3, "MarchLevel" => 3, "RendLevel" => 4, "DineLevel" => 4, "TitanLevel" => 6, _ => 4, })); } public void ExecuteClient(SelectableLevel Level) { } } [UsedImplicitly] [HarmonyPatch] public class TheRumblingEvent : IEvent { private const float NormalSpeed = 6f; public string Name => "The Rumbling"; public string Description => "Fix the Barricades!"; public EventPositivity Positivity => EventPositivity.Negative; public EventRarity DefaultRarity => EventRarity.Uncommon; public void ExecuteServer(SelectableLevel Level) { EnemySpawnManager.DraftEnemySpawn<ForestGiantAI>(new EnemySpawnManager.SpawnInfo(((Object)Level).name switch { "ExperimentationLevel" => 6, "AssuranceLevel" => 8, "VowLevel" => 8, "OffenseLevel" => 8, "MarchLevel" => 8, "RendLevel" => 10, "DineLevel" => 10, "TitanLevel" => 8, _ => 8, }, Outside: true)); } public void ExecuteClient(SelectableLevel Level) { } [HarmonyPostfix] [HarmonyPatch(typeof(ForestGiantAI), "Update")] private static void EnemyAIPatch(ref ForestGiantAI __instance) { if (((NetworkBehaviour)__instance).IsOwner && EventManager.IsActive<TheRumblingEvent>() && ((EnemyAI)__instance).currentBehaviourStateIndex == 1 && !__instance.inEatingPlayerAnimation) { ((EnemyAI)__instance).agent.speed = 6f; } } } [UsedImplicitly] public class TheyAreShyEvent : IEvent { public string Name => "Don't look... away?"; public string Description => "Instructions unclear."; public EventPositivity Positivity => EventPositivity.Negative; public EventRarity DefaultRarity => EventRarity.Rare; public void ExecuteServer(SelectableLevel Level) { EnemySpawnManager.DraftEnemySpawn<SpringManAI>(new EnemySpawnManager.SpawnInfo(3)); EnemySpawnManager.DraftEnemySpawn<FlowermanAI>(new EnemySpawnManager.SpawnInfo(3)); EnemySpawnManager.DraftEnemySpawn<SpringManAI>(new EnemySpawnManager.SpawnInfo(2, Outside: true)); EnemySpawnManager.DraftEnemySpawn<FlowermanAI>(new EnemySpawnManager.SpawnInfo(3, Outside: true)); } public void ExecuteClient(SelectableLevel Level) { } } [UsedImplicitly] public class UnfairCompanyEvent : IEvent { private const int OutsideEnemyCount = 3; public string Name => "Unfair Company"; public string Description => "Sometimes, life just ain't fair."; public EventPositivity Positivity => EventPositivity.Negative; public EventRarity DefaultRarity => EventRarity.VeryRare; public void ExecuteServer(SelectableLevel Level) { for (int i = 0; i < 3; i++) { if (LevelManager.AllOutsideEnemies.Random(out var Value)) { EnemySpawnManager.DraftEnemySpawn(Value.enemyType, new EnemySpawnManager.SpawnInfo(1, Outside: true)); } } LevelManager.ModifyLevelProperties(Level, delegate(SelectableLevel Level) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Expected O, but got Unknown Level.outsideEnemySpawnChanceThroughDay = new AnimationCurve((Keyframe[])(object)new Keyframe[2] { new Keyframe(0f, 999f), new Keyframe(1f, 999f) }); Level.enemySpawnChanceThroughoutDay = new AnimationCurve((Keyframe[])(object)new Keyframe[2] { new Keyframe(0f, 500f), new Keyframe(1f, 500f) }); }, "outsideEnemySpawnChanceThroughDay", "enemySpawnChanceThroughoutDay"); } public void ExecuteClient(SelectableLevel Level) { } } } namespace BrutalCompanyPlus.Config { [AttributeUsage(AttributeTargets.Class)] public class ConfigCategory : Attribute { public readonly string Name; public ConfigCategory(string Name) { this.Name = Name; } } [AttributeUsage(AttributeTargets.Class)] public class SharedDescription : Attribute { public readonly string Template; public SharedDescription(string Template) { this.Template = Template; } } [AttributeUsage(AttributeTargets.Property)] public class Configuration : Attribute { public readonly object DefaultValue; internal readonly bool ExcludeFromShared; public string Name { get; internal set; } public ConfigDescription Description { get; internal set; } private Configuration(string Name, ConfigDescription Description, object DefaultValue, bool ExcludeFromShared) { this.Name = Name; this.Description = Description; this.DefaultValue = DefaultValue; this.ExcludeFromShared = ExcludeFromShared; } public Configuration(string Description, object DefaultValue, bool ExcludeFromShared = false) : this(null, new ConfigDescription(Description, (AcceptableValueBase)null, Array.Empty<object>()), DefaultValue, ExcludeFromShared) { }//IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown public Configuration(string Description, int DefaultValue, int MinValue, int MaxValue, bool ExcludeFromShared = false) : this(null, new ConfigDescription(Description, (AcceptableValueBase)(object)new AcceptableValueRange<int>(MinValue, MaxValue), Array.Empty<object>()), DefaultValue, ExcludeFromShared) { }//IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown public override string ToString() { return $"(name: {Name}, description: {Description.Description}, default: {DefaultValue})"; } } public static class ConfigLoader { public static void Bind(Plugin Plugin) { //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Expected O, but got Unknown Type[] types = Assembly.GetExecutingAssembly().GetTypes(); foreach (Type type in types) { if (!type.TryGetAttribute<ConfigCategory>(out var Attribute)) { continue; } Plugin.Logger.LogDebug((object)("Binding config for " + type.Name + "...")); PropertyInfo[] properties = type.GetProperties(BindingFlags.Static | BindingFlags.Public); Plugin.Logger.LogDebug((object)$"Found {properties.Length} properties..."); PropertyInfo[] array = properties; foreach (PropertyInfo propertyInfo in array) { if (!propertyInfo.TryGetAttribute<Configuration>(out var Attribute2)) { continue; } Plugin.Logger.LogDebug((object)("Binding config for " + propertyInfo.Name + "...")); if (string.IsNullOrEmpty(Attribute2.Name)) { Attribute2.Name = propertyInfo.Name; } if (!Attribute2.ExcludeFromShared && type.TryGetAttribute<SharedDescription>(out var Attribute3)) { Attribute2.Description = new ConfigDescription(Attribute3.Template.Replace("{}", Attribute2.Description.Description), Attribute2.Description.AcceptableValues, Attribute2.Description.Tags); } if (propertyInfo.TryGetEntryType(out var Type)) { object obj = Convert.ChangeType(Attribute2.DefaultValue, Type); Plugin.Logger.LogDebug((object)$"Binding config for {type.Name}/{propertyInfo.Name}: {Attribute2}"); object value = typeof(ConfigFile).GetMethods(BindingFlags.Instance | BindingFlags.Public).FirstOrDefault((MethodInfo M) => M.Name == "Bind" && M.GetParameters().Length == 4 && M.GetParameters()[3].ParameterType == typeof(ConfigDescription)).MakeGenericMethod(Type) .Invoke(((BaseUnityPlugin)Plugin).Config, new object[4] { Attribute.Name, Attribute2.Name, obj, Attribute2.Description }); propertyInfo.SetValue(null, value); } } } } private static bool TryGetAttribute<T>(this MemberInfo Member, out T Attribute) where T : Attribute { object[] customAttributes = Member.GetCustomAttributes(typeof(T), inherit: false); if (customAttributes.IsEmpty()) { Attribute = null; return false; } Attribute = (T)customAttributes[0]; return true; } private static bool TryGetEntryType(this PropertyInfo Info, out Type Type) { if (!Info.PropertyType.IsGenericType || Info.PropertyType.GetGenericTypeDefinition() != typeof(ConfigEntry<>)) { Type = null; return false; } Type[] genericArguments = Info.PropertyType.GetGenericArguments(); if (genericArguments.Length != 1) { Type = null; return false; } Type = genericArguments[0]; return true; } } internal static class EventConfig { private const string Category = "Event Rarities"; internal static void RegisterWith(BaseUnityPlugin FromPlugin, ref List<IEvent> Events) { foreach (IEvent Event in Events) { try { string text = Event.Name.Replace("'", ""); EventRegistry.EventRarityValues[Event] = FromPlugin.Config.Bind<EventRarity>("Event Rarities", text, Event.DefaultRarity, Event.Description).Value; } catch (Exception ex) { Plugin.Logger.LogError((object)ex.ToString()); string text2 = ((FromPlugin.Info.Metadata.GUID != "BrutalCompanyPlus") ? (" from " + FromPlugin.Info.Metadata.Name) : ""); Diagnostics.AddError("Failed to register event \"" + Event.Name + "\"" + text2 + "! See console for details."); EventRegistry.EventRarityValues[Event] = Event.DefaultRarity; } } } } internal static class PluginConfig { [ConfigCategory("Custom Scrap Values")] [SharedDescription("Define min/max scrap pieces and min/max total scrap value for {} (for vanilla, use: -1,-1,-1,-1)")] public static class ScrapValues { public const string DefaultValues = "-1,-1,-1,-1"; [Configuration("Experimentation", "6,25,400,1500", false)] public static ConfigEntry<string> ExperimentationLevel { get; set; } [Configuration("Assurance", "10,25,600,2500", false)] public static ConfigEntry<string> AssuranceLevel { get; set; } [Configuration("Vow", "12,35,600,2500", false)] public static ConfigEntry<string> VowLevel { get; set; } [Configuration("Offense", "15,35,800,3500", false)] public static ConfigEntry<string> OffenseLevel { get; set; } [Configuration("March", "15,35,800,3500", false)] public static ConfigEntry<string> MarchLevel { get; set; } [Configuration("Rend", "20,60,1500,5000", false)] public static ConfigEntry<string> RendLevel { get; set; } [Configuration("Dine", "20,60,1500,5000", false)] public static ConfigEntry<string> DineLevel { get; set; } [Configuration("Titan", "20,60,2000,6000", false)] public static ConfigEntry<string> TitanLevel { get; set; } [Configuration("any custom levels", "20,60,2000,6000", false)] public static ConfigEntry<string> CustomLevel { get; set; } } [ConfigCategory("Moon Heat")] public static class MoonHeat { [Configuration("Rate at which the moon heat increases by when landing back on the same planet", 20f, false)] public static ConfigEntry<float> IncreaseRate { get; set; } [Configuration("Rate at which the moon heat decreases by when not visiting the planet", 10f, false)] public static ConfigEntry<float> DecreaseRate { get; set; } [Configuration("Defines how moon heat affects the weather (format: `start:end:type`, start is inclusive and end is exclusive)", "20:40:Rainy,40:60:Foggy,60:80:Flooded,80:100:Stormy,100:101:Eclipsed", false)] public static ConfigEntry<string> HeatCurve { get; set; } } [ConfigCategory("Map Hazard Adjustments")] public static class MapHazards { [Configuration("Amount of turrets that should be spawned (for vanilla, use: -1)", 8, false)] public static ConfigEntry<int> TurretSpawnRate { get; set; } [Configuration("Amount of landmines that should be spawned (for vanilla, use: -1)", 30, false)] public static ConfigEntry<int> LandmineSpawnRate { get; set; } } [ConfigCategory("Enemy Rarity Values")] [SharedDescription("Define custom enemy rarity values for {} (no spawn: 0, max chance: 100, BCP default: -1)")] public static class EnemyRarityValues { private const string DefaultRarity = "Centipede:-1,Bunker Spider:-1,Hoarding bug:-1,Flowerman:-1,Crawler:-1,Blob:-1,Girl:-1,Puffer:-1,Nutcracker:-1,Spring:-1,Jester:-1,Masked:-1,Lasso:-1"; [Configuration("Set this to `false` if you want vanilla spawning behavior.", true, true)] public static ConfigEntry<bool> Enabled { get; set; } [Configuration("Experimentation", "Centipede:-1,Bunker Spider:-1,Hoarding bug:-1,Flowerman:-1,Crawler:-1,Blob:-1,Girl:-1,Puffer:-1,Nutcracker:-1,Spring:-1,Jester:-1,Masked:-1,Lasso:-1", false)] public static ConfigEntry<string> ExperimentationLevel { get; set; } [Configuration("Assurance", "Centipede:-1,Bunker Spider:-1,Hoarding bug:-1,Flowerman:-1,Crawler:-1,Blob:-1,Girl:-1,Puffer:-1,Nutcracker:-1,Spring:-1,Jester:-1,Masked:-1,Lasso:-1", false)] public static ConfigEntry<string> AssuranceLevel { get; set; } [Configuration("Vow", "Centipede:-1,Bunker Spider:-1,Hoarding bug:-1,Flowerman:-1,Crawler:-1,Blob:-1,Girl:-1,Puffer:-1,Nutcracker:-1,Spring:-1,Jester:-1,Masked:-1,Lasso:-1", false)] public static ConfigEntry<string> VowLevel { get; set; } [Configuration("Offense", "Centipede:-1,Bunker Spider:-1,Hoarding bug:-1,Flowerman:-1,Crawler:-1,Blob:-1,Girl:-1,Puffer:-1,Nutcracker:-1,Spring:-1,Jester:-1,Masked:-1,Lasso:-1", false)] public static ConfigEntry<string> OffenseLevel { get; set; } [Configuration("March", "Centipede:-1,Bunker Spider:-1,Hoarding bug:-1,Flowerman:-1,Crawler:-1,Blob:-1,Girl:-1,Puffer:-1,Nutcracker:-1,Spring:-1,Jester:-1,Masked:-1,Lasso:-1", false)] public static ConfigEntry<string> MarchLevel { get; set; } [Configuration("Rend", "Centipede:-1,Bunker Spider:-1,Hoarding bug:-1,Flowerman:-1,Crawler:-1,Blob:-1,Girl:-1,Puffer:-1,Nutcracker:-1,Spring:-1,Jester:-1,Masked:-1,Lasso:-1", false)] public static ConfigEntry<string> RendLevel { get; set; } [Configuration("Dine", "Centipede:-1,Bunker Spider:-1,Hoarding bug:-1,Flowerman:-1,Crawler:-1,Blob:-1,Girl:-1,Puffer:-1,Nutcracker:-1,Spring:-1,Jester:-1,Masked:-1,Lasso:-1", false)] public static ConfigEntry<string> DineLevel { get; set; } [Configuration("Titan", "Centipede:-1,Bunker Spider:-1,Hoarding bug:-1,Flowerman:-1,Crawler:-1,Blob:-1,Girl:-1,Puffer:-1,Nutcracker:-1,Spring:-1,Jester:-1,Masked:-1,Lasso:-1", false)] public static ConfigEntry<string> TitanLevel { get; set; } [Configuration("any custom levels", "Centipede:-1,Bunker Spider:-1,Hoarding bug:-1,Flowerman:-1,Crawler:-1,Blob:-1,Girl:-1,Puffer:-1,Nutcracker:-1,Spring:-1,Jester:-1,Masked:-1,Lasso:-1", false)] public static ConfigEntry<string> CustomLevel { get; set; } } [ConfigCategory("Credits-related Adjustments")] public static class CreditsAdjustments { [Configuration("Amount of money to give when a player leaves a moon alive (to disable, use: -1)", 150, false)] public static ConfigEntry<int> FreeMoneyAmount { get; set; } } [ConfigCategory("Enemy-related Adjustments")] public static class EnemyAdjustments { [Configuration("Whether all enemies should be nominated for spawning on all moons (vanilla: false)", true, false)] public static ConfigEntry<bool> SpawnOnAllMoons { get; set; } } [ConfigCategory("Quota-related Adjustments")] public static class QuotaAdjustments { [Configuration("Days available before deadline (for vanilla, use: -1)", 4, false)] public static ConfigEntry<int> DeadlineDays { get; set; } [Configuration("Amount of credits everyone gets at the start of a new session (for vanilla, use: -1)", 200, false)] public static ConfigEntry<int> StartingCredits { get; set; } [Configuration("Quota you begin with at the start of a new session (for vanilla, use: -1)", 400, false)] public static ConfigEntry<int> StartingQuota { get; set; } [Configuration("Rate at which the quota increases by when it's met (for vanilla, use: -1)", 275, false)] public static ConfigEntry<int> BaseIncrease { get; set; } } [ConfigCategory("Event Settings")] public static class EventSettings { [Configuration("Chance between 0 and 100 for an event to occur (this is separate from event rarity and no events may still occur even if the chance is met!)", 100, 0, 100, false)] public static ConfigEntry<int> GlobalChance { get; set; } [Configuration("Whether all events have equal chance to happen (disables event rarity altogether!)", false, false)] public static ConfigEntry<bool> EqualChance { get; set; } } internal static void Bind(Plugin Plugin) { ConfigLoader.Bind(Plugin); Validate(); } private static void Validate() { LevelNames.AllCustom.ForEach(ConfigUtils.GetEnemyRarityValues); LevelNames.AllCustom.ForEach(ConfigUtils.GetScrapValues); ConfigUtils.GetMoonHeatCurve(); } } } namespace BrutalCompanyPlus.Api { public static class EventRegistry { private static readonly List<IEvent> RegisteredEvents = new List<IEvent>(); internal static readonly Dictionary<IEvent, EventRarity> EventRarityValues = new Dictionary<IEvent, EventRarity>(); [UsedImplicitly] public static void RegisterEvents(BaseUnityPlugin FromPlugin, List<IEvent> Events) { EventConfig.RegisterWith(FromPlugin, ref Events); RegisteredEvents.AddRange(Events); Plugin.Logger.LogWarning((object)$"Registered {Events.Count} events from {FromPlugin.Info.Metadata.Name}:"); foreach (IEvent Event in Events) { Plugin.Logger.LogWarning((object)$"Registered event: {Event.Name} (rarity: {Event.GetRarity()}, description: {Event.Description})"); } } [MethodImpl(MethodImplOptions.NoInlining)] public static void AutoRegister(BaseUnityPlugin FromPlugin) { IEnumerable<IEvent> source = from type in Assembly.GetCallingAssembly().GetTypes() where type.IsClass && typeof(IEvent).IsAssignableFrom(type) select (IEvent)Activator.CreateInstance(type); RegisterEvents(FromPlugin, source.ToList()); } public static T GetEvent<T>() where T : IEvent { return (T)(RegisteredEvents.FirstOrDefault((IEvent Event) => Event is T) ?? ((object)default(T))); } public static IEvent GetEvent(int EventId) { return RegisteredEvents.ElementAtOrDefault(EventId); } private static EventRarity GetRarity(this IEvent Event) { return EventRarityValues[Event]; } public static int GetId(this IEvent Event) { return RegisteredEvents.IndexOf(Event); } public static bool IsActive(this IEvent Event) { return EventManager.CurrentEvent == Event; } internal static IEvent GetRandomEvent() { int num = RegisteredEvents.Sum((IEvent Event) => (int)Event.GetRarity()); int num2 = Random.Range(0, num); foreach (IEvent registeredEvent in RegisteredEvents) { num2 = (int)(num2 - registeredEvent.GetRarity()); if (num2 <= 0) { return registeredEvent; } } Plugin.Logger.LogFatal((object)$"Failed to get random event! (totalRarity: {num}, random: {num2})"); return GetEvent<NoneEvent>(); } internal static IEvent GetRandomEventWithoutRarity() { if (RegisteredEvents.Where((IEvent Event) => Event.GetRarity() != EventRarity.Disabled).Random(out var Value)) { return Value; } Plugin.Logger.LogFatal((object)"Failed to get random event! (without rarity)"); return GetEvent<NoneEvent>(); } } public interface IEvent { string Name { get; } string Description { get; } EventPositivity Positivity { get; } EventRarity DefaultRarity { get; } bool CanRun([UsedImplicitly] SelectableLevel Level) { return true; } void ExecuteServer([UsedImplicitly] SelectableLevel Level); void ExecuteClient([UsedImplicitly] SelectableLevel Level); void UpdateServer() { } void OnEnd([UsedImplicitly] SelectableLevel Level) { } } public enum EventPositivity { Positive, Neutral, Negative, Golden } public enum EventRarity { [Obsolete("For configuration purposes only. Do not use.")] Disabled = 0, Common = 100, Uncommon = 85, Rare = 60, VeryRare = 40, UltraRare = 20 } public static class EventExtensions { public static void Log(this IEvent Event, string Message) { Plugin.Logger.LogInfo((object)("[Event (" + Event.Name + ")] " + Message)); } } }