Some mods target the Mono version of the game, which is available by opting into the Steam beta branch "alternate"
Decompiled source of madman v1.0.0
Mods/madman.dll
Decompiled a day agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using HarmonyLib; using Il2CppInterop.Runtime; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppScheduleOne.Combat; using Il2CppScheduleOne.Effects; using Il2CppScheduleOne.Equipping; using Il2CppScheduleOne.FX; using Il2CppScheduleOne.ItemFramework; using Il2CppScheduleOne.NPCs; using Il2CppScheduleOne.PlayerScripts; using Il2CppScheduleOne.PlayerScripts.Health; using MadmanMod; using MelonLoader; using MelonLoader.Preferences; using Microsoft.CodeAnalysis; using S1API.Console; using S1API.Lifecycle; using S1APITemplate; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: MelonInfo(typeof(Core), "madman", "1.0.0", "Timber Van Thorn", null)] [assembly: MelonGame("TVGS", "Schedule I")] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("madman")] [assembly: AssemblyConfiguration("CrossCompat")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+ff93ce131518eef04a8566b62f1d3c0b8347bdfc")] [assembly: AssemblyProduct("madman")] [assembly: AssemblyTitle("madman")] [assembly: NeutralResourcesLanguage("en-US")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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] [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] [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 S1APITemplate { public sealed class Core : MelonMod { private static MelonPreferences_Category? _preferencesCategory; private static MelonPreferences_Entry<bool>? _debugLogsEntry; public static Core? Instance { get; private set; } public static bool DebugLogsEnabled => _debugLogsEntry?.Value ?? false; public override void OnInitializeMelon() { Instance = this; InitializePreferences(); GameLifecycle.OnPreLoad += OnPreLoad; GameLifecycle.OnLoadComplete += OnLoadComplete; ((MelonBase)this).LoggerInstance.Msg("madman initialized."); } public override void OnUpdate() { CheatCode.Tick(); PlayerAttack.Tick(); PlayerEffects.Tick(); InfiniteAmmo.Tick(); } public override void OnApplicationQuit() { GameLifecycle.OnPreLoad -= OnPreLoad; GameLifecycle.OnLoadComplete -= OnLoadComplete; Instance = null; } private void OnPreLoad() { ((MelonBase)this).LoggerInstance.Msg("Game is preparing to load. Register stable S1API content needed by save data here."); } private void OnLoadComplete() { ((MelonBase)this).LoggerInstance.Msg("Save loading is complete. Initialize systems that depend on the loaded world here."); } public override void OnSceneWasLoaded(int buildIndex, string sceneName) { MelonLogger.Msg("[Madman] scene loaded: " + sceneName); if (sceneName == "Menu" || sceneName == "Main") { MadmanState.Reset(); } } private static void InitializePreferences() { _preferencesCategory = MelonPreferences.CreateCategory("madman"); _debugLogsEntry = _preferencesCategory.CreateEntry<bool>("DebugLogs", false, "Enable Debug Logs", "Show detailed debug messages in the MelonLoader console.", false, false, (ValueValidator)null, (string)null); _preferencesCategory.SaveToFile(false); } } } namespace S1APITemplate.Utils { public static class Constants { public static class Defaults { public const bool DebugLogsEnabled = false; } public static class Constraints { public const float MinConstraint = 0f; public const float MaxConstraint = 100f; } public static class Game { public const string Studio = "TVGS"; public const string Name = "Schedule I"; } public const string ModName = "madman"; public const string ModVersion = "1.0.0"; public const string ModAuthor = "Timber Van Thorn"; public const string ModDescription = "Be careful, cops can still arrest a god for the many horrible things he done-did. uwu"; public const string PreferencesCategory = "madman"; } } namespace MadmanMod { public static class CheatCode { private static int taps; private static float lastTap; public static void Tick() { if (Input.GetKeyDown((KeyCode)289)) { float unscaledTime = Time.unscaledTime; taps = ((!(unscaledTime - lastTap < 1.2f)) ? 1 : (taps + 1)); lastTap = unscaledTime; if (taps >= 3) { taps = 0; MadmanState.Toggle(); } } } } public static class ExplosionFx { private const bool UseGameExplosion = true; private const bool KeepOwnBlast = false; private const float NpcCooldown = 0.75f; private const float GlobalCooldown = 0.25f; private const bool FollowRagdoll = true; private const float MinFollowSeconds = 0.25f; private const float MaxFollowSeconds = 1f; private const float SettleDistance = 0.1f; private const float DamageRadius = 6f; private const float MaxDamage = 200f; private const float PushRadius = 8f; private const float MaxPush = 15f; private static CombatManager combat; private static object dataObj; private static float lastAny; private static readonly Dictionary<int, float> lastNpc = new Dictionary<int, float>(); private const float FollowSeconds = 0.2f; public static void Boom(Vector3 pos, NPCHealth primary, bool follow = false) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) float time = Time.time; int instanceID = ((Object)primary).GetInstanceID(); if (!(time - lastAny < 0.25f) && (!lastNpc.TryGetValue(instanceID, out var value) || !(time - value < 0.75f))) { lastAny = time; lastNpc[instanceID] = time; SkinnedMeshRenderer body = FindBody(primary); Vector3 start = BodyPoint(body, primary, pos); bool flag = false; MelonCoroutines.Start(BoomAfter(primary, body, start, instanceID, 0.2f)); } } private static IEnumerator BoomAfter(NPCHealth h, SkinnedMeshRenderer body, Vector3 start, int id, float seconds) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) Vector3 last = start; float t = 0.1f; while (t < seconds) { yield return null; t += Time.deltaTime; if ((Object)(object)h == (Object)null) { break; } last = BodyPoint(body, h, last); } Explode(last, id); } private static SkinnedMeshRenderer FindBody(NPCHealth h) { try { NPC componentInParent = ((Component)h).GetComponentInParent<NPC>(); Transform val = (((Object)(object)componentInParent != (Object)null) ? ((Component)componentInParent).transform : ((Component)h).transform); return ((Component)val).GetComponentInChildren<SkinnedMeshRenderer>(); } catch { return null; } } private static Vector3 BodyPoint(SkinnedMeshRenderer body, NPCHealth h, Vector3 fallback) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)body != (Object)null) { Bounds bounds = ((Renderer)body).bounds; return ((Bounds)(ref bounds)).center; } } catch { } return ((Object)(object)h != (Object)null) ? ((Component)h).transform.position : fallback; } private static void Explode(Vector3 pos, int id) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //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_0024: Unknown result type (might be due to invalid IL or missing references) if (!GameExplosion(pos + Vector3.up * 0.5f)) { OwnBlast(pos, id); } } private static IEnumerator BoomWhenSettled(NPCHealth h, Vector3 hitPos) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) int id = ((Object)h).GetInstanceID(); Vector3 last = hitPos; float elapsed = 0f; float sample = 0f; while (elapsed < 1f) { yield return null; elapsed += Time.deltaTime; sample += Time.deltaTime; if ((Object)(object)h == (Object)null) { break; } if (!(sample < 0.15f)) { sample = 0f; Vector3 now = BodyPos(h, last); bool settled = Vector3.Distance(now, last) < 0.1f; last = now; if (elapsed >= 0.25f && settled) { break; } } } Explode(last, id); } private static Vector3 BodyPos(NPCHealth h, Vector3 fallback) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0034: 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_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) try { NPC componentInParent = ((Component)h).GetComponentInParent<NPC>(); Transform val = (((Object)(object)componentInParent != (Object)null) ? ((Component)componentInParent).transform : ((Component)h).transform); SkinnedMeshRenderer componentInChildren = ((Component)val).GetComponentInChildren<SkinnedMeshRenderer>(); if ((Object)(object)componentInChildren != (Object)null) { Bounds bounds = ((Renderer)componentInChildren).bounds; return ((Bounds)(ref bounds)).center; } } catch { } return ((Object)(object)h != (Object)null) ? ((Component)h).transform.position : fallback; } private static bool GameExplosion(Vector3 pos) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)combat == (Object)null) { combat = Object.FindObjectOfType<CombatManager>(); } if ((Object)(object)combat == (Object)null) { MelonLogger.Warning("[Madman] CombatManager not found"); return false; } if (dataObj == null) { dataObj = BuildData(); } MadmanState.InBlast = true; MelonCoroutines.Start(ClearGuardLater(0.6f)); combat.CreateExplosion(pos, (ExplosionData)dataObj); return true; } catch (Exception ex) { MelonLogger.Warning("[Madman] CreateExplosion failed: " + ex.Message); return false; } } private static IEnumerator ClearGuardLater(float seconds) { float t = 0f; while (t < seconds) { t += Time.deltaTime; yield return null; } MadmanState.InBlast = false; } private static object BuildData() { //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) Type typeFromHandle = typeof(ExplosionData); MemberInfo[] members = typeFromHandle.GetMembers(BindingFlags.Static | BindingFlags.Public); foreach (MemberInfo memberInfo in members) { object obj = null; try { if (memberInfo is FieldInfo fieldInfo && fieldInfo.FieldType == typeFromHandle) { obj = fieldInfo.GetValue(null); } else if (memberInfo is PropertyInfo propertyInfo && propertyInfo.PropertyType == typeFromHandle && propertyInfo.GetIndexParameters().Length == 0) { obj = propertyInfo.GetValue(null); } } catch { } if (obj != null) { MelonLogger.Msg("[Madman] using ExplosionData preset '" + memberInfo.Name + "'"); return obj; } } MelonLogger.Msg("[Madman] ExplosionData members: " + string.Join(", ", from m in typeFromHandle.GetMembers(BindingFlags.Instance | BindingFlags.Public) where m is FieldInfo || m is PropertyInfo select m.Name + ":" + ((m as FieldInfo)?.FieldType ?? (m as PropertyInfo).PropertyType).Name)); object obj3 = (object)default(ExplosionData); SetNum(obj3, "DamageRadius", 6f); SetNum(obj3, "MaxDamage", 200f); SetNum(obj3, "PushForceRadius", 8f); SetNum(obj3, "MaxPushForce", 15f); return obj3; } private static void SetNum(object boxed, string name, float value) { Type type = boxed.GetType(); FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public); if (field != null) { field.SetValue(boxed, Convert.ChangeType(value, field.FieldType)); return; } PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public); if (property != null && property.CanWrite) { property.SetValue(boxed, Convert.ChangeType(value, property.PropertyType)); } else { MelonLogger.Warning("[Madman] ExplosionData has no '" + name + "'"); } } private static void OwnBlast(Vector3 pos, int skipNpcId) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) SpawnVisual(pos); MadmanState.InBlast = true; try { HashSet<int> hashSet = new HashSet<int> { skipNpcId }; foreach (Collider item in (Il2CppArrayBase<Collider>)(object)Physics.OverlapSphere(pos, 4f)) { if (!((Object)(object)((Component)item).GetComponentInParent<Player>() != (Object)null)) { NPCHealth componentInParent = ((Component)item).GetComponentInParent<NPCHealth>(); if ((Object)(object)componentInParent != (Object)null && hashSet.Add(((Object)componentInParent).GetInstanceID()) && !Reflect.Flag(componentInParent, "IsDead")) { bool flag = true; MadmanCombatPatch.Kill(componentInParent); } Rigidbody attachedRigidbody = item.attachedRigidbody; if ((Object)(object)attachedRigidbody != (Object)null) { attachedRigidbody.AddExplosionForce(600f, pos, 4f, 0.5f); } } } } catch (Exception ex) { MelonLogger.Warning("[Madman] blast failed: " + ex.Message); } finally { MadmanState.InBlast = false; } } private static void SpawnVisual(Vector3 pos) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown //IL_0081: Unknown result type (might be due to invalid IL or missing references) try { GameObject val = GameObject.CreatePrimitive((PrimitiveType)0); Object.Destroy((Object)(object)val.GetComponent<Collider>()); val.transform.position = pos; Shader val2 = Shader.Find("Unlit/Color") ?? Shader.Find("Sprites/Default"); Renderer component = val.GetComponent<Renderer>(); if ((Object)(object)val2 != (Object)null && (Object)(object)component != (Object)null) { component.material = new Material(val2); component.material.color = new Color(1f, 0.5f, 0.1f, 1f); } MelonCoroutines.Start(Expand(val)); } catch (Exception ex) { MelonLogger.Warning("[Madman] blast visual failed: " + ex.Message); } } public static void Reset() { combat = null; lastAny = 0f; lastNpc.Clear(); } private static IEnumerator Expand(GameObject go) { float t = 0f; while (t < 0.35f) { if ((Object)(object)go == (Object)null) { yield break; } t += Time.deltaTime; go.transform.localScale = Vector3.one * Mathf.Lerp(0.5f, 8f, t / 0.35f); yield return null; } if ((Object)(object)go != (Object)null) { Object.Destroy((Object)(object)go); } } } internal static class InfiniteAmmo { private static readonly string[] CapacityNames = new string[6] { "MagazineSize", "magazineSize", "MaxAmmo", "maxAmmo", "AmmoCapacity", "Capacity" }; private static readonly List<Equippable_RangedWeapon> weapons = new List<Equippable_RangedWeapon>(); private static readonly Dictionary<string, int> capCache = new Dictionary<string, int>(); private static readonly Dictionary<string, int> best = new Dictionary<string, int>(); private const float RefillInterval = 0.1f; private const float ScanInterval = 2f; private static float nextRefill; private static float nextScan; private static bool logged; private static bool warned; private static IntPtr fieldPtr; private static bool loggedItemPath; public static void Tick() { if (!MadmanState.Enabled || Time.time < nextRefill) { return; } nextRefill = Time.time + 0.1f; try { if (Time.time >= nextScan) { nextScan = Time.time + 2f; weapons.Clear(); foreach (Equippable_RangedWeapon item in Object.FindObjectsOfType<Equippable_RangedWeapon>()) { weapons.Add(item); } } for (int num = weapons.Count - 1; num >= 0; num--) { Equippable_RangedWeapon val = weapons[num]; if ((Object)(object)val == (Object)null) { weapons.RemoveAt(num); } else { if (!logged) { logged = true; LogMembers(val); } int num2 = Capacity(val); int ammo = val.Ammo; if (num2 <= 0) { best.TryGetValue(((Object)val).name, out var value); value = Math.Max(value, ammo); best[((Object)val).name] = value; num2 = Math.Max(value, 8); } if (ammo < num2 && !SetAmmo(val, num2) && !warned) { warned = true; MelonLogger.Warning("[Madman] could not write Ammo"); } } } } catch (Exception ex) { MelonLogger.Warning("[Madman] infinite ammo failed: " + ex.Message); nextRefill = Time.time + 5f; } } private static int Capacity(Equippable_RangedWeapon w) { string name = ((Object)w).name; if (capCache.TryGetValue(name, out var value)) { return value; } string[] capacityNames = CapacityNames; foreach (string name2 in capacityNames) { if (Reflect.Get(w, name2) is int num && num > 0) { capCache[name] = num; return num; } } capCache[name] = 0; return 0; } private static bool SetAmmo(Equippable_RangedWeapon w, int value) { MethodInfo methodInfo = typeof(Equippable_RangedWeapon).GetProperty("Ammo", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetSetMethod(nonPublic: true); if (methodInfo != null) { methodInfo.Invoke(w, new object[1] { value }); return true; } if (SetViaItemInstance(w, value)) { return true; } if (fieldPtr == IntPtr.Zero) { fieldPtr = FindAmmoField(); } if (fieldPtr == IntPtr.Zero) { return false; } IntPtr ptr = IL2CPP.Il2CppObjectBaseToPtrNotNull((Il2CppObjectBase)(object)w); int ofs = (int)IL2CPP.il2cpp_field_get_offset(fieldPtr); Marshal.WriteInt32(ptr, ofs, value); return true; } private static bool SetViaItemInstance(Equippable_RangedWeapon w, int value) { string[] array = new string[3] { "itemInstance", "ItemInstance", "instance" }; foreach (string text in array) { object obj = Reflect.Get(w, text); Il2CppObjectBase val = (Il2CppObjectBase)((obj is Il2CppObjectBase) ? obj : null); if (val == null) { continue; } IntegerItemInstance val2 = val.TryCast<IntegerItemInstance>(); if (val2 != null) { if (!loggedItemPath) { loggedItemPath = true; MelonLogger.Msg("[Madman] ammo via item instance '" + text + "'"); } if (Reflect.Invoke(val2, "SetValue", value)) { return true; } PropertyInfo property = ((object)val2).GetType().GetProperty("Value", BindingFlags.Instance | BindingFlags.Public); if (property != null && property.CanWrite) { property.SetValue(val2, value); return true; } } } return false; } private static IntPtr FindAmmoField() { FieldInfo[] fields = typeof(Equippable_RangedWeapon).GetFields(BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { if (fieldInfo.Name.StartsWith("NativeFieldInfoPtr") && fieldInfo.Name.IndexOf("Ammo", StringComparison.OrdinalIgnoreCase) >= 0 && fieldInfo.GetValue(null) is IntPtr intPtr && intPtr != IntPtr.Zero) { MelonLogger.Msg("[Madman] ammo field: " + fieldInfo.Name); return intPtr; } } return IntPtr.Zero; } private static void LogMembers(object w) { IEnumerable<string> values = from m in w.GetType().GetMembers(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) where (m is PropertyInfo || m is FieldInfo) && !m.Name.StartsWith("NativeFieldInfoPtr") select m.Name + ":" + ((m as FieldInfo)?.FieldType ?? (m as PropertyInfo).PropertyType).Name; MelonLogger.Msg("[Madman] Equippable_RangedWeapon members: " + string.Join(", ", values)); } } internal static class MadmanCombatPatch { public static bool Busy; public static float? CurrentHealth(NPCHealth h) { string[] array = new string[3] { "Health", "CurrentHealth", "currentHealth" }; foreach (string name in array) { if (Reflect.Get(h, name) is float value) { return value; } } return null; } public static bool Alive(NPCHealth h) { if (Reflect.Flag(h, "IsDead")) { return false; } float? num = CurrentHealth(h); return !num.HasValue || !(num.Value <= 0f); } public static void Kill(NPCHealth h) { Busy = true; try { if (Reflect.TryInvoke(h, "Die")) { WantedLevel.Raise(); } } finally { Busy = false; } } public static bool KnockOut(NPCHealth h) { Busy = true; try { return Reflect.TryInvoke(h, "KnockOut", "Knockout"); } finally { Busy = false; } } } internal static class PlayerAttack { private const bool RequireRecentAttack = false; private static float last; public static bool Allowed => true; public static void Tick() { if (Input.GetMouseButton(0)) { last = Time.time; } } } [HarmonyPatch] internal static class MadmanGunPatch { private static MethodBase target; private static bool Prepare() { target = Reflect.Find(typeof(NPCHealth), "TakeDamage"); if (target == null) { MelonLogger.Warning("[Madman] NPCHealth.TakeDamage not found, gun rule disabled"); } return target != null; } private static MethodBase TargetMethod() { return target; } private static bool Prefix(object __instance) { //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_0050: Unknown result type (might be due to invalid IL or missing references) if (!MadmanState.Enabled || MadmanState.InBlast || MadmanCombatPatch.Busy) { return true; } NPCHealth val = (NPCHealth)((__instance is NPCHealth) ? __instance : null); if ((Object)(object)val == (Object)null || !PlayerAttack.Allowed) { return true; } Vector3 position = ((Component)val).transform.position; ExplosionFx.Boom(position, val); if (!MadmanCombatPatch.Alive(val)) { return true; } MeleeTracker.Forget(((Object)val).GetInstanceID()); MadmanCombatPatch.Kill(val); return false; } } [HarmonyPatch] internal static class MadmanMeleePatch { private static MethodBase target; private static readonly Dictionary<int, float> lastEvent = new Dictionary<int, float>(); private static bool Prepare() { target = typeof(NPCHealth).GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name.Contains("set_value") && m.Name.Contains("currentHealth")); if (target == null) { MelonLogger.Warning("[Madman] currentHealth setter not found, melee rule disabled"); } return target != null; } private static MethodBase TargetMethod() { return target; } private static bool Prefix(object __instance, object[] __args) { //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) if (!MadmanState.Enabled || MadmanState.InBlast || MadmanCombatPatch.Busy) { return true; } NPCHealth val = (NPCHealth)((__instance is NPCHealth) ? __instance : null); if ((Object)(object)val == (Object)null || __args == null || __args.Length < 2) { return true; } if (!(__args[0] is float num) || !(__args[1] is bool flag) || !flag) { return true; } float? num2 = MadmanCombatPatch.CurrentHealth(val); if (!num2.HasValue || num2.Value <= 0f || num >= num2.Value - 0.01f) { return true; } if (!PlayerAttack.Allowed) { return true; } int instanceID = ((Object)val).GetInstanceID(); float time = Time.time; if (lastEvent.TryGetValue(instanceID, out var value) && time - value < 0.15f) { return false; } lastEvent[instanceID] = time; Vector3 position = ((Component)val).transform.position; ExplosionFx.Boom(position, val); if (MeleeTracker.RegisterHit(instanceID) >= 2) { MeleeTracker.Forget(instanceID); MadmanCombatPatch.Kill(val); } else if (!MadmanCombatPatch.KnockOut(val)) { __args[0] = 0f; return true; } return false; } } public class MadmanCommand : BaseConsoleCommand { public override string CommandWord => "madman"; public override string CommandDescription => "Toggle madman mode. Optional: madman on / madman off"; public override string ExampleUsage => "madman"; public override void ExecuteCommand(List<string> args) { if (args != null && args.Count > 0) { string text = args[0].ToLowerInvariant(); MadmanState.Set(text == "on" || text == "1" || text == "true"); } else { MadmanState.Toggle(); } } } [HarmonyPatch] internal static class MadmanFusePatch { private static readonly List<MethodBase> targets = new List<MethodBase>(); private static bool Prepare() { Add(typeof(Explosive), "ApplyToNPC"); Add(typeof(Explosive), "ApplyToPlayer"); Add(typeof(CountdownExplosion), "Trigger"); return targets.Count > 0; } private static void Add(Type t, string name) { MethodBase methodBase = Reflect.Find(t, name); if (methodBase != null) { targets.Add(methodBase); return; } MelonLogger.Warning($"[Madman] {t.Name}.{name} not found, fuse block incomplete"); } private static IEnumerable<MethodBase> TargetMethods() { return targets; } private static bool Prefix(MethodBase __originalMethod) { if (!MadmanState.Enabled) { return true; } MelonLogger.Msg("[Madman] blocked " + __originalMethod.DeclaringType.Name + "." + __originalMethod.Name); return false; } } [HarmonyPatch] internal static class MadmanGodmodePatch { private static MethodBase target; private static bool Prepare() { target = Reflect.Find(typeof(PlayerHealth), "TakeDamage"); if (target == null) { MelonLogger.Warning("[Madman] PlayerHealth.TakeDamage not found, godmode disabled"); } return target != null; } private static MethodBase TargetMethod() { return target; } private static bool Prefix() { return !MadmanState.Enabled; } } public class MadmanScanCommand : BaseConsoleCommand { public override string CommandWord => "madmanscan"; public override string CommandDescription => "Logs game types/members matching words (read-only). e.g. madmanscan ammo"; public override string ExampleUsage => "madmanscan ammo reload"; public override void ExecuteCommand(List<string> args) { string[] words = ((args != null && args.Count > 0) ? args.Select((string a) => a.ToLowerInvariant()).ToArray() : new string[3] { "explo", "blast", "detonat" }); Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => a.GetName().Name == "Assembly-CSharp"); if (assembly == null) { MelonLogger.Warning("[Scan] Assembly-CSharp not found"); return; } Type[] array; try { array = assembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { array = ex.Types.Where((Type t) => t != null).ToArray(); } int num = 0; Type[] array2 = array; foreach (Type type in array2) { if (!(type.Namespace ?? "").StartsWith("Il2CppScheduleOne")) { continue; } MemberInfo[] members; try { members = type.GetMembers(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } catch { continue; } List<MemberInfo> source = members.Where((MemberInfo m) => !m.Name.StartsWith("NativeFieldInfoPtr") && !m.Name.StartsWith("NativeMethodInfoPtr") && !m.Name.StartsWith("get_") && !m.Name.StartsWith("set_") && (m is MethodInfo || m is PropertyInfo || m is FieldInfo)).ToList(); bool flag = Hit(type.Name); List<MemberInfo> list = (flag ? source.Take(30).ToList() : source.Where((MemberInfo m) => Hit(m.Name)).ToList()); if (list.Count == 0) { continue; } MelonLogger.Msg($"[Scan] {type.Namespace}.{type.Name}{(flag ? " (type match)" : "")}"); foreach (MemberInfo item in list) { string text = ((item is MethodInfo methodInfo) ? ("(" + string.Join(", ", from p in methodInfo.GetParameters() select p.ParameterType.Name) + ")") : ((item is PropertyInfo propertyInfo) ? (" : " + propertyInfo.PropertyType.Name) : (" : " + ((FieldInfo)item).FieldType.Name))); MelonLogger.Msg("[Scan] " + item.Name + text); if (++num >= 150) { MelonLogger.Msg("[Scan] stopped at 150 results"); return; } } } MelonLogger.Msg($"[Scan] done, {num} members"); bool Hit(string s) { return words.Any((string w) => s.IndexOf(w, StringComparison.OrdinalIgnoreCase) >= 0); } } } public static class MadmanState { public static bool InBlast; public const float ComboWindow = 4f; public const float BlastRadius = 4f; public const float BlastForce = 600f; public const bool BlastKills = true; private static float noPlayerSince; public static bool Enabled { get; private set; } public static void Set(bool enable) { if (enable && (Object)(object)Player.Local == (Object)null) { MelonLogger.Warning("[Madman] load a save first"); return; } Enabled = enable; MeleeTracker.Clear(); PlayerEffects.Apply(enable); MelonLogger.Msg("[Madman] " + (enable ? "ON" : "OFF")); } public static void Toggle() { Set(!Enabled); } public static void Reset() { Enabled = false; InBlast = false; MeleeTracker.Clear(); PlayerEffects.Reset(); ExplosionFx.Reset(); MelonLogger.Msg("[Madman] reset"); } public static void Tick() { if (!Enabled || (Object)(object)Player.Local != (Object)null) { noPlayerSince = 0f; } else if (noPlayerSince == 0f) { noPlayerSince = Time.time; } else if (Time.time - noPlayerSince > 2f) { noPlayerSince = 0f; Reset(); } } } public static class MeleeTracker { private static readonly Dictionary<int, int> counts = new Dictionary<int, int>(); private static readonly Dictionary<int, float> lastHit = new Dictionary<int, float>(); public static int RegisterHit(int id) { float time = Time.time; if (!lastHit.TryGetValue(id, out var value) || time - value > 4f) { counts[id] = 0; } counts[id] = ((!counts.TryGetValue(id, out var value2)) ? 1 : (value2 + 1)); lastHit[id] = time; return counts[id]; } public static void Forget(int id) { counts.Remove(id); lastHit.Remove(id); } public static void Clear() { counts.Clear(); lastHit.Clear(); } } internal static class PlayerEffects { private static readonly Type[] Wanted = new Type[4] { typeof(Sneaky), typeof(Energizing), typeof(AntiGravity), typeof(Athletic) }; private static readonly Dictionary<Type, object> cache = new Dictionary<Type, object>(); private const float RefreshSeconds = 1f; private static bool active; private static float next; public static void Apply(bool on) { active = on; next = 0f; Player local = Player.Local; if ((Object)(object)local == (Object)null) { MelonLogger.Warning("[Madman] no local player yet, effects will apply once one exists"); return; } Type[] wanted = Wanted; foreach (Type type in wanted) { object obj = Get(type); if (obj == null) { MelonLogger.Warning("[Madman] could not get " + type.Name); continue; } bool flag = (on ? Reflect.Invoke(obj, "ApplyToPlayer", local) : Reflect.Invoke(obj, "ClearFromPlayer", local)); MelonLogger.Msg($"[Madman] {type.Name} {(on ? "apply" : "clear")}: {(flag ? "ok" : "method not found")}"); } } public static void Reset() { active = false; next = 0f; cache.Clear(); } public static void Tick() { if (!active || Time.time < next) { return; } next = Time.time + 1f; Player local = Player.Local; if ((Object)(object)local == (Object)null) { return; } Type[] wanted = Wanted; foreach (Type t in wanted) { object obj = Get(t); if (obj != null) { Reflect.Invoke(obj, "ClearFromPlayer", local); Reflect.Invoke(obj, "ApplyToPlayer", local); } } } private static object Get(Type t) { if (cache.TryGetValue(t, out object value) && value != null) { return value; } value = Create(t); if (value != null) { cache[t] = value; } return value; } private static object Create(Type t) { try { Il2CppReferenceArray<Object> val = Resources.FindObjectsOfTypeAll(Il2CppType.From(t)); if (val != null && ((Il2CppArrayBase<Object>)(object)val).Length > 0) { return Activator.CreateInstance(t, ((Il2CppObjectBase)((Il2CppArrayBase<Object>)(object)val)[0]).Pointer); } } catch { } try { return Activator.CreateInstance(t); } catch (Exception ex) { MelonLogger.Warning("[Madman] " + t.Name + " instance failed: " + ex.Message); return null; } } } internal static class Reflect { private const BindingFlags All = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy; public static MethodBase Find(Type t, string name) { return (from m in t.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy) where m.Name == name orderby m.GetParameters().Length select m).FirstOrDefault(); } public static object Get(object o, string name) { if (o == null) { return null; } Type type = o.GetType(); PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy); if (property != null) { try { return property.GetValue(o); } catch { } } FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy); if (field != null) { try { return field.GetValue(o); } catch { } } return null; } public static bool Flag(object o, string name) { object obj = Get(o, name); bool flag = default(bool); int num; if (obj is bool) { flag = (bool)obj; num = 1; } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } public static bool TryInvoke(object o, params string[] names) { foreach (string text in names) { MethodBase methodBase = Find(o.GetType(), text); if (methodBase == null) { continue; } try { object[] parameters = (from p in methodBase.GetParameters() select p.ParameterType.IsValueType ? Activator.CreateInstance(p.ParameterType) : null).ToArray(); methodBase.Invoke(o, parameters); return true; } catch (Exception ex) { MelonLogger.Warning("[Madman] " + text + " failed: " + ex.Message); } } MelonLogger.Warning("[Madman] none of [" + string.Join(", ", names) + "] found on " + o.GetType().Name); return false; } public static bool Invoke(object o, string name, params object[] args) { MethodInfo methodInfo = o.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy).FirstOrDefault((MethodInfo x) => x.Name == name && x.GetParameters().Length == args.Length); if (methodInfo == null) { return false; } try { methodInfo.Invoke(o, args); return true; } catch (Exception ex) { MelonLogger.Warning("[Madman] " + name + " threw: " + ex.Message); return false; } } } internal static class WantedLevel { private const string LevelName = "Lethal"; private static float last; public static void Raise() { if (Time.time - last < 1f) { return; } last = Time.time; try { Player local = Player.Local; object obj = (((Object)(object)local == (Object)null) ? null : Reflect.Get(local, "CrimeData")); if (obj == null) { MelonLogger.Warning("[Madman] no CrimeData on the player"); return; } MethodInfo methodInfo = obj.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo x) => x.Name == "SetPursuitLevel"); if (methodInfo == null) { MelonLogger.Warning("[Madman] SetPursuitLevel not found on CrimeData"); return; } ParameterInfo[] parameters = methodInfo.GetParameters(); if (parameters.Length == 0 || !parameters[0].ParameterType.IsEnum) { MelonLogger.Warning("[Madman] unexpected SetPursuitLevel signature"); return; } object level; try { level = Enum.Parse(parameters[0].ParameterType, "Lethal"); } catch { MelonLogger.Warning("[Madman] no level 'Lethal'. Options: " + string.Join(", ", Enum.GetNames(parameters[0].ParameterType))); return; } object[] parameters2 = parameters.Select((ParameterInfo p, int i) => (i == 0) ? level : (p.ParameterType.IsValueType ? Activator.CreateInstance(p.ParameterType) : null)).ToArray(); methodInfo.Invoke(obj, parameters2); Reflect.Invoke(obj, "RecordLastKnownPosition", true); } catch (Exception ex) { MelonLogger.Warning("[Madman] wanted level failed: " + ex.Message); } } } }