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 Natural Selection v0.3.0
DLLs/fandovec03.NaturalSelection.dll
Decompiled a year ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.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.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using CleaningCompany; using EnhancedMonsters; using EnhancedMonsters.Patches; using GameNetcodeStuff; using HarmonyLib; using LethalNetworkAPI; using Microsoft.CodeAnalysis; using NaturalSelection.EnemyPatches; using NaturalSelection.Generics; using NaturalSelectionLib; using Unity.Netcode; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("ReXuvination")] [assembly: IgnoresAccessChecksTo("SellBodies")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("fandovec03.NaturalSelection")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.3.0.0")] [assembly: AssemblyInformationalVersion("0.3.0+a0e438f818ef0d7d93b96638f3017e5aa6fb3ac1")] [assembly: AssemblyProduct("NaturalSelection")] [assembly: AssemblyTitle("fandovec03.NaturalSelection")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.3.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.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.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = 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 NaturalSelection { [BepInPlugin("fandovec03.NaturalSelection", "NaturalSelection", "0.3.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Script : BaseUnityPlugin { internal static ManualLogSource Logger = null; internal static bool stableToggle; private static bool isExperimental = false; private static bool isPrerelease = false; private static bool debugBool = false; private static bool spammyLogs = false; private static bool debugNetworking = false; private static bool debugLibrary = false; private static bool debugTriggerFlags = false; private static bool debugGiants = false; private static bool debugHygrodere = false; private static bool debugNutcrackers = false; private static bool debugRedBees = false; private static bool debugSandworms = false; private static bool debugSpiders = false; private static bool debugSpiderWebs = false; private static bool debugUnspecified = false; internal static bool enhancedMonstersPresent = false; internal static bool sellBodiesPresent = false; internal static bool rexuvinationPresent = false; internal static Dictionary<string, bool> Bools = new Dictionary<string, bool>(); public static Action<string, bool>? OnConfigSettingChanged; public static Script Instance { get; private set; } = null; internal static Harmony? Harmony { get; set; } internal static MyModConfig BoundingConfig { get; set; } = null; private static void SubscribeDebugConfigBools(ConfigEntry<bool> entryKey, bool boolParam, string entry) { ConfigEntry<bool> entryKey2 = entryKey; string entry2 = entry; entryKey2.SettingChanged += delegate { boolParam = entryKey2.Value; Logger.LogMessage((object)$"Updating with entry.Value {entryKey2.Value}. Result: {boolParam}"); OnConfigSettingChanged?.Invoke(entry2, entryKey2.Value); }; } private void Awake() { Logger = ((BaseUnityPlugin)this).Logger; Instance = this; BoundingConfig = new MyModConfig(((BaseUnityPlugin)this).Config); stableToggle = BoundingConfig.stableMode.Value; Bools.Add("debugBool", debugBool); Bools.Add("spammyLogs", spammyLogs); Bools.Add("debugNetworking", debugNetworking); Bools.Add("debugLibrary", debugLibrary); Bools.Add("debugTriggerFlags", debugTriggerFlags); Bools.Add("debugGiants", debugGiants); Bools.Add("debugHygrodere", debugHygrodere); Bools.Add("debugNutcrackers", debugNutcrackers); Bools.Add("debugRedBees", debugRedBees); Bools.Add("debugSandworms", debugSandworms); Bools.Add("debugSpiders", debugSpiders); Bools.Add("debugSpiderWebs", debugSpiderWebs); Bools.Add("debugUnspecified", debugUnspecified); foreach (KeyValuePair<string, ConfigEntry<bool>> debugEntry in BoundingConfig.debugEntries) { if (Bools.ContainsKey(debugEntry.Key)) { Bools[debugEntry.Key] = debugEntry.Value.Value; SubscribeDebugConfigBools(debugEntry.Value, Bools[debugEntry.Key], debugEntry.Key); } else { Logger.LogError((object)("Failed to find bool for config entry " + debugEntry.Key)); } } char[] array = "0.3.0".ToCharArray(); if ((array[0] == '9' && array[1] == '9') || (array[0] == '8' && array[1] == '8')) { if (array[0] == '9' && array[1] == '9') { isExperimental = true; } if (array[0] == '8' && array[1] == '8') { isPrerelease = true; } array[0] = '0'; array[1] = '0'; } Patch(); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(array); Logger.LogInfo((object)string.Format("{0} v{1} has loaded!", "fandovec03.NaturalSelection", stringBuilder)); } internal static void Patch() { //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) //IL_0017: Expected O, but got Unknown if (Harmony == null) { Harmony = new Harmony("fandovec03.NaturalSelection"); } Logger.LogInfo((object)"Patching NaturalSelection..."); if (Chainloader.PluginInfos.ContainsKey("com.velddev.enhancedmonsters") || BoundingConfig.enhancedMonstersCompToggle.Value) { enhancedMonstersPresent = true; Logger.LogDebug((object)"Enhanced Monsters is present"); } if (Chainloader.PluginInfos.ContainsKey("Entity378.sellbodies") || BoundingConfig.sellBodiesFixedCompToggle.Value) { sellBodiesPresent = true; Logger.LogDebug((object)"SellbodiesFixed is present"); } if (Chainloader.PluginInfos.ContainsKey("XuuXiaolan.ReXuvination") || BoundingConfig.ReXuvinationCompToggle.Value) { rexuvinationPresent = true; Logger.LogDebug((object)"ReXuvination is present"); } if (isExperimental) { Logger.LogFatal((object)("LOADING EXPERIMENTAL BUILD OF " + "NaturalSelection".ToUpper() + ", DOWNLOAD NATURAL SELECTION INSTEAD FOR MORE STABLE EXPERIENCE!")); } if (isPrerelease) { Logger.LogWarning((object)("LOADING PRERELASE BUILD OF " + "NaturalSelection".ToUpper() + ", DOWNLOAD NATURAL SELECTION INSTEAD FOR MORE STABLE EXPERIENCE!")); } Harmony.PatchAll(typeof(AICollisionDetectPatch)); Harmony.PatchAll(typeof(EnemyAIPatch)); Harmony.PatchAll(typeof(Networking)); Harmony.PatchAll(typeof(NetworkingMethods)); Harmony.PatchAll(typeof(InitializeGamePatch)); try { NaturalSelectionLib.LibrarySetup(Logger, spammyLogs, debugLibrary); Logger.LogMessage((object)("Library successfully setup! Version " + NaturalSelectionLib.ReturnVersion())); } catch { Logger.LogError((object)"Failed to setup library!"); } Harmony.PatchAll(typeof(RoundManagerPatch)); if (BoundingConfig.enableLeviathan.Value) { Harmony.PatchAll(typeof(SandWormAIPatch)); } if (BoundingConfig.enableSlime.Value) { Harmony.PatchAll(typeof(BlobAIPatch)); } if (BoundingConfig.enableHoardingBug.Value) { Harmony.PatchAll(typeof(HoarderBugPatch)); } if (BoundingConfig.enableRedBees.Value) { Harmony.PatchAll(typeof(BeeAIPatch)); } if (BoundingConfig.enableGiant.Value) { Harmony.PatchAll(typeof(ForestGiantPatch)); } if (BoundingConfig.enableSpiderWebs.Value) { Harmony.PatchAll(typeof(SandSpiderWebTrapPatch)); } if (!stableToggle) { if (BoundingConfig.enableNutcracker.Value) { Harmony.PatchAll(typeof(NutcrackerAIPatch)); } if (BoundingConfig.enableSporeLizard.Value) { Harmony.PatchAll(typeof(PufferAIPatch)); } if (BoundingConfig.enableSpider.Value) { Harmony.PatchAll(typeof(SandSpiderAIPatch)); } Logger.LogInfo((object)"Stable mode off. Loaded all patches."); } else { Logger.LogInfo((object)"Stable mode on. Excluded unstable and WIP patches from loading."); } Logger.LogInfo((object)"Finished patching NaturalSelection !"); } internal static void Unpatch() { Logger.LogDebug((object)"Unpatching..."); Harmony? harmony = Harmony; if (harmony != null) { harmony.UnpatchSelf(); } Logger.LogDebug((object)"Finished unpatching!"); } } public static class MyPluginInfo { public const string PLUGIN_GUID = "fandovec03.NaturalSelection"; public const string PLUGIN_NAME = "NaturalSelection"; public const string PLUGIN_VERSION = "0.3.0"; } } namespace NaturalSelection.Generics { internal class InitializeGamePatch { private static bool finishedLoading = false; private static List<EnemyAI> loadedEnemyList = Resources.FindObjectsOfTypeAll<EnemyAI>().ToList(); private static List<string> loadedEnemyNamesFromConfig = new List<string>(); private static List<string> beeBlacklistList = Script.BoundingConfig.beeBlacklist.Value.Split(',', StringSplitOptions.RemoveEmptyEntries).ToList(); private static List<string> blobBlacklistList = Script.BoundingConfig.blobBlacklist.Value.Split(',', StringSplitOptions.RemoveEmptyEntries).ToList(); private static List<string> sandwormBlacklistList = Script.BoundingConfig.sandwormBlacklist.Value.Split(',', StringSplitOptions.RemoveEmptyEntries).ToList(); private static List<string> spiderWebBlacklistList = Script.BoundingConfig.spiderWebBlacklist.Value.Split(',', StringSplitOptions.RemoveEmptyEntries).ToList(); private static List<string> speedModifierList = Script.BoundingConfig.speedModifierList.Value.Split(',', StringSplitOptions.RemoveEmptyEntries).ToList(); private static List<string> spiderBlacklistList = Script.BoundingConfig.spiderBlacklist.Value.Split(',', StringSplitOptions.RemoveEmptyEntries).ToList(); private static Dictionary<string, bool> beeBlacklistrDictionay = new Dictionary<string, bool>(); private static Dictionary<string, bool> blobBlacklistDictionay = new Dictionary<string, bool>(); private static Dictionary<string, bool> sandwormBlacklistDictionay = new Dictionary<string, bool>(); private static Dictionary<string, bool> spiderWebBlacklistDictionay = new Dictionary<string, bool>(); public static Dictionary<string, float> speedModifierDictionay = new Dictionary<string, float>(); private static Dictionary<string, bool> spiderBlacklistDictionay = new Dictionary<string, bool>(); public static List<string> beeBlacklistFinal = new List<string>(); public static List<string> blobBlacklistFinal = new List<string>(); public static List<string> sandwormBlacklistFinal = new List<string>(); public static List<string> spiderWebBlacklistFinal = new List<string>(); public static List<string> spiderBlacklistFinal = new List<string>(); public static List<EnemyAI> tryFindLater = new List<EnemyAI>(); [HarmonyPatch(typeof(InitializeGame), "Start")] [HarmonyPostfix] public static void InitializeGameStartPatch() { if (!finishedLoading) { Script.Logger.LogMessage((object)"Reading/Checking/Writing entries for enemies."); ReadConfigLists(); CheckConfigLists(loadedEnemyList); WriteToConfigLists(); } LibraryCalls.SubscribeToConfigChanges(); Networking.SubscribeToConfigChanges(); finishedLoading = true; } [HarmonyPatch(typeof(StartOfRound), "Awake")] [HarmonyPostfix] public static void StartOfRoundPatch() { if (tryFindLater.Count > 0) { Script.Logger.LogMessage((object)"Secondary list is not empty. Checking/Writing entries for skipped enemies"); try { CheckConfigLists(tryFindLater); WriteToConfigLists(); tryFindLater.Clear(); } catch { Script.Logger.LogError((object)"An error has occured while working with the list."); tryFindLater.Clear(); } } } public static void ReadConfigLists() { foreach (string speedModifier in speedModifierList) { try { string text = speedModifier.Split(":")[0]; float num = float.Parse(speedModifier.Split(":")[1].Replace(".", ",")); speedModifierDictionay.Add(text, num); Script.Logger.LogDebug((object)$"Found {text}, {num}"); } catch (Exception ex) { Script.Logger.LogError((object)"Failed to add enemy into speedModifierDictionary"); Script.Logger.LogError((object)speedModifier); Script.Logger.LogError((object)speedModifier.Split(":")[0]); Script.Logger.LogError((object)speedModifier.Split(":")[1]); Script.Logger.LogError((object)ex); } } foreach (string beeBlacklist in beeBlacklistList) { try { string text2 = beeBlacklist.Split(":")[0]; bool flag = bool.Parse(beeBlacklist.Split(":")[1]); if (flag) { beeBlacklistFinal.Add(text2); } beeBlacklistrDictionay.Add(text2, flag); Script.Logger.LogDebug((object)$"Found {text2}, {flag}"); } catch (Exception ex2) { Script.Logger.LogError((object)"Failed to add enemy into beeBlacklistrDictionay"); Script.Logger.LogError((object)beeBlacklist); Script.Logger.LogError((object)beeBlacklist.Split(":")[0]); Script.Logger.LogError((object)beeBlacklist.Split(":")[1]); Script.Logger.LogError((object)ex2); } } foreach (string blobBlacklist in blobBlacklistList) { try { string text3 = blobBlacklist.Split(":")[0]; bool flag2 = bool.Parse(blobBlacklist.Split(":")[1]); if (flag2) { blobBlacklistFinal.Add(text3); } blobBlacklistDictionay.Add(text3, flag2); Script.Logger.LogDebug((object)$"Found {text3}, {flag2}"); } catch (Exception ex3) { Script.Logger.LogError((object)"Failed to add enemy into blobBlacklistDictionay"); Script.Logger.LogError((object)blobBlacklist); Script.Logger.LogError((object)blobBlacklist.Split(":")[0]); Script.Logger.LogError((object)blobBlacklist.Split(":")[1]); Script.Logger.LogError((object)ex3); } } foreach (string sandwormBlacklist in sandwormBlacklistList) { try { string text4 = sandwormBlacklist.Split(":")[0]; bool flag3 = bool.Parse(sandwormBlacklist.Split(":")[1]); if (flag3) { sandwormBlacklistFinal.Add(text4); } sandwormBlacklistDictionay.Add(text4, flag3); Script.Logger.LogDebug((object)$"Found {text4}, {flag3}"); } catch (Exception ex4) { Script.Logger.LogError((object)"Failed to add enemy into sandwormBlacklistDictionay"); Script.Logger.LogError((object)sandwormBlacklist); Script.Logger.LogError((object)sandwormBlacklist.Split(":")[0]); Script.Logger.LogError((object)sandwormBlacklist.Split(":")[1]); Script.Logger.LogError((object)ex4); } } foreach (string spiderWebBlacklist in spiderWebBlacklistList) { try { string text5 = spiderWebBlacklist.Split(":")[0]; bool flag4 = bool.Parse(spiderWebBlacklist.Split(":")[1]); if (flag4) { spiderWebBlacklistFinal.Add(text5); } spiderWebBlacklistDictionay.Add(text5, flag4); Script.Logger.LogDebug((object)$"Found {text5}, {flag4}"); } catch (Exception ex5) { Script.Logger.LogError((object)"Failed to add enemy into spiderWebBlacklistDictionay"); Script.Logger.LogError((object)spiderWebBlacklist); Script.Logger.LogError((object)spiderWebBlacklist.Split(":")[0]); Script.Logger.LogError((object)spiderWebBlacklist.Split(":")[1]); Script.Logger.LogError((object)ex5); } } foreach (string spiderBlacklist in spiderBlacklistList) { try { string text6 = spiderBlacklist.Split(":")[0]; bool flag5 = bool.Parse(spiderBlacklist.Split(":")[1]); if (flag5) { spiderBlacklistFinal.Add(text6); } spiderBlacklistDictionay.Add(text6, flag5); Script.Logger.LogDebug((object)$"Found {text6}, {flag5}"); } catch (Exception ex6) { Script.Logger.LogError((object)"Failed to add enemy into spiderBlacklistDictionay"); Script.Logger.LogError((object)spiderBlacklist); Script.Logger.LogError((object)spiderBlacklist.Split(":")[0]); Script.Logger.LogError((object)spiderBlacklist.Split(":")[1]); Script.Logger.LogError((object)ex6); } } } public static void CheckConfigLists(List<EnemyAI> listOfEnemies) { foreach (EnemyAI listOfEnemy in listOfEnemies) { string enemyName; try { enemyName = listOfEnemy.enemyType.enemyName; } catch { Script.Logger.LogWarning((object)("Failed to get enemy name from " + ((Object)listOfEnemy).name + ". Adding to list for 2nd attempt.")); tryFindLater.Add(listOfEnemy); continue; } if (!loadedEnemyNamesFromConfig.Contains(enemyName)) { loadedEnemyNamesFromConfig.Add(enemyName); } } foreach (string item in loadedEnemyNamesFromConfig) { Script.Logger.LogInfo((object)("Checking config entries for enemy: " + item)); if (!speedModifierDictionay.Keys.Contains(item)) { Script.Logger.LogDebug((object)("Generating new web speed modifier entry for " + item)); speedModifierDictionay.Add(item, 1f); } if (!beeBlacklistrDictionay.Keys.Contains(item)) { Script.Logger.LogDebug((object)("Generating new bee blacklist entry for " + item)); beeBlacklistrDictionay.Add(item, value: false); } if (!blobBlacklistDictionay.Keys.Contains(item)) { Script.Logger.LogDebug((object)("Generating new blob blacklist entry for " + item)); blobBlacklistDictionay.Add(item, value: false); } if (!sandwormBlacklistDictionay.Keys.Contains(item)) { Script.Logger.LogDebug((object)("Generating new Sandworm blacklist entry for " + item)); sandwormBlacklistDictionay.Add(item, value: false); } if (!spiderWebBlacklistDictionay.Keys.Contains(item)) { Script.Logger.LogDebug((object)("Generating new spider web blacklist entry for " + item)); spiderWebBlacklistDictionay.Add(item, value: false); } if (!spiderBlacklistDictionay.Keys.Contains(item)) { Script.Logger.LogDebug((object)("Generating new spider blacklist entry for " + item)); spiderBlacklistDictionay.Add(item, value: false); } } if (!Script.BoundingConfig.debugBool.Value) { return; } foreach (string item2 in beeBlacklistFinal) { Script.Logger.LogDebug((object)("checking final blacklist beeBlacklistFinal -> " + item2)); } foreach (string item3 in sandwormBlacklistFinal) { Script.Logger.LogDebug((object)("checking final blacklist sandwormBlacklistFinal -> " + item3)); } foreach (string item4 in spiderWebBlacklistFinal) { Script.Logger.LogDebug((object)("checking final blacklist spiderWebBlacklistFinal -> " + item4)); } foreach (string item5 in spiderBlacklistFinal) { Script.Logger.LogDebug((object)("checking final blacklist spiderBlacklistFinal -> " + item5)); } foreach (KeyValuePair<string, float> item6 in speedModifierDictionay) { Script.Logger.LogDebug((object)string.Format("checking final speed modifier list {0} -> {1}, {2}", "speedModifierDictionay", item6.Key, item6.Value)); } } public static void WriteToConfigLists() { string text = ""; string text2 = ""; string text3 = ""; string text4 = ""; string text5 = ""; string text6 = ""; try { foreach (KeyValuePair<string, float> item in speedModifierDictionay) { text = $"{text}{item.Key}:{item.Value},"; } Script.BoundingConfig.speedModifierList.Value = text; foreach (KeyValuePair<string, bool> item2 in beeBlacklistrDictionay) { text2 = $"{text2}{item2.Key}:{item2.Value},"; } Script.BoundingConfig.beeBlacklist.Value = text2; foreach (KeyValuePair<string, bool> item3 in blobBlacklistDictionay) { text3 = $"{text3}{item3.Key}:{item3.Value},"; } Script.BoundingConfig.blobBlacklist.Value = text3; foreach (KeyValuePair<string, bool> item4 in sandwormBlacklistDictionay) { text4 = $"{text4}{item4.Key}:{item4.Value},"; } Script.BoundingConfig.sandwormBlacklist.Value = text4; foreach (KeyValuePair<string, bool> item5 in spiderWebBlacklistDictionay) { text5 = $"{text5}{item5.Key}:{item5.Value},"; } Script.BoundingConfig.spiderWebBlacklist.Value = text5; foreach (KeyValuePair<string, bool> item6 in spiderBlacklistDictionay) { text6 = $"{text6}{item6.Key}:{item6.Value},"; } Script.BoundingConfig.spiderBlacklist.Value = text6; Script.Logger.LogInfo((object)"Finished generating configucations."); } catch (Exception ex) { Script.Logger.LogError((object)"Failed to generate configucations."); Script.Logger.LogError((object)ex); } } } public class LibraryCalls { private static bool debugSpam = Script.Bools["spammyLogs"]; private static bool debugTriggerFlag = Script.Bools["debugTriggerFlags"]; private static void Event_OnConfigSettingChanged(string entryKey, bool value) { if (entryKey == "debugTriggerFlags") { debugTriggerFlag = value; } if (entryKey == "spammyLogs") { debugSpam = value; } } public static void SubscribeToConfigChanges() { Script.OnConfigSettingChanged = (Action<string, bool>)Delegate.Combine(Script.OnConfigSettingChanged, new Action<string, bool>(Event_OnConfigSettingChanged)); } public static string DebugStringHead(EnemyAI? instance, bool shortFormat = true) { if (debugSpam && debugTriggerFlag) { Script.Logger.LogInfo((object)"Called library DebugStringHead!"); } return NaturalSelectionLib.DebugStringHead(instance, shortFormat); } public static List<EnemyAI> GetCompleteList(EnemyAI instance, bool FilterThemselves = true, int includeOrReturnThedDead = 0) { if (debugSpam && debugTriggerFlag) { Script.Logger.LogInfo((object)"Called library GetCompleteList!"); } return NaturalSelectionLib.GetCompleteList(instance, FilterThemselves, includeOrReturnThedDead); } public static List<EnemyAI> GetInsideOrOutsideEnemyList(List<EnemyAI> importEnemyList, EnemyAI instance) { if (debugSpam && debugTriggerFlag) { Script.Logger.LogInfo((object)"Called library GetInsideOrOutsideEnemyList!"); } return NaturalSelectionLib.GetInsideOrOutsideEnemyList(importEnemyList, instance); } public static EnemyAI? FindClosestEnemy(List<EnemyAI> importEnemyList, EnemyAI? importClosestEnemy, EnemyAI instance, bool includeTheDead = false) { if (debugSpam && debugTriggerFlag) { Script.Logger.LogInfo((object)"Called library findClosestEnemy!"); } return NaturalSelectionLib.FindClosestEnemy(importEnemyList, importClosestEnemy, instance, includeTheDead); } public static List<EnemyAI> FilterEnemyList(List<EnemyAI> importEnemyList, List<Type>? targetTypes, List<string>? blacklist, EnemyAI instance, bool inverseToggle = false, bool filterOutImmortal = true) { if (debugSpam && debugTriggerFlag) { Script.Logger.LogInfo((object)"Called library filterEnemyList!"); } return NaturalSelectionLib.FilterEnemyList(importEnemyList, targetTypes, blacklist, instance, inverseToggle, filterOutImmortal); } public static Dictionary<EnemyAI, float> GetEnemiesInLOS(EnemyAI instance, List<EnemyAI> importEnemyList, float width = 45f, int importRange = 0, float proximityAwareness = -1f) { if (debugSpam && debugTriggerFlag) { Script.Logger.LogInfo((object)"Called library GetEnemiesInLOS!"); } return NaturalSelectionLib.GetEnemiesInLOS(instance, importEnemyList, width, (float)importRange, proximityAwareness); } } internal class MyModConfig { public readonly ConfigEntry<bool> sandwormCollisionOverride; public readonly ConfigEntry<bool> blobAICantOpenDoors; public readonly ConfigEntry<bool> stableMode; public readonly ConfigEntry<bool> IgnoreImmortalEnemies; public readonly ConfigEntry<float> agentRadiusModifier; public readonly ConfigEntry<bool> enableSpider; public readonly ConfigEntry<bool> enableSlime; public readonly ConfigEntry<bool> enableLeviathan; public readonly ConfigEntry<bool> enableSporeLizard; public readonly ConfigEntry<bool> enableRedBees; public readonly ConfigEntry<bool> enableNutcracker; public readonly ConfigEntry<bool> enableGiant; public readonly ConfigEntry<bool> enableHoardingBug; public readonly ConfigEntry<float> beesSetGiantsOnFireMinChance; public readonly ConfigEntry<float> beesSetGiantsOnFireMaxChance; public readonly ConfigEntry<int> giantExtinguishChance; public readonly ConfigEntry<bool> blobConsumesCorpses; public readonly ConfigEntry<bool> blobPathfindToCorpses; public readonly ConfigEntry<bool> blobPathfind; public readonly ConfigEntry<bool> sandwormDoNotEatPlayersInsideLeavingShip; public readonly ConfigEntry<bool> sandwormFilterTypes; public readonly ConfigEntry<bool> enableSpiderWebs; public readonly ConfigEntry<string> speedModifierList; public readonly ConfigEntry<float> webStrength; public readonly ConfigEntry<float> chaseAfterEnemiesModifier; public readonly ConfigEntry<string> beeBlacklist; public readonly ConfigEntry<string> blobBlacklist; public readonly ConfigEntry<string> sandwormBlacklist; public readonly ConfigEntry<string> spiderWebBlacklist; public readonly ConfigEntry<string> spiderBlacklist; public ConfigEntry<bool> debugBool; public ConfigEntry<bool> spammyLogs; public ConfigEntry<bool> debugTriggerFlags; public ConfigEntry<bool> debugNetworking; public ConfigEntry<bool> debugRedBees; public ConfigEntry<bool> debugSandworms; public ConfigEntry<bool> debugHygrodere; public ConfigEntry<bool> debugNutcrackers; public ConfigEntry<bool> debugSpiders; public ConfigEntry<bool> debugGiants; public ConfigEntry<bool> debugUnspecified; public ConfigEntry<bool> debugLibrary; public ConfigEntry<bool> debugSpiderWebs; public Dictionary<string, ConfigEntry<bool>> debugEntries = new Dictionary<string, ConfigEntry<bool>>(); public ConfigEntry<bool> enhancedMonstersCompToggle; public ConfigEntry<bool> sellBodiesFixedCompToggle; public ConfigEntry<bool> ReXuvinationCompToggle; public MyModConfig(ConfigFile cfg) { //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Expected O, but got Unknown //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Expected O, but got Unknown //IL_0236: Unknown result type (might be due to invalid IL or missing references) //IL_0240: Expected O, but got Unknown cfg.SaveOnConfigSet = false; sandwormCollisionOverride = cfg.Bind<bool>("Experimental Fixes", "Sandworm collision override", false, "Override vanilla sandworm collisions. May fix lag when sandworm collides with multiple enemies at once. \n \n May be removed in the future."); blobAICantOpenDoors = cfg.Bind<bool>("Experimental Fixes", "Blob cannot open doors", true, "Blob can't open doors."); stableMode = cfg.Bind<bool>("General Settings", "Toggle stable mode", true, "When true, the mod will exlude patches that are WIP or are experimental from loading. Requires restart."); IgnoreImmortalEnemies = cfg.Bind<bool>("General Settings", "Ignore Immortal Enemies", false, "All immortal enemies will be ignored by majority of entities."); agentRadiusModifier = cfg.Bind<float>("General Settings", "Agent radius modifier", 0.5f, "Modifies agent radius of entities for more reliable collisions."); enableSpider = cfg.Bind<bool>("Entity settings/WIP", "Enable spider", false, "Enable changes to apply to to spider and modify it's behavior. Unfinished."); enableSlime = cfg.Bind<bool>("Entity settings", "Enable slime", true, "Enable changes to apply to to slime and modify it's behavior."); enableLeviathan = cfg.Bind<bool>("Entity settings", "Enable leviathan", true, "Enable changes to apply to to leviathan and modify it's behavior."); enableSporeLizard = cfg.Bind<bool>("Entity settings/WIP", "Enable SporeLizard", false, "Enable changes to apply to to spore lizard. \n\n Early build. DEV ONLY"); enableRedBees = cfg.Bind<bool>("Entity settings", "Enable Red bees (Circuit bees)", true, "Enable changes to apply to red bees and modify it's behavior."); enableNutcracker = cfg.Bind<bool>("Entity settings/WIP", "Enable Nutcracker", false, "Enable changes to nutcracker to apply to and modify its behavior. \n\n Early build. DEV ONLY"); enableGiant = cfg.Bind<bool>("Entity settings", "Enable Giant", true, "Enable changes to apply to to forest giant."); enableHoardingBug = cfg.Bind<bool>("Entity settings/WIP", "Enable Hoarding bug", false, "Enable changes to apply to to hoarding bug"); enableSpiderWebs = cfg.Bind<bool>("Entity settings", "Enable Spider Webs", true, "Enables changes to apply to to spider webs. Webs will stick to and slow down enemies."); giantExtinguishChance = cfg.Bind<int>("Entity settings | Giant", "Extinguish chance", 33, new ConfigDescription("Chance of giants extinguishing themselves in percent.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>())); beesSetGiantsOnFireMinChance = cfg.Bind<float>("Entity settings | Giant", "Ignite giants min chace", 1.5f, new ConfigDescription("The minimum chance bees will set giant on fire on hit in percent. Applies to calm bees.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>())); beesSetGiantsOnFireMaxChance = cfg.Bind<float>("Entity settings | Giant", "Ignite giants max chace", 8f, new ConfigDescription("The minimum chance bees will set giant on fire on hit in percent. Applies to angry bees.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>())); blobConsumesCorpses = cfg.Bind<bool>("Entity settings | Hygrodere", "Consume corpses", true, "Hygrodere consume dead enemy corpses."); blobPathfindToCorpses = cfg.Bind<bool>("Entity settings | Hygrodere", "Pathfind to corpses", true, "Hygrodere move towards corpses to consume."); blobPathfind = cfg.Bind<bool>("Entity settings | Hygrodere", "Pathfind", true, "Pathfind to other entities."); sandwormDoNotEatPlayersInsideLeavingShip = cfg.Bind<bool>("Entity settings | Sandworm", "Do not eat players inside leaving ship", false, "Worms do not eat players inside ship leaving moon."); sandwormFilterTypes = cfg.Bind<bool>("Entity settings | Sandworm", "Filter out enemy types", true, "Filter out enemies by enemy type. When disabled allows sandworms to target that are filtered out (Vanilla enemies smaller than employee). Blacklisting enemies is highly recommended when this setting is disabled."); chaseAfterEnemiesModifier = cfg.Bind<float>("Entity settings | Spider/Spider Web", "Chase after enemies modifier", 3f, "Modifies chase timer for chasing enemies. When chasing another enemy, hunter's chase timer is divided by set number."); speedModifierList = cfg.Bind<string>("Entity settings | Spider/Spider Web", "Web speed modifiers", "", "Modifies final speed of enemy caught in web. \n \n [The ',' acts as a separator between each entry. Entry format: EnemyName:Speed ] \n This config generates automatically."); webStrength = cfg.Bind<float>("Entity settings | Spider/Spider Web", "Spider Web Strenght", 1.3f, "Strength of spider webs. Stronger spider web slows enemies more."); beeBlacklist = cfg.Bind<string>("Blacklists", "Bees Blacklist", "", "Any enemy with set value to true will be ignored by circuit bees. \n \n [The ',' acts as a separator between each entry. Entry format: EnemyName:True/False] \n This config generates automatically."); blobBlacklist = cfg.Bind<string>("Blacklists", "Blob Blacklist", "", "Any enemy with set value to true will be ignored by hygroderes. \n \n [The ',' acts as a separator between each entry. Entry format: EnemyName:True/False ] \n This config generates automatically."); sandwormBlacklist = cfg.Bind<string>("Blacklists", "Sandworm Blacklist", "", "Any enemy with set value to true will be ignored by sandworms. \n \n [The ',' acts as a separator between each entry. Entry format: EnemyName:True/False] \n This config generates automatically."); spiderWebBlacklist = cfg.Bind<string>("Blacklists", "Web blacklist", "", "Any enemy with set value to true will be ignored by webs. \n \n [The ',' acts as a separator between each entry. Entry format: EnemyName:True/False] \n This config generates automatically."); spiderBlacklist = cfg.Bind<string>("Blacklists", "Spider blacklist", "", "Any enemy with set value to true will be ignored by spider. \n \n [The ',' acts as a separator between each entry. Entry format: EnemyName:True/False] \n This config generates automatically."); debugBool = cfg.Bind<bool>("Debug", "Debug mode", false, "Enables debug mode for more debug logs. Can be changed at runtime via config mods."); debugEntries.Add("debugBool", debugBool); spammyLogs = cfg.Bind<bool>("Debug", "Spammy logs", false, "Enables spammy logs for extra logs. Can be changed at runtime via config mods."); debugEntries.Add("spammyLogs", spammyLogs); debugNetworking = cfg.Bind<bool>("Debug", "Debug networking", false, "Enables debug logs for networking. Can be changed at runtime via config mods."); debugEntries.Add("debugNetworking", debugNetworking); debugTriggerFlags = cfg.Bind<bool>("Debug", "Trigger flags", false, "Enables logs with trigger flag."); debugEntries.Add("debugTriggerFlags", debugTriggerFlags); debugUnspecified = cfg.Bind<bool>("Debug", "Log unspecified", false, "Enables logs for unspecified. Can be changed at runtime via config mods."); debugEntries.Add("debugUnspecified", debugUnspecified); debugLibrary = cfg.Bind<bool>("Debug", "Log library", false, "Enables logs for the library. Can be changed at runtime via config mods."); debugEntries.Add("debugLibrary", debugLibrary); debugRedBees = cfg.Bind<bool>("Debug", "Log bees", false, "Enables logs for bees. Can be changed at runtime via config mods."); debugEntries.Add("debugRedBees", debugRedBees); debugSandworms = cfg.Bind<bool>("Debug", "Log sandworms", false, "Enables logs for sandowrms. Can be changed at runtime via config mods."); debugEntries.Add("debugSandworms", debugSandworms); debugHygrodere = cfg.Bind<bool>("Debug", "Log hydrogere", false, "Enables logs for hydrogere. Can be changed at runtime via config mods."); debugEntries.Add("debugHygrodere", debugHygrodere); debugNutcrackers = cfg.Bind<bool>("Debug", "Log nutcrackers", false, "Enables logs for nutcrackers. Can be changed at runtime via config mods."); debugEntries.Add("debugNutcrackers", debugNutcrackers); debugSpiders = cfg.Bind<bool>("Debug", "Log spiders", false, "Enables logs for spiders. Can be changed at runtime via config mods."); debugEntries.Add("debugSpiders", debugSpiders); debugGiants = cfg.Bind<bool>("Debug", "Log giants", false, "Enables logs for giants. Can be changed at runtime via config mods."); debugEntries.Add("debugGiants", debugGiants); debugSpiderWebs = cfg.Bind<bool>("Debug", "Log spider webs", false, "Enables logs for spider webs. Can be changed at runtime via config mods."); debugEntries.Add("debugSpiderWebs", debugSpiderWebs); ReXuvinationCompToggle = cfg.Bind<bool>("Compatibility toggles", "ReXuvination compatibility", false, "Manually toggles compatibility patches for ReXuvination."); enhancedMonstersCompToggle = cfg.Bind<bool>("WIP", "Enhanced monsters compatibility", false, "Manually toggles compatibility patches for Enhanced monsters."); sellBodiesFixedCompToggle = cfg.Bind<bool>("WIP", "Sellbodiesfixed compatibility", false, "Manually toggles compatibility patches for Sellbodiesfixed."); ClearOrphanedEntries(cfg); cfg.Save(); cfg.SaveOnConfigSet = true; } public void ClearOrphanedEntries(ConfigFile cfg) { PropertyInfo propertyInfo = AccessTools.Property(typeof(ConfigFile), "OrphanedEntries"); Dictionary<ConfigDefinition, string> dictionary = (Dictionary<ConfigDefinition, string>)propertyInfo.GetValue(cfg); foreach (KeyValuePair<ConfigDefinition, string> item in dictionary) { Script.Logger.LogWarning((object)("Found orphaned entry of " + item.Key.Section + ": " + item.Key.Key + ", " + item.Value + ". Make sure your configuration was not altered.")); } dictionary.Clear(); } } public class Networking { public static Dictionary<string, int> NetworkingDictionary = new Dictionary<string, int>(); private static bool logNetworking = Script.Bools["debugNetworking"]; private static void Event_OnConfigSettingChanged(string entryKey, bool value) { if (entryKey == "debugNetworking") { logNetworking = value; } } public static void SubscribeToConfigChanges() { Script.OnConfigSettingChanged = (Action<string, bool>)Delegate.Combine(Script.OnConfigSettingChanged, new Action<string, bool>(Event_OnConfigSettingChanged)); } public static LNetworkVariable<float> NSEnemyNetworkVariableFloat(string NWID) { if (!NetworkingDictionary.ContainsKey(NWID)) { NetworkingDictionary.Add(NWID, 31); } return LNetworkVariable<float>.Connect(NWID, 0f, (LNetworkVariableWritePerms)0, (Action<float, float>)null); } public static LNetworkVariable<int> NSEnemyNetworkVariableInt(string NWID) { if (!NetworkingDictionary.ContainsKey(NWID)) { NetworkingDictionary.Add(NWID, 32); } return LNetworkVariable<int>.Connect(NWID, 0, (LNetworkVariableWritePerms)0, (Action<int, int>)null); } public static LNetworkVariable<bool> NSEnemyNetworkVariableBool(string NWID) { if (!NetworkingDictionary.ContainsKey(NWID)) { NetworkingDictionary.Add(NWID, 33); } return LNetworkVariable<bool>.Connect(NWID, false, (LNetworkVariableWritePerms)0, (Action<bool, bool>)null); } public static LNetworkEvent NSEnemyNetworkEvent(string NWID) { if (!NetworkingDictionary.ContainsKey(NWID)) { NetworkingDictionary.Add(NWID, 2); } return LNetworkEvent.Connect(NWID, (Action<ulong>)null, (Action)null, (Action<ulong>)null); } public static void ClearSubscribtionsInDictionary() { foreach (KeyValuePair<string, int> item in NetworkingDictionary) { switch (item.Value) { case 2: if (logNetworking) { Script.Logger.LogDebug((object)("Clearing subscriptions of event " + item.Key)); } LNetworkEvent.Connect(item.Key, (Action<ulong>)null, (Action)null, (Action<ulong>)null).ClearSubscriptions(); break; case 31: if (logNetworking) { Script.Logger.LogDebug((object)("Disposing of network float " + item.Key)); } LNetworkVariable<float>.Connect(item.Key, 0f, (LNetworkVariableWritePerms)0, (Action<float, float>)null).Dispose(); break; case 32: if (logNetworking) { Script.Logger.LogDebug((object)("Disposing of network int " + item.Key)); } LNetworkVariable<int>.Connect(item.Key, 0, (LNetworkVariableWritePerms)0, (Action<int, int>)null).Dispose(); break; case 33: if (logNetworking) { Script.Logger.LogDebug((object)("Disposing of network bool " + item.Key)); } LNetworkVariable<bool>.Connect(item.Key, false, (LNetworkVariableWritePerms)0, (Action<bool, bool>)null).Dispose(); break; } } Script.Logger.LogInfo((object)"/Networking/ Finished clearing dictionary."); NetworkingDictionary.Clear(); } } internal class NetworkingMethods { [HarmonyPatch(typeof(GameNetworkManager), "ResetGameValuesToDefault")] [HarmonyPostfix] private static void ResetGameValuesToDefaultPatch() { Script.Logger.LogInfo((object)"/Networking-ResetGameValuesToDefault/ Clearing all subscribtions and globalEnemyLists."); Networking.ClearSubscribtionsInDictionary(); NaturalSelectionLib.globalEnemyLists.Clear(); } [HarmonyPatch(typeof(RoundManager), "ResetEnemyVariables")] [HarmonyPostfix] private static void ResetEnemyVariablesPatch() { Script.Logger.LogInfo((object)"/Networking-ResetEnemyVariables/ Clearing all subscribtions and globalEnemyLists."); Networking.ClearSubscribtionsInDictionary(); NaturalSelectionLib.globalEnemyLists.Clear(); } } [HarmonyPatch(typeof(RoundManager))] internal class RoundManagerPatch { private static float nextUpdate = 0f; private static float updateTime = 0f; private static Dictionary<Type, List<EnemyAI>> checkedTypes = new Dictionary<Type, List<EnemyAI>>(); public static float updateListInterval = 1f; private static bool logSpam = Script.Bools["spammyLogs"]; private static bool logUnspecified = Script.Bools["debugUnspecified"]; private static void Event_OnConfigSettingChanged(string entryKey, bool value) { if (entryKey == "debugUnspecified") { logUnspecified = value; } if (entryKey == "spammyLogs") { logSpam = value; } } [HarmonyPatch("Awake")] [HarmonyPostfix] private static void AwakePostfixPatch() { Script.OnConfigSettingChanged = (Action<string, bool>)Delegate.Combine(Script.OnConfigSettingChanged, new Action<string, bool>(Event_OnConfigSettingChanged)); } [HarmonyPatch("Update")] [HarmonyPrefix] private static void UpdatePatch() { if (!(Time.realtimeSinceStartup >= nextUpdate)) { return; } foreach (Type item in checkedTypes.Keys.ToList()) { NaturalSelectionLib.UpdateListInsideDictionrary(item, checkedTypes[item]); } checkedTypes.Clear(); nextUpdate = Time.realtimeSinceStartup + updateListInterval; } public static bool RequestUpdate(EnemyAI instance) { if (!checkedTypes.ContainsKey(((object)instance).GetType()) && ((NetworkBehaviour)instance).IsOwner) { checkedTypes.Add(((object)instance).GetType(), new List<EnemyAI>()); if (logUnspecified && logSpam) { Script.Logger.LogMessage((object)$"/RoundManager/ request was Accepted. Requested by {LibraryCalls.DebugStringHead(instance)} at {Time.realtimeSinceStartup}"); } return true; } if (logUnspecified && logSpam && !((NetworkBehaviour)instance).IsOwner) { Script.Logger.LogDebug((object)"/RoundManager/ request was Denied. Not owner of the instance."); } else if (logUnspecified && logSpam) { Script.Logger.LogDebug((object)$"/RoundManager/ request was Denied. Requested by {LibraryCalls.DebugStringHead(instance)} at {Time.realtimeSinceStartup}"); } return false; } public static void ScheduleGlobalListUpdate(EnemyAI instance, List<EnemyAI> list) { if (checkedTypes.ContainsKey(((object)instance).GetType())) { checkedTypes[((object)instance).GetType()] = list; } if (!NaturalSelectionLib.globalEnemyLists.ContainsKey(((object)instance).GetType())) { Script.Logger.LogWarning((object)(LibraryCalls.DebugStringHead(instance) + "global enemy list for this enemy does not exist! Creating a new one.")); NaturalSelectionLib.UpdateListInsideDictionrary(((object)instance).GetType(), checkedTypes[((object)instance).GetType()]); } } } } namespace NaturalSelection.Experimental { public class EnhancedMonstersPatch { public static List<GameObject> deadEnemiesList = new List<GameObject>(); [HarmonyPatch(typeof(EnemyAI_Patches), "KillEnemy")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> EnhancedMonstersKillEnemyPatchT(IEnumerable<CodeInstruction> instructions) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Expected O, but got Unknown //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Expected O, but got Unknown //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Expected O, but got Unknown //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Expected O, but got Unknown //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Expected O, but got Unknown //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Expected O, but got Unknown //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Expected O, but got Unknown //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Expected O, but got Unknown //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Expected O, but got Unknown //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Expected O, but got Unknown //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Expected O, but got Unknown Script.Logger.LogWarning((object)"Fired Transpiller for EnemyAI.KillEnemyOnOwnerClient"); CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null); Script.Logger.LogInfo((object)new CodeInstruction(OpCodes.Ldsfld, (object)AccessTools.Field(typeof(Script), "Logger"))); Script.Logger.LogInfo((object)new CodeInstruction(OpCodes.Ldstr, (object)"Successfully Transpiled EnhancedMonster by NaturalSelection")); Script.Logger.LogInfo((object)new CodeInstruction(OpCodes.Callvirt, (object)AccessTools.Method(typeof(ManualLogSource), "LogMessage", new Type[1] { typeof(string) }, (Type[])null))); val.MatchForward(true, (CodeMatch[])(object)new CodeMatch[4] { new CodeMatch((OpCode?)OpCodes.Ldloc_S, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Callvirt, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldc_I4_0, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Callvirt, (object)AccessTools.Method(typeof(NetworkObject), "Spawn", (Type[])null, (Type[])null), (string)null) }).ThrowIfInvalid("Could not find match for EnhancedMonstersKillEnemyPatchT").Advance(1) .InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { new CodeInstruction(OpCodes.Ldsfld, (object)AccessTools.Field(typeof(Plugin), "logger")) }) .InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { new CodeInstruction(OpCodes.Ldstr, (object)"Successfully Transpiled EnhancedMonster by NaturalSelection") }) .InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { new CodeInstruction(OpCodes.Callvirt, (object)AccessTools.Method(typeof(ManualLogSource), "LogMessage", new Type[1] { typeof(string) }, (Type[])null)) }) .InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { new CodeInstruction(OpCodes.Ldsfld, (object)AccessTools.Field(typeof(EnhancedMonstersPatch), "deadEnemiesList")) }) .InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { new CodeInstruction(OpCodes.Ldloc_S, (object)8) }) .Insert((CodeInstruction[])(object)new CodeInstruction[1] { new CodeInstruction(OpCodes.Callvirt, (object)AccessTools.Method(typeof(List<GameObject>), "Add", new Type[1] { typeof(GameObject) }, (Type[])null)) }); int num = 0; for (int i = 0; i < instructions.ToList().Count; i++) { try { if (((object)val.Instructions().ToList()[i]).ToString() != ((object)instructions.ToList()[i - num]).ToString()) { Script.Logger.LogError((object)$"{val.Instructions().ToList()[i]} : {instructions.ToList()[i - num]}"); if (((object)val.Instructions().ToList()[i]).ToString() != ((object)instructions.ToList()[i - num]).ToString()) { num++; } } else { Script.Logger.LogInfo((object)instructions.ToList()[i]); } } catch { Script.Logger.LogError((object)"Failed to read instructions"); } } return val.Instructions(); } } internal class SellBodiesTraceScript : MonoBehaviour { private GameObject instance; public SellBodiesTraceScript() { instance = ((Component)this).gameObject; } private void Awake() { instance = ((Component)this).gameObject; Script.Logger.LogMessage((object)("Successfully added SellBodiesTraceScript of " + ((Object)instance).name)); if (!SellBodiesFixedPatch.deadEnemyBodies.Contains(instance)) { SellBodiesFixedPatch.deadEnemyBodies.Add(instance); } } private void OnDestroy() { Script.Logger.LogMessage((object)("Removing SellBodiesTraceScript " + ((Object)instance).name + " from list")); SellBodiesFixedPatch.deadEnemyBodies.Remove(instance); } } internal class SellBodiesFixedPatch { public static List<GameObject> deadEnemyBodies = new List<GameObject>(); public static void AddTracerScriptToPrefabs() { foreach (KeyValuePair<string, string> item in Plugin.instance.pathToName) { Item val = Plugin.instance.bundle.LoadAsset<Item>(item.Key); val.spawnPrefab.gameObject.AddComponent<SellBodiesTraceScript>(); Script.Logger.LogMessage((object)("Added SellBodiesTracerScript to " + item.Value + " at " + item.Key)); } } } } namespace NaturalSelection.EnemyPatches { internal class BeeValues { internal EnemyAI? closestEnemy; internal EnemyAI? targetEnemy; internal Vector3 lastKnownEnemyPosition = Vector3.zero; internal int customBehaviorStateIndex; internal Dictionary<EnemyAI, float> hitRegistry = new Dictionary<EnemyAI, float>(); internal float LostLOSOfEnemy; internal List<Type> enemyTypes = new List<Type>(); internal float delayTimer = 0.2f; internal List<EnemyAI> localEnemyList = new List<EnemyAI>(); } [HarmonyPatch(typeof(RedLocustBees))] internal class BeeAIPatch { private static Dictionary<RedLocustBees, BeeValues> beeList = new Dictionary<RedLocustBees, BeeValues>(); private static bool logBees = Script.Bools["debugRedBees"]; private static bool debugSpam = Script.Bools["spammyLogs"]; private static bool debugTriggers = Script.Bools["debugTriggerFlags"]; private static List<string> beeBlacklist = InitializeGamePatch.beeBlacklistFinal; private static void Event_OnConfigSettingChanged(string entryKey, bool value) { if (entryKey == "debugRedBees") { logBees = value; } if (entryKey == "spammyLogs") { debugSpam = value; } if (entryKey == "debugTriggerFlags") { debugTriggers = value; } } [HarmonyPatch("Start")] [HarmonyPostfix] private static void StartPatch(RedLocustBees __instance) { if (!beeList.ContainsKey(__instance)) { beeList.Add(__instance, new BeeValues()); } BeeValues beeValues = beeList[__instance]; if (beeValues.enemyTypes.Count < 1) { beeValues.enemyTypes.Add(typeof(DocileLocustBeesAI)); beeValues.enemyTypes.Add(typeof(SandWormAI)); } Script.OnConfigSettingChanged = (Action<string, bool>)Delegate.Combine(Script.OnConfigSettingChanged, new Action<string, bool>(Event_OnConfigSettingChanged)); } [HarmonyPatch("Update")] [HarmonyPostfix] private static void UpdatePatch(RedLocustBees __instance) { BeeValues beeValues = beeList[__instance]; if (RoundManagerPatch.RequestUpdate((EnemyAI)(object)__instance)) { List<EnemyAI> list = new List<EnemyAI>(LibraryCalls.FilterEnemyList(LibraryCalls.GetCompleteList((EnemyAI)(object)__instance), beeList[__instance].enemyTypes, beeBlacklist, (EnemyAI)(object)__instance, inverseToggle: true, Script.BoundingConfig.IgnoreImmortalEnemies.Value)); RoundManagerPatch.ScheduleGlobalListUpdate((EnemyAI)(object)__instance, list); } foreach (KeyValuePair<EnemyAI, float> item in new Dictionary<EnemyAI, float>(beeValues.hitRegistry)) { if (item.Value > 1.7f) { beeValues.hitRegistry.Remove(item.Key); } else { beeValues.hitRegistry[item.Key] += Time.deltaTime; } } } [HarmonyPatch("DoAIInterval")] [HarmonyPrefix] private static bool DoAIIntervalPrefixPatch(RedLocustBees __instance) { //IL_0069: Unknown result type (might be due to invalid IL or missing references) BeeValues beeValues = beeList[__instance]; if ((Object)(object)beeValues.targetEnemy != (Object)null && !((EnemyAI)__instance).movingTowardsTargetPlayer && ((EnemyAI)__instance).currentBehaviourStateIndex != 0) { if (logBees && debugSpam && debugTriggers) { Script.Logger.LogDebug((object)(LibraryCalls.DebugStringHead((EnemyAI?)(object)__instance) + " DoAIInterval: Prefix triggered false")); } if (((EnemyAI)__instance).moveTowardsDestination) { ((EnemyAI)__instance).agent.SetDestination(((EnemyAI)__instance).destination); } ((EnemyAI)__instance).SyncPositionToClients(); return false; } if (logBees && debugSpam && debugTriggers) { Script.Logger.LogDebug((object)(LibraryCalls.DebugStringHead((EnemyAI?)(object)__instance) + " DoAIInterval: Prefix triggered true")); } return true; } [HarmonyPatch("DoAIInterval")] [HarmonyPostfix] private static void DoAIIntervalPostfixPatch(RedLocustBees __instance) { //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_0283: Unknown result type (might be due to invalid IL or missing references) //IL_03e2: Unknown result type (might be due to invalid IL or missing references) //IL_03f2: Unknown result type (might be due to invalid IL or missing references) //IL_060e: Unknown result type (might be due to invalid IL or missing references) //IL_0613: Unknown result type (might be due to invalid IL or missing references) //IL_061d: Unknown result type (might be due to invalid IL or missing references) //IL_0622: Unknown result type (might be due to invalid IL or missing references) //IL_0627: Unknown result type (might be due to invalid IL or missing references) //IL_02ea: Unknown result type (might be due to invalid IL or missing references) //IL_02fa: Unknown result type (might be due to invalid IL or missing references) //IL_065c: Unknown result type (might be due to invalid IL or missing references) //IL_0318: 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_04b5: Unknown result type (might be due to invalid IL or missing references) //IL_035f: Unknown result type (might be due to invalid IL or missing references) //IL_08a0: Unknown result type (might be due to invalid IL or missing references) //IL_08cd: Unknown result type (might be due to invalid IL or missing references) //IL_072c: Unknown result type (might be due to invalid IL or missing references) //IL_073c: Unknown result type (might be due to invalid IL or missing references) //IL_09d5: Unknown result type (might be due to invalid IL or missing references) //IL_09da: Unknown result type (might be due to invalid IL or missing references) //IL_09e1: Unknown result type (might be due to invalid IL or missing references) //IL_075a: Unknown result type (might be due to invalid IL or missing references) //IL_07a1: Unknown result type (might be due to invalid IL or missing references) //IL_0aaa: Unknown result type (might be due to invalid IL or missing references) //IL_0a70: Unknown result type (might be due to invalid IL or missing references) BeeValues beeValues = beeList[__instance]; Type type = ((object)__instance).GetType(); beeValues.localEnemyList = new List<EnemyAI>(LibraryCalls.GetInsideOrOutsideEnemyList(NaturalSelectionLib.globalEnemyLists[type], (EnemyAI)(object)__instance)); Dictionary<EnemyAI, float> dictionary = new Dictionary<EnemyAI, float>(LibraryCalls.GetEnemiesInLOS((EnemyAI)(object)__instance, beeValues.localEnemyList, 360f, 16, 1f)); switch (((EnemyAI)__instance).currentBehaviourStateIndex) { case 0: { EnemyAI val4 = null; if (dictionary.Count > 0) { foreach (KeyValuePair<EnemyAI, float> item in new Dictionary<EnemyAI, float>(dictionary)) { if (logBees && debugSpam) { Script.Logger.LogDebug((object)$"{LibraryCalls.DebugStringHead((EnemyAI?)(object)__instance)} Checking the LOSList: {LibraryCalls.DebugStringHead(item.Key)}, Distance: {item.Value}"); } if ((Object)(object)item.Key == (Object)(object)__instance) { if (logBees && debugSpam) { Script.Logger.LogWarning((object)$"{LibraryCalls.DebugStringHead((EnemyAI?)(object)__instance)} FOUND ITSELF IN THE LOSList: {LibraryCalls.DebugStringHead(item.Key)} Distance: {item.Value}"); } dictionary.Remove(item.Key); } if (((object)item.Key).GetType() == ((object)__instance).GetType()) { if (logBees && debugSpam) { Script.Logger.LogWarning((object)$"{LibraryCalls.DebugStringHead((EnemyAI?)(object)__instance)} Found its type in THE LOSList: {LibraryCalls.DebugStringHead(item.Key)}, Distance: {item.Value}"); } dictionary.Remove(item.Key); } if (item.Key.isEnemyDead) { if (logBees && debugSpam) { Script.Logger.LogDebug((object)$"{LibraryCalls.DebugStringHead((EnemyAI?)(object)__instance)} Found dead enemy in LOSList: {LibraryCalls.DebugStringHead(item.Key)}, Distance: {item.Value}"); } dictionary.Remove(item.Key); } } if (dictionary.Count > 0) { val4 = dictionary.Keys.First(); } if (logBees) { Script.Logger.LogInfo((object)(LibraryCalls.DebugStringHead((EnemyAI?)(object)__instance) + " case0: Checked LOS for enemies. Enemy found: " + LibraryCalls.DebugStringHead(val4))); } } if (__instance.wasInChase) { __instance.wasInChase = false; } if (Vector3.Distance(((Component)__instance).transform.position, __instance.lastKnownHivePosition) > 2f) { ((EnemyAI)__instance).SetDestinationToPosition(__instance.lastKnownHivePosition, true); } if (__instance.IsHiveMissing()) { ((EnemyAI)__instance).SwitchToBehaviourState(2); beeValues.customBehaviorStateIndex = 2; if (logBees) { Script.Logger.LogInfo((object)$"{LibraryCalls.DebugStringHead((EnemyAI?)(object)__instance)} case0: HIVE IS MISSING! CustomBehaviorStateIndex changed: {beeValues.customBehaviorStateIndex}"); } } else if ((Object)(object)val4 != (Object)null && Vector3.Distance(((Component)val4).transform.position, ((Component)__instance.hive).transform.position) < (float)__instance.defenseDistance) { ((EnemyAI)__instance).SetDestinationToPosition(((Component)val4).transform.position, true); if (logBees) { Script.Logger.LogInfo((object)$"{LibraryCalls.DebugStringHead((EnemyAI?)(object)__instance)} case0: Moving towards {val4}"); } beeValues.customBehaviorStateIndex = 1; ((EnemyAI)__instance).SwitchToBehaviourState(1); __instance.syncedLastKnownHivePosition = false; __instance.SyncLastKnownHivePositionServerRpc(__instance.lastKnownHivePosition); beeValues.LostLOSOfEnemy = 0f; if (logBees) { Script.Logger.LogDebug((object)$"{LibraryCalls.DebugStringHead((EnemyAI?)(object)__instance)} case0: CustomBehaviorStateIndex changed: {beeValues.customBehaviorStateIndex}"); } } break; } case 1: { if (((Object)(object)((EnemyAI)__instance).targetPlayer != (Object)null && ((EnemyAI)__instance).movingTowardsTargetPlayer) || (!((Object)(object)beeValues.targetEnemy == (Object)null) && !beeValues.targetEnemy.isEnemyDead && !(Vector3.Distance(((Component)beeValues.targetEnemy).transform.position, ((Component)__instance.hive).transform.position) > (float)__instance.defenseDistance + 5f))) { break; } bool flag2 = false; EnemyAI val3 = null; if (dictionary.Count > 0) { val3 = dictionary.Keys.First(); } if (logBees) { Script.Logger.LogDebug((object)$"{LibraryCalls.DebugStringHead((EnemyAI?)(object)__instance)} case2: {val3} is closest to hive."); } if ((Object)(object)val3 != (Object)null && (Object)(object)beeValues.targetEnemy != (Object)(object)val3) { flag2 = true; __instance.wasInChase = false; beeValues.targetEnemy = val3; ((EnemyAI)__instance).SetDestinationToPosition(((Component)beeValues.targetEnemy).transform.position, true); ((EnemyAI)__instance).StopSearch(__instance.searchForHive, true); __instance.syncedLastKnownHivePosition = false; beeValues.LostLOSOfEnemy = 0f; __instance.SyncLastKnownHivePositionServerRpc(__instance.lastKnownHivePosition); if (logBees) { Script.Logger.LogInfo((object)$"{LibraryCalls.DebugStringHead((EnemyAI?)(object)__instance)} case2: Targeting {val3}. Synced hive position"); } } else { if (!((Object)(object)beeValues.targetEnemy != (Object)null)) { break; } ((EnemyAI)__instance).agent.acceleration = 16f; if (!flag2 && dictionary.Count == 0) { beeValues.targetEnemy = null; } __instance.wasInChase = false; if (__instance.IsHiveMissing()) { beeValues.customBehaviorStateIndex = 2; ((EnemyAI)__instance).SwitchToBehaviourState(2); if (logBees) { Script.Logger.LogInfo((object)$"{LibraryCalls.DebugStringHead((EnemyAI?)(object)__instance)} case1: HIVE IS MISSING! CustomBehaviorStateIndex changed: {beeValues.customBehaviorStateIndex}"); } } else { beeValues.customBehaviorStateIndex = 0; ((EnemyAI)__instance).SwitchToBehaviourState(0); if (logBees) { Script.Logger.LogDebug((object)$"{LibraryCalls.DebugStringHead((EnemyAI?)(object)__instance)} case1: CustomBehaviorStateIndex changed: {beeValues.customBehaviorStateIndex}"); } } } break; } case 2: { if ((Object)(object)((EnemyAI)__instance).targetPlayer != (Object)null || ((EnemyAI)__instance).movingTowardsTargetPlayer) { if (logBees && debugSpam) { Script.Logger.LogDebug((object)(LibraryCalls.DebugStringHead((EnemyAI?)(object)__instance) + " case2: target player found or moving towards target player")); } break; } if (__instance.IsHivePlacedAndInLOS()) { if (__instance.wasInChase) { __instance.wasInChase = false; } __instance.lastKnownHivePosition = ((Component)__instance.hive).transform.position + Vector3.up * 0.5f; if (logBees) { Script.Logger.LogDebug((object)(LibraryCalls.DebugStringHead((EnemyAI?)(object)__instance) + " case2: IsHivePlacedAndInLOS triggered")); } EnemyAI val = null; Collider[] array = Physics.OverlapSphere(((Component)__instance.hive).transform.position, (float)__instance.defenseDistance, StartOfRound.Instance.collidersAndRoomMaskAndDefault, (QueryTriggerInteraction)2); if (array != null && array.Length != 0) { for (int i = 0; i < array.Length; i++) { if (((Component)array[i]).gameObject.tag == "Enemy" && !((Object)(object)((Component)array[i]).gameObject.GetComponent<EnemyAICollisionDetect>().mainScript == (Object)(object)__instance)) { val = ((Component)array[i]).gameObject.GetComponent<EnemyAICollisionDetect>().mainScript; if (logBees) { Script.Logger.LogInfo((object)(LibraryCalls.DebugStringHead((EnemyAI?)(object)__instance) + " case2: CollisionArray triggered. Enemy found: " + LibraryCalls.DebugStringHead(val))); } break; } } } if ((Object)(object)val != (Object)null && Vector3.Distance(((Component)val).transform.position, ((Component)__instance.hive).transform.position) < (float)__instance.defenseDistance) { ((EnemyAI)__instance).SetDestinationToPosition(((Component)val).transform.position, true); if (logBees) { Script.Logger.LogInfo((object)$"{LibraryCalls.DebugStringHead((EnemyAI?)(object)__instance)} case2: Moving towards: {val}"); } beeValues.customBehaviorStateIndex = 1; ((EnemyAI)__instance).SwitchToBehaviourState(1); __instance.syncedLastKnownHivePosition = false; __instance.SyncLastKnownHivePositionServerRpc(__instance.lastKnownHivePosition); beeValues.LostLOSOfEnemy = 0f; if (logBees) { Script.Logger.LogDebug((object)$"{LibraryCalls.DebugStringHead((EnemyAI?)(object)__instance)} case2: CustomBehaviorStateIndex changed: {beeValues.customBehaviorStateIndex}"); } } else { beeValues.customBehaviorStateIndex = 0; ((EnemyAI)__instance).SwitchToBehaviourState(0); if (logBees) { Script.Logger.LogDebug((object)$"{LibraryCalls.DebugStringHead((EnemyAI?)(object)__instance)} case2: CustomBehaviorStateIndex changed: {beeValues.customBehaviorStateIndex}"); } } break; } bool flag = false; EnemyAI val2 = null; if (dictionary.Count > 0) { val2 = dictionary.Keys.First(); } if (logBees) { Script.Logger.LogDebug((object)$"{LibraryCalls.DebugStringHead((EnemyAI?)(object)__instance)} case2: {val2} is closest to hive."); } if ((Object)(object)val2 != (Object)null && (Object)(object)beeValues.targetEnemy != (Object)(object)val2) { flag = true; __instance.wasInChase = false; beeValues.targetEnemy = val2; ((EnemyAI)__instance).SetDestinationToPosition(((Component)beeValues.targetEnemy).transform.position, true); ((EnemyAI)__instance).StopSearch(__instance.searchForHive, true); __instance.syncedLastKnownHivePosition = false; beeValues.LostLOSOfEnemy = 0f; __instance.SyncLastKnownHivePositionServerRpc(__instance.lastKnownHivePosition); if (logBees) { Script.Logger.LogInfo((object)$"{LibraryCalls.DebugStringHead((EnemyAI?)(object)__instance)} case2: Targeting {val2}. Synced hive position"); } break; } if ((Object)(object)beeValues.targetEnemy != (Object)null) { ((EnemyAI)__instance).agent.acceleration = 16f; if (!flag && dictionary.Count == 0) { if (logBees && debugSpam) { Script.Logger.LogDebug((object)$"{LibraryCalls.DebugStringHead((EnemyAI?)(object)__instance)} case2: lost LOS of {beeValues.targetEnemy}, started timer."); } beeValues.LostLOSOfEnemy += ((EnemyAI)__instance).AIIntervalTime; if (beeValues.LostLOSOfEnemy >= 4.5f) { beeValues.targetEnemy = null; beeValues.LostLOSOfEnemy = 0f; if (logBees) { Script.Logger.LogDebug((object)$"{LibraryCalls.DebugStringHead((EnemyAI?)(object)__instance)} case2: lost LOS of {beeValues.targetEnemy}, Stopped and reset timer."); } } } else { __instance.wasInChase = true; beeValues.lastKnownEnemyPosition = ((Component)beeValues.targetEnemy).transform.position; ((EnemyAI)__instance).SetDestinationToPosition(beeValues.lastKnownEnemyPosition, true); beeValues.LostLOSOfEnemy = 0f; if (logBees) { Script.Logger.LogDebug((object)$"{LibraryCalls.DebugStringHead((EnemyAI?)(object)__instance)} case2: lost {beeValues.targetEnemy}"); } } break; } ((EnemyAI)__instance).agent.acceleration = 13f; if (__instance.searchForHive.inProgress) { break; } if (logBees) { Script.Logger.LogInfo((object)(LibraryCalls.DebugStringHead((EnemyAI?)(object)__instance) + " case2: set new search for hive")); } if (__instance.wasInChase) { ((EnemyAI)__instance).StartSearch(beeValues.lastKnownEnemyPosition, __instance.searchForHive); if (logBees) { Script.Logger.LogDebug((object)(LibraryCalls.DebugStringHead((EnemyAI?)(object)__instance) + " case2: Started search for hive.")); } } else { ((EnemyAI)__instance).StartSearch(((Component)__instance).transform.position, __instance.searchForHive); if (logBees) { Script.Logger.LogDebug((object)(LibraryCalls.DebugStringHead((EnemyAI?)(object)__instance) + " case2: Started search for hive.")); } } break; } } } private static LNetworkVariable<float> NSSetOnFireChance(RedLocustBees instance) { string nWID = "NSSetOnFireChance" + ((NetworkBehaviour)instance).NetworkObjectId; return Networking.NSEnemyNetworkVariableFloat(nWID); } private static LNetworkVariable<float> NSSetOnFireMaxChance(RedLocustBees instance) { string nWID = "NSSetOnFireMaxChance" + ((NetworkBehaviour)instance).NetworkObjectId; return Networking.NSEnemyNetworkVariableFloat(nWID); } private static LNetworkEvent NetworkSetGiantOnFire(ForestGiantAI forestGiantAI) { string nWID = "NSSetGiantOnFire" + ((NetworkBehaviour)forestGiantAI).NetworkObjectId; return Networking.NSEnemyNetworkEvent(nWID); } public static void OnCustomEnemyCollision(RedLocustBees __instance, EnemyAI mainscript2) { //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Expected O, but got Unknown if (!beeList.ContainsKey(__instance) || beeBlacklist.Contains(mainscript2.enemyType.enemyName) || (((beeList[__instance].hitRegistry.ContainsKey(mainscript2) && !(beeList[__instance].hitRegistry[mainscript2] > 1.7f)) || ((EnemyAI)__instance).currentBehaviourStateIndex <= 0 || mainscript2.isEnemyDead) && ((beeList[__instance].hitRegistry.ContainsKey(mainscript2) && !(beeList[__instance].hitRegistry[mainscript2] > 1.2f)) || ((EnemyAI)__instance).currentBehaviourStateIndex != 2 || mainscript2.isEnemyDead))) { return; } mainscript2.HitEnemy(1, (PlayerControllerB)null, true, -1); if (!beeList[__instance].hitRegistry.ContainsKey(mainscript2)) { beeList[__instance].hitRegistry.Add(mainscript2, 0f); } else { beeList[__instance].hitRegistry[mainscript2] = 0f; } if (!(mainscript2 is ForestGiantAI) || mainscript2.currentBehaviourStateIndex == 2) { return; } if (((NetworkBehaviour)__instance).IsOwner) { NSSetOnFireChance(__instance).Value = Random.Range(0f, 100f); if (((EnemyAI)__instance).currentBehaviourStateIndex != 2) { NSSetOnFireMaxChance(__instance).Value = Script.BoundingConfig.beesSetGiantsOnFireMinChance.Value; } else { NSSetOnFireMaxChance(__instance).Value = Script.BoundingConfig.beesSetGiantsOnFireMaxChance.Value; } Script.Logger.LogInfo((object)$"{LibraryCalls.DebugStringHead((EnemyAI?)(object)__instance)} OnCustomEnemyCollision: Giant hit. Chance to set on fire: {NSSetOnFireMaxChance(__instance).Value} , rolled {NSSetOnFireChance(__instance)}"); } else if (logBees) { Script.Logger.LogMessage((object)"Client not elligible to determine chance to set giant on fire"); } if (NSSetOnFireChance(__instance).Value <= NSSetOnFireMaxChance(__instance).Value && ((NetworkBehaviour)__instance).IsOwner) { Script.Logger.LogInfo((object)$"{LibraryCalls.DebugStringHead((EnemyAI?)(object)__instance)} OnCustomEnemyCollision: SET GIANT ON FIRE! Random number: {NSSetOnFireChance(__instance).Value}"); ForestGiantAI forestGiantAI = (ForestGiantAI)mainscript2; NetworkSetGiantOnFire(forestGiantAI).InvokeServer(); } } } internal class BlobData { internal EnemyAI? closestEnemy; internal bool playSound; internal List<EnemyAI> localEnemyList = new List<EnemyAI>(); internal Dictionary<EnemyAI, float> hitRegistry = new Dictionary<EnemyAI, float>(); } [HarmonyPatch(typeof(BlobAI))] internal class BlobAIPatch { private static Dictionary<BlobAI, BlobData> slimeList = new Dictionary<BlobAI, BlobData>(); private static bool logBlob = Script.Bools["debugHygrodere"]; private static bool triggerFlag = Script.Bools["debugTriggerFlags"]; private static List<string> blobBlacklist = InitializeGamePatch.blobBlacklistFinal; private static LNetworkEvent BlobEatCorpseEvent(BlobAI instance) { string nWID = "NSSlimeEatEvent" + ((NetworkBehaviour)instance).NetworkObjectId; return Networking.NSEnemyNetworkEvent(nWID); } private static void Event_OnConfigSettingChanged(string entryKey, bool value) { if (entryKey == "debugHygrodere") { logBlob = value; } if (entryKey == "debugTriggerFlags") { triggerFlag = value; } } [HarmonyPatch("Start")] [HarmonyPrefix] private static void StartPatch(BlobAI __instance) { if (!slimeList.ContainsKey(__instance)) { slimeList.Add(__instance, new BlobData()); } if (Script.BoundingConfig.blobAICantOpenDoors.Value) { ((EnemyAI)__instance).openDoorSpeedMultiplier = 0f; } BlobData blobData = slimeList[__instance]; BlobEatCorpseEvent(__instance).OnClientReceived += EventReceived; Script.OnConfigSettingChanged = (Action<string, bool>)Delegate.Combine(Script.OnConfigSettingChanged, new Action<string, bool>(Event_OnConfigSettingChanged)); void EventReceived() { blobData.playSound = true; } } [HarmonyPatch("DoAIInterval")] [HarmonyPrefix] private static bool DoAIIntervalPrefixPatch(BlobAI __instance) { //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_005d: 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_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) BlobData blobData = slimeList[__instance]; if (Script.BoundingConfig.blobPathfind.Value && (((Object)(object)((EnemyAI)__instance).GetClosestPlayer(false, false, false) != (Object)null && (!((EnemyAI)__instance).PlayerIsTargetable(((EnemyAI)__instance).GetClosestPlayer(false, false, false), false, false) || ((Object)(object)blobData.closestEnemy != (Object)null && Vector3.Distance(((Component)blobData.closestEnemy).transform.position, ((Component)__instance).transform.position) < Vector3.Distance(((Component)((EnemyAI)__instance).GetClosestPlayer(false, false, false)).transform.position, ((Component)__instance).transform.position)))) || (Object)(object)((EnemyAI)__instance).GetClosestPlayer(false, false, false) == (Object)null)) { if (((EnemyAI)__instance).moveTowardsDestination) { ((EnemyAI)__instance).agent.SetDestination(((EnemyAI)__instance).destination); } ((EnemyAI)__instance).SyncPositionToClients(); if (__instance.searchForPlayers.inProgress) { ((EnemyAI)__instance).StopSearch(__instance.searchForPlayers, true); } if ((Object)(object)blobData.closestEnemy != (Object)null) { ((EnemyAI)__instance).SetDestinationToPosition(((Component)blobData.closestEnemy).transform.position, true); } return false; } return true; } [HarmonyPatch("Update")] [HarmonyPrefix] private static void BlobUpdatePatch(BlobAI __instance) { BlobData blobData = slimeList[__instance]; Type type = ((object)__instance).GetType(); foreach (KeyValuePair<EnemyAI, float> item in new Dictionary<EnemyAI, float>(blobData.hitRegistry)) { if (item.Value > 1.5f) { blobData.hitRegistry.Remove(item.Key); } else { blobData.hitRegistry[item.Key] += Time.deltaTime; } } if (RoundManagerPatch.RequestUpdate((EnemyAI)(object)__instance)) { List<EnemyAI> list = LibraryCalls.FilterEnemyList(LibraryCalls.GetCompleteList((EnemyAI)(object)__instance, FilterThemselves: true, 1), null, blobBlacklist, (EnemyAI)(object)__instance).ToList(); RoundManagerPatch.ScheduleGlobalListUpdate((EnemyAI)(object)__instance, list); } if (((NetworkBehaviour)__instance).IsOwner) { blobData.localEnemyList = LibraryCalls.GetInsideOrOutsideEnemyList(NaturalSelectionLib.globalEnemyLists[type], (EnemyAI)(object)__instance).ToList(); blobData.closestEnemy = LibraryCalls.FindClosestEnemy(blobData.localEnemyList, blobData.closestEnemy, (EnemyAI)(object)__instance, Script.BoundingConfig.blobPathfindToCorpses.Value); } if (blobData.playSound) { Script.Logger.LogMessage((object)("Playing sound. NetworkObjectID: " + ((NetworkBehaviour)__instance).NetworkObjectId)); ((EnemyAI)__instance).creatureVoice.PlayOneShot(__instance.killPlayerSFX); blobData.playSound = false; } } public static void OnCustomEnemyCollision(BlobAI __instance, EnemyAI mainscript2) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) BlobData blobData = slimeList[__instance]; if (blobData.hitRegistry.ContainsKey(mainscript2) || blobBlacklist.Contains(mainscript2.enemyType.enemyName)) { return; } if (mainscript2.isEnemyDead && !IsEnemyImmortal.EnemyIsImmortal(mainscript2) && Vector3.Distance(((Component)__instance).transform.position, ((Component)mainscript2).transform.position) <= 2.8f && Script.BoundingConfig.blobConsumesCorpses.Value) { if (((NetworkBehaviour)__instance).IsOwner && mainscript2.thisNetworkObject.IsSpawned) { BlobEatCorpseEvent(__instance).InvokeClients(); Script.Logger.LogMessage((object)"Send event"); mainscript2.thisNetworkObject.Despawn(true); } } else { if (mainscript2.isEnemyDead || mainscript2 is NutcrackerEnemyAI || mainscript2 is CaveDwellerAI) { return; } blobData.hitRegistry.Add(mainscript2, 0f); if (mainscript2 is FlowermanAI) { FlowermanAI val = (FlowermanAI)(object)((mainscript2 is FlowermanAI) ? mainscript2 : null); if ((Object)(object)val != (Object)null) { float angerMeter = val.angerMeter; bool isInAngerMode = val.isInAngerMode; ((EnemyAI)val).HitEnemy(1, (PlayerControllerB)null, true, -1); if (mainscript2.enemyHP <= 0) { mainscript2.KillEnemyOnOwnerClient(false); } ((EnemyAI)val).targetPlayer = null; ((EnemyAI)val).movingTowardsTargetPlayer = false; val.isInAngerMode = false; val.angerMeter = angerMeter; val.isInAngerMode = isInAngerMode; return; } } if (mainscript2 is HoarderBugAI) { HoarderBugAI val2 = (HoarderBugAI)(object)((mainscript2 is HoarderBugAI) ? mainscript2 : null); if ((Object)(object)val2 != (Object)null) { HoarderBugPatch.CustomOnHit(1, (EnemyAI)(object)__instance, playHitSFX: false, val2); if (mainscript2.enemyHP <= 0) { mainscript2.KillEnemyOnOwnerClient(false); } } } else { mainscript2.HitEnemy(1, (PlayerControllerB)null, true, -1); if (mainscript2.enemyHP <= 0) { mainscript2.KillEnemyOnOwnerClient(false); } } } } } internal class OnCollideWithUniversal { private class EnemyCollisionData { internal bool subscribed; } private static bool enableSpider = Script.BoundingConfig.enableSpider.Value; private static bool enableSlime = Script.BoundingConfig.enableSlime.Value; private static bool enableBees = Script.BoundingConfig.enableRedBees.Value; private static bool logUnspecified = Script.Bools["debugUnspecified"]; private static bool triggerFlag = Script.Bools["debugTriggerFlags"]; private static bool debugSpam = Script.Bools["spammyLogs"]; private static void Event_OnConfigSettingChanged() { logUnspecified = Script.Bools["debugUnspecified"]; debugSpam = Script.Bools["spammyLogs"]; triggerFlag = Script.Bools["debugTriggerFlags"]; } public static void Collide(string text, EnemyAI? mainscript, EnemyAI? mainscript2) { //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Expected O, but got Unknown //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Expected O, but got Unknown //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Expected O, but got Unknown if (logUnspecified && debugSpam && triggerFlag) { Script.Logger.LogDebug((object)(LibraryCalls.DebugStringHead(mainscript) + " hit collider of " + LibraryCalls.DebugStringHead(mainscript2) + " Tag: " + text)); } if ((Object)(object)mainscript != (Object)null) { _ = text == "Player"; } if ((Object)(object)mainscript != (Object)null && (Object)(object)mainscript2 != (Object)null) { if (mainscript is SandSpiderAI && !(mainscript2 is SandSpiderAI) && (Object)(object)mainscript2 != (Object)null && enableSpider) { SandSpiderAIPatch.OnCustomEnemyCollision((SandSpiderAI)mainscript, mainscript2); } if (mainscript is BlobAI && !(mainscript2 is BlobAI) && (Object)(object)mainscript2 != (Object)null && enableSlime) { BlobAIPatch.OnCustomEnemyCollision((BlobAI)mainscript, mainscript2); } if (mainscript is RedLocustBees && !(mainscript2 is RedLocustBees) && (Object)(object)mainscript2 != (Object)null && enableBees) { BeeAIPatch.OnCustomEnemyCollision((RedLocustBees)mainscript, mainscript2); } } } } [HarmonyPatch(typeof(EnemyAICollisionDetect))] public class AICollisionDetectPatch { [HarmonyPatch("OnTriggerStay")] [HarmonyPrefix] private static bool OnTriggerStayPrefix(Collider other, EnemyAICollisionDetect __instance) { if ((Object)(object)other == (Object)null) { Script.Logger.LogError((object)(LibraryCalls.DebugStringHead(__instance.mainScript) + " Collider is null! Using original function...")); return true; } EnemyAICollisionDetect component = ((Component)other).gameObject.GetComponent<EnemyAICollisionDetect>(); if ((Object)(object)__instance != (Object)null) { EnemyAI val = null; if (((Component)other).CompareTag("Player") && !__instance.mainScript.isEnemyDead) { OnCollideWithUniversal.Collide("Player", null, null); return true; } if ((Object)(object)component != (Object)null) { val = ((!((Object)(object)component?.mainScript == (Object)null)) ? ((Component)other).gameObject.GetComponentInParent<EnemyAI>() : component?.mainScript); if (((Component)other).CompareTag("Enemy") && (Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)__instance.mainScript && !IsEnemyImmortal.EnemyIsImmortal(val) && !__instance.mainScript.isEnemyDead) { OnCollideWithUniversal.Collide("Enemy", __instance.mainScript, val); return true; } } } return true; } } public class IsEnemyImmortal { public static bool EnemyIsImmortal(EnemyAI instance) { if (instance is NutcrackerEnemyAI && instance.currentBehaviourStateIndex == 0) { return true; } if (instance is JesterAI) { return true; } if (instance is BlobAI) { return true; } if (instance is SpringManAI) { return true; } if (instance is SandWormAI) { return true; } if (instance is ButlerBeesEnemyAI) { return true; } return false; } } internal class EnemyData { internal float originalAgentRadius; internal Dictionary<Type, int> targetedByEnemies = new Dictionary<Type, int>(); } [HarmonyPatch(typeof(EnemyAI))] internal class EnemyAIPatch { private static bool debugUnspecified = Script.Bools["debugUnspecified"]; private static bool debugTriggerFlags = Script.Bools["debugTriggerFlags"]; private static Dictionary<EnemyAI, EnemyData> enemyData = new Dictionary<EnemyAI, EnemyData>(); private static void Event_OnConfigSettingChanged(string entryKey, bool value) { if (entryKey == "debugUnspecified") { debugUnspecified = value; } if (entryKey == "debugTriggerFlags") { debugTriggerFlags = value; } } [HarmonyPatch("Start")] [HarmonyPostfix] private static void StartPostfix(EnemyAI __instance) { if (!EnemyAIPatch.enemyData.ContainsKey(__instance)) { EnemyAIPatch.enemyData.Add(__instance, new EnemyData()); } EnemyData enemyData = EnemyAIPatch.enemyData[__instance]; enemyData.originalAgentRadius = __instance.agent.radius; __instance.agent.radius = __instance.agent.radius * Script.BoundingConfig.agentRadiusModifier.Value; if (debugUnspecified && debugTriggerFlags) { Script.Logger.LogMessage((object)$"Modified agent radius. Original: {EnemyAIPatch.enemyData[__instance].originalAgentRadius}, Modified: {__instance.agent.radius}"); } Script.OnConfigSettingChanged = (Action<string, bool>)Delegate.Combine(Script.OnConfigSettingChanged, new Action<string, bool>(Event_OnConfigSettingChanged)); } public static int ReactToHit(int force = 0, EnemyAI? enemyAI = null, PlayerControllerB? player = null) { if (force > 0) { return 1; } if (force > 1) { return 2; } return 0; } [HarmonyPatch("HitEnemy")] [HarmonyPostfix] public static void HitEnemyPatch(EnemyAI __instance, int force, PlayerControllerB playerWhoHit, bool playHitSFX, int hitID) { string text = "unknown"; if ((Object)(object)playerWhoHit != (Object)null) { text = $"{playerWhoHit.playerUsername}(SteamID: {playerWhoHit.playerSteamId}, playerClientID: {playerWhoHit.playerClientId})"; } if (debugTriggerFlags) { Script.Logger.LogInfo((object)$"{LibraryCalls.DebugStringHead(__instance)} registered hit by {text} with force of {force}. playHitSFX:{playHitSFX}, hitID:{hitID}."); } } } public class ReversePatchAI { public static Action<EnemyAI> originalUpdate; static ReversePatchAI() { MethodInfo meth = AccessTools.Method(typeof(EnemyAI), "Update", (Type[])null, (Type[])null); DynamicMethod dynamicMethod = new DynamicMethod("Base.Update", null, new Type[1] { typeof(EnemyAI) }, typeof(EnemyAI)); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Call, meth); iLGenerator.Emit(OpCodes.Ret); originalUpdate = (Action<EnemyAI>)dynamicMethod.CreateDelegate(typeof(Action<EnemyAI>)); } } internal class GiantData { internal int extinguished; internal bool setFireOnKill; } [HarmonyPatch(typeof(ForestGiantAI))] internal class ForestGiantPatch { private static Dictionary<ForestGiantAI, GiantData> giantDictionary = new Dictionary<ForestGiantAI, GiantData>(); private static bool logGiant = Script.Bools["debugGiants"]; private static bool debugSpam = Script.Bools["spammyLogs"]; private static LNetworkEvent NetworkSetGiantOnFire(ForestGiantAI forestGiantAI) { string nWID = "NSSetGiantOnFire" + ((NetworkBehaviour)forestGiantAI).NetworkObjectId; return Networking.NSEnemyNetworkEvent(nWID); } internal static LNetworkEvent NetworkExtinguish(ForestGiantAI forestGiantAI) { string nWID = "NSExtinguish" + ((NetworkBehaviour)forestGiantAI).NetworkObjectId; return Networking.NSEnemyNetworkEvent(nWID); } private static LNetworkVariable<float> NetworkOwnerPostfixResult(ForestGiantAI forestGiantAI) { string nWID = "NSOwnerrealtimeSinceStartup" + ((NetworkBehaviour)forestGiantAI).NetworkObjectId; return Networking.NSEnemyNetworkVariableFloat(nWID); } private static void Event_OnConfigSettingChanged(string entryKey, bool value) { if (entryKey == "debugGiants") { logGiant = value; } if (entryKey == "spammyLogs") { debugSpam = value; } } [HarmonyPatch("Start")] [HarmonyPostfix] private static void startPostfix(ForestGiantAI __instance) { ForestGiantAI __instance2 = __instance; if (!giantDictionary.ContainsKey(__instance2)) { giantDictionary.Add(__instance2, new GiantData()); } GiantData data = giantDictionary[__instance2]; NetworkSetGiantOnFire(__instance2).OnServerReceived += UpdateSetGiantOnFireServer; NetworkExtinguish(__instance2).OnClientReceived += ExtuinguishGiant; Script.OnConfigSettingChanged = (Action<string, bool>)Delegate.Combine(Script.OnConfigSettingChanged, new Action<string, bool>(Event_OnConfigSettingChanged)); void ExtuinguishGiant() { ((EnemyAI)__instance2).SwitchToBehaviourState(0); __instance2.burningParticlesContainer.SetActive(false); __instance2.giantBurningAudio.Stop(); ((EnemyAI)__instance2).creatureAnimator.SetBool("burning", false); data.extinguished = 1; } void UpdateSetGiantOnFireServer(ulong client) { if (((NetworkBehaviour)__instance2).IsOwner) { __instance2.timeAtStartOfBurning = Time.realtimeSinceStartup; ((EnemyAI)__instance2).SwitchToBehaviourState(2); Script.Logger.LogInfo((object)"Received UpdateSetGiantOnFire event"); } } } [HarmonyPatch("KillEnemy")] [HarmonyPostfix] private static void KillEnemyPatchPostfix(ForestGiantAI __instance) { GiantData giantData = giantDictionary[__instance]; if (giantData.extinguished != 1 && ((EnemyAI)__instance).currentBehaviourStateIndex == 2) { __instance.burningParticlesContainer.SetActive(true); } if (logGiant) { Script.Logger.LogInfo((object)LibraryCalls.DebugStringHead((EnemyAI?)(object)__instance)); } } [HarmonyPatch("Update")] [HarmonyPrefix] private static bool UpdatePrefix(ForestGiantAI __instance) { GiantData giantData = giantDictionary[__instance]; if (((EnemyAI)__instance).currentBehaviourStateIndex == 2 && Time.realtimeSinceStartup - __instance.timeAtStartOfBurning > 9.5f && ((EnemyAI)__instance).enemyHP > 20 && giantData.extinguished == 0 && !((EnemyAI)__instance).isEnemyDead && ((NetworkBehaviour)__instance).IsOwner) { int num = Random.Range(0, 100); if (num <= Script.BoundingConfig.giantExtinguishChance.Value) { NetworkExtinguish(__instance).InvokeClients(); Script.Logger.LogInfo((object)$"{LibraryCalls.DebugStringHead((EnemyAI?)(object)__instance)} successfully extinguished itself. Skipping Update. Rolled {num}"); } else { Script.Logger.LogInfo((object)$"{LibraryCalls.DebugStringHead((EnemyAI?)(object)__instance)} failed to extinguish itself. rolled {num}"); giantData.extinguished = 2; } } if (giantData.extinguished == 1) { ((EnemyAI)__instance).enemyHP = ((EnemyAI)__instance).enemyHP - 20; giantData.extinguished = 2; return false; } return true; } [HarmonyPatch("Update")] [HarmonyPostfix] private static void UpdatePostfix(ForestGiantAI __instance) { GiantData giantData = giantDictionary[__instance]; if (((NetworkBehaviour)__instance).IsOwner) { NetworkOwnerPostfixResult(__instance).Value = Time.realtimeSinceStartup - __instance.timeAtStartOfBurning; } if (((EnemyAI)__instance).isEnemyDead && ((EnemyAI)__instance).currentBehaviourStateIndex == 2 && NetworkOwnerPostfixResult(__instance).Value < 20f) { if (((NetworkBehaviour)__instance).IsOwner) { NetworkOwnerPostfixResult(__instance).Value = Time.realtimeSinceStartup - __instance.timeAtStartOfBurning; } if (!__instance.giantBurningAudio.isPlaying) { __instance.giantBurningAudio.Play(); } __instance.giantBurningAudio.volume = Mathf.Min(__instance.giantBurningAudio.volume + Time.deltaTime * 0.5f, 1f); } else if (((EnemyAI)__instance).isEnemyDead && NetworkOwnerPostfixResult(__instance).Value > 26f && __instance.burningParticlesContainer.activeSelf) { __instance.burningParticlesContainer.SetActive(false); } } } internal class HoarderBugValues { internal EnemyAI? targetEnemy; internal EnemyAI? closestEnemy; internal bool alertedByEnemy; internal List<EnemyAI> enemies = new List<EnemyAI>(); internal List<EnemyAI> enemiesInLOS = new List<EnemyAI>(); internal bool limitSpeed; internal float limitedSpeed; } [HarmonyPatch(typeof(HoarderBugAI))] internal class HoarderBugPatch { private static Dictionary<HoarderBugAI, HoarderBugValues> hoarderBugList = new Dictionary<HoarderBugAI, HoarderBugValues>(); private static bool triggerFlag = Script.Bools["debugTriggerFlags"]; private static void Event_OnConfigSettingChanged(string entryKey, bool value) { if (entryKey == "debugTriggerFlags") { triggerFlag = value; } } public static void CustomOnHit(int force, EnemyAI enemyWhoHit, bool playHitSFX, HoarderBugAI __instance) { ((EnemyAI)__instance).enemyHP = ((EnemyAI)__instance).enemyHP - force; if (triggerFlag) { Script.Logger.LogDebug((object)"Hoarderbug CustomHit Triggered"); } if (playHitSFX) { WalkieTalkie.TransmitOneShotAudio(((EnemyAI)__instance).creatureVoice, ((EnemyAI)__instance).enemyType.hitBodySFX, 1f); ((EnemyAI)__instance).creatureVoice.PlayOneShot(((EnemyAI)__instance).enemyType.hitBodySFX); } if ((Object)(object)((EnemyAI)__instance).creatureVoice != (Object)null) { ((EnemyAI)__instance).creatureVoice.PlayOneShot(((EnemyAI)__instance).enemyType.hitEnemyVoiceSFX); } RoundManager.PlayRandomClip(((EnemyAI)__instance).creatureVoice, __instance.angryScreechSFX, true, 1f, 0, 1000); ((EnemyAI)__instance).SwitchToBehaviourState(1); if (((EnemyAI)__instance).enemyHP <= 0) { ((EnemyAI)__instance).KillEnemyOnOwnerClient(false); } } [HarmonyPatch("Start")] [HarmonyPrefix] private static void StartPatch(HoarderBugAI __instance) { if (!hoarderBugList.ContainsKey(__instance)) { hoarderBugList.Add(__instance, new HoarderBugValues()); } Script.OnConfigSettingChanged = (Action<string, bool>)Delegate.Combine(Script.OnConfigSettingChanged, new Action<string, bool>(Event_OnConfigSettingChanged)); } [HarmonyPatch("Update")] [HarmonyPostfix] private static void UpdatePostfix(HoarderBugAI __instance) { HoarderBugValues hoarderBugValues = hoarderBugList[__instance]; if (hoarderBugValues.limitSpeed) { ((EnemyAI)__instance).agent.speed = hoarderBugValues.limitedSpeed; } } } internal class NutcrackerData { internal EnemyAI? closestEnemy; internal EnemyAI? targetEnemy; internal bool SeeMovingEnemy; internal Vector3 lastSeenEnemyPosition = Vector3.zero; internal float TimeSinceSeeingMonster; internal float TimeSinceHittingMonster; } [HarmonyPatch(typeof(NutcrackerEnemyAI))] internal class NutcrackerAIPatch { private static List<EnemyAI> enemyList = new List<EnemyAI>(); private static Dictionary<NutcrackerEnemyAI, NutcrackerData> NutcrackerData = new Dictionary<NutcrackerEnemyAI, NutcrackerData>(); private static bool debugSpam = Script.Bools["spammyLogs"]; private static bool debugNutcrackers = Script.Bools["debugNutcrackers"]; private static bool debugTriggerFlags = Script.Bools["debugTriggerFlags"]; public static bool CheckLOSForMonsters(Vector3 monsterPosition, NutcrackerEnemyAI __instance, float width = 45f, int range = 60, int proximityAwareness = 60) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_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_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_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_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0063: 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) if (Vector3.Distance(monsterPosition, ((EnemyAI)__instance).eye.position) < (float)range && !Physics.Linecast(((EnemyAI)__instance).eye.position, monsterPosition, StartOfRound.Instance.collidersAndRoomMaskAndDefault)) { Vector3 val = monsterPosition - ((EnemyAI)__instance).eye.position; if (Vector3.Angle(((EnemyAI)__instance).eye.forward, val) < width || (proximityAwareness != -1 && Vector3.Distance(((EnemyAI)__instance).eye.position, monsterPosition) < (float)proximityAwareness)) { return true; } } return false; } private static void Event_OnConfigSettingChanged(string entryKey, bool value) { if (entryKey == "debugNutcrackers") { debugNutcrackers = value; } if (entryKey == "spammyLogs") { debugSpam = value; } if (entryKey == "debugTriggerFlags") { debugTriggerFlags = value; } } [HarmonyPatch("Start")] [HarmonyPostfix] private static void UpdatePatch(NutcrackerEnemyAI __instance) { if (!NutcrackerData.ContainsKey(__instance)) { NutcrackerData.Add(__instance, new NutcrackerData()); } Script.OnConfigSettingChanged = (Action<string, bool>)Delegate.Combine(Script.OnConfigSettingChanged, new Action<string, bool>(Event_OnConfigSettingChanged)); } [HarmonyPatch("Update")] [HarmonyPostfix] private static void NutcrackerUpdatePostfix(NutcrackerEnemyAI __instance) { //IL_0061: 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_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_00af: 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_0115: Unknown result type (might be due to invalid IL or missing references) //IL_019d: 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_014a: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Unknown result type (might be due to invalid IL or missing references) //IL_02c5: Unknown result type (might be due to invalid IL or missing references) //IL_02aa: Unknown result type (might be due to invalid IL or missing references) //IL_02af: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Unknown result type (might be due to invalid IL or missing references) //IL_0247: Unknown result type (might be due to invalid IL or missing references) //IL_027a: Unknown result type (might be due to invalid IL or missing references) NutcrackerData nutcrackerData = NutcrackerData[__instance]; enemyList = LibraryCalls.GetInsideOrOutsideEnemyList(LibraryCalls.GetCompleteList((EnemyAI)(object)__instance), (EnemyAI)(object)__instance); nutcrackerData.closestEnemy = LibraryCalls.FindClosestEnemy(enemyList, nutcrackerData.closestEnemy, (EnemyAI)(object)__instance); Vector3 velocity; if (((EnemyAI)__instance).currentBehaviourStateIndex == 1 && (Object)(object)nutcrackerData.closestEnemy != (Object)null) { if (__instance.isInspecting && CheckLOSForMonsters(((Component)nutcrackerData.closestEnemy).transform.position, __instance, 70f, 60, 1)) { velocity = nutcrackerData.closestEnemy.agent.velocity; if (((Vector3)(ref velocity)).magnitude > 0f) { __instance.isInspecting = false; nutcrackerData.SeeMovingEnemy = true; __instance.lastSeenPlayerPos = ((Component)nutcrackerD