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 CowardlyGreydwarfs v1.0.0
CowardlyGreydwarfs.dll
Decompiled a day agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("CowardlyGreydwarfs")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("CowardlyGreydwarfs")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("efb8d134-6ac1-4d17-ae04-edff6144bb93")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.0.0")] namespace CowardlyGreydwarfs; [BepInPlugin("com.robit.cowardlygreydwarfs", "Cowardly Greydwarfs", "1.0.0")] public class CowardlyGreydwarfsPlugin : BaseUnityPlugin { private static class DamagePatch { internal static void Prefix(Character __instance, ref float __state) { if ((Object)(object)__instance == (Object)null) { __state = 0f; } else { __state = __instance.GetHealth(); } } internal static void Postfix(Character __instance, float __state) { if ((Object)(object)__instance == (Object)null || !IsAffectedCreature(__instance)) { return; } float health = __instance.GetHealth(); if (health <= 0f) { return; } float num = __state - health; if (num <= 0f) { return; } float maxHealth = __instance.GetMaxHealth(); if (maxHealth <= 0f) { return; } float num2 = num / maxHealth; float value = BigHitThreshold.Value; if (value <= 0f || num2 < value) { return; } float value2 = PanicDuration.Value; if (!(value2 <= 0f)) { int instanceID = ((Object)__instance).GetInstanceID(); float num3 = Time.time + value2; if (PanicUntil.TryGetValue(instanceID, out var value3)) { PanicUntil[instanceID] = Mathf.Max(value3, num3); } else { PanicUntil.Add(instanceID, num3); } if (DebugLogging.Value) { string prefabName = GetPrefabName(((Component)__instance).gameObject); Log.LogInfo((object)(prefabName + " panicked! Hit removed " + (num2 * 100f).ToString("0.0") + "% of max HP. Fleeing for " + value2.ToString("0.0") + " seconds.")); } } } } private static class AIPatch { internal struct FleeState { internal bool Applied; internal float OldFleeIfLowHealth; internal float OldFleeTimeSinceHurt; } internal static void Prefix(MonsterAI __instance, ref FleeState __state) { __state = new FleeState { Applied = false }; if ((Object)(object)__instance == (Object)null) { return; } Character component = ((Component)__instance).GetComponent<Character>(); if ((Object)(object)component == (Object)null || !IsAffectedCreature(component)) { return; } float health = component.GetHealth(); float maxHealth = component.GetMaxHealth(); if (health <= 0f || maxHealth <= 0f) { return; } int instanceID = ((Object)component).GetInstanceID(); bool flag = false; if (PanicUntil.TryGetValue(instanceID, out var value)) { if (Time.time < value) { flag = true; } else { PanicUntil.Remove(instanceID); } } float num = health / maxHealth; float value2 = LowHealthThreshold.Value; bool flag2 = value2 > 0f && num <= value2; if (flag || flag2) { __state.OldFleeIfLowHealth = (float)FleeIfLowHealthField.GetValue(__instance); __state.OldFleeTimeSinceHurt = (float)FleeTimeSinceHurtField.GetValue(__instance); __state.Applied = true; FleeIfLowHealthField.SetValue(__instance, 1.01f); FleeTimeSinceHurtField.SetValue(__instance, float.MaxValue); } } internal static void Postfix(MonsterAI __instance, FleeState __state) { if (!((Object)(object)__instance == (Object)null) && __state.Applied) { FleeIfLowHealthField.SetValue(__instance, __state.OldFleeIfLowHealth); FleeTimeSinceHurtField.SetValue(__instance, __state.OldFleeTimeSinceHurt); } } } private Harmony _harmony; internal static ManualLogSource Log; internal static ConfigEntry<bool> EnableGreylings; internal static ConfigEntry<bool> EnableGreydwarfs; internal static ConfigEntry<bool> EnableShamans; internal static ConfigEntry<bool> EnableBrutes; internal static ConfigEntry<float> BigHitThreshold; internal static ConfigEntry<float> LowHealthThreshold; internal static ConfigEntry<float> PanicDuration; internal static ConfigEntry<bool> DebugLogging; internal static FieldInfo FleeIfLowHealthField; internal static FieldInfo FleeTimeSinceHurtField; internal static readonly Dictionary<int, float> PanicUntil = new Dictionary<int, float>(); private static readonly List<int> ExpiredPanicEntries = new List<int>(); private float _nextCleanupTime; private void Awake() { //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Expected O, but got Unknown //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Expected O, but got Unknown //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Expected O, but got Unknown //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Expected O, but got Unknown //IL_0259: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Unknown result type (might be due to invalid IL or missing references) //IL_027b: Expected O, but got Unknown //IL_027b: Expected O, but got Unknown //IL_0293: Unknown result type (might be due to invalid IL or missing references) //IL_02a8: Unknown result type (might be due to invalid IL or missing references) //IL_02b5: Expected O, but got Unknown //IL_02b5: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; EnableGreylings = ((BaseUnityPlugin)this).Config.Bind<bool>("Creatures", "Enable Greylings", true, "Allow Greylings to flee."); EnableGreydwarfs = ((BaseUnityPlugin)this).Config.Bind<bool>("Creatures", "Enable Greydwarfs", true, "Allow normal Greydwarfs to flee."); EnableShamans = ((BaseUnityPlugin)this).Config.Bind<bool>("Creatures", "Enable Shamans", false, "Allow Greydwarf Shamans to flee."); EnableBrutes = ((BaseUnityPlugin)this).Config.Bind<bool>("Creatures", "Enable Brutes", false, "Allow Greydwarf Brutes to flee."); BigHitThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("Fleeing", "Big Hit Threshold", 0.5f, new ConfigDescription("Fraction of the creature's maximum health that must be lost from ONE hit to cause panic. 0.50 = 50%. Set to 0 to disable.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); LowHealthThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("Fleeing", "Low Health Threshold", 0.2f, new ConfigDescription("Creature will flee while its health is at or below this fraction. 0.20 = 20%. Set to 0 to disable.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); PanicDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Fleeing", "Panic Duration", 15f, new ConfigDescription("How many seconds a creature flees after receiving a big hit.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 120f), Array.Empty<object>())); DebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "Debug Logging", false, "Log panic triggers to the BepInEx console."); FleeIfLowHealthField = AccessTools.Field(typeof(MonsterAI), "m_fleeIfLowHealth"); FleeTimeSinceHurtField = AccessTools.Field(typeof(MonsterAI), "m_fleeTimeSinceHurt"); if (FleeIfLowHealthField == null) { ((BaseUnityPlugin)this).Logger.LogError((object)"Could not find MonsterAI.m_fleeIfLowHealth. Cowardly Greydwarfs cannot start."); return; } if (FleeTimeSinceHurtField == null) { ((BaseUnityPlugin)this).Logger.LogError((object)"Could not find MonsterAI.m_fleeTimeSinceHurt. Cowardly Greydwarfs cannot start."); return; } MethodInfo methodInfo = AccessTools.Method(typeof(Character), "RPC_Damage", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(MonsterAI), "UpdateAI", (Type[])null, (Type[])null); if (methodInfo == null) { ((BaseUnityPlugin)this).Logger.LogError((object)"Could not find Character.RPC_Damage. Cowardly Greydwarfs cannot start."); return; } if (methodInfo2 == null) { ((BaseUnityPlugin)this).Logger.LogError((object)"Could not find MonsterAI.UpdateAI. Cowardly Greydwarfs cannot start."); return; } _harmony = new Harmony("com.robit.cowardlygreydwarfs"); _harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(DamagePatch), "Prefix", (Type[])null), new HarmonyMethod(typeof(DamagePatch), "Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(AIPatch), "Prefix", (Type[])null), new HarmonyMethod(typeof(AIPatch), "Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Cowardly Greydwarfs v1.0.0 loaded."); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } private void Update() { if (Time.time < _nextCleanupTime) { return; } _nextCleanupTime = Time.time + 10f; ExpiredPanicEntries.Clear(); foreach (KeyValuePair<int, float> item in PanicUntil) { if (Time.time >= item.Value) { ExpiredPanicEntries.Add(item.Key); } } foreach (int expiredPanicEntry in ExpiredPanicEntries) { PanicUntil.Remove(expiredPanicEntry); } } internal static bool IsAffectedCreature(Character character) { if ((Object)(object)character == (Object)null) { return false; } return GetPrefabName(((Component)character).gameObject) switch { "Greyling" => EnableGreylings.Value, "Greydwarf" => EnableGreydwarfs.Value, "Greydwarf_Shaman" => EnableShamans.Value, "Greydwarf_Elite" => EnableBrutes.Value, _ => false, }; } internal static string GetPrefabName(GameObject gameObject) { if ((Object)(object)gameObject == (Object)null) { return string.Empty; } string text = ((Object)gameObject).name; int num = text.IndexOf("(Clone)", StringComparison.Ordinal); if (num >= 0) { text = text.Substring(0, num); } return text.Trim(); } }