From 94dd86d1fb5d05e6d27aaa7da710ad5022080de2 Mon Sep 17 00:00:00 2001 From: ManlyMarco <39247311+ManlyMarco@users.noreply.github.com> Date: Sun, 22 Sep 2024 02:51:10 +0200 Subject: [PATCH] [SVS] Add "Block interrupts" cheat (#31) Thanks to the anon that figured out how to block interruptions with cheat engine, and to deaknaew for letting me know about it and helping research it. --- SVS_CheatTools/CheatToolsWindowInit.SVS.cs | 14 +++++++- SVS_CheatTools/Hooks.cs | 38 ++++++++++++++++++++-- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/SVS_CheatTools/CheatToolsWindowInit.SVS.cs b/SVS_CheatTools/CheatToolsWindowInit.SVS.cs index 1051bb8..ac2bbe9 100644 --- a/SVS_CheatTools/CheatToolsWindowInit.SVS.cs +++ b/SVS_CheatTools/CheatToolsWindowInit.SVS.cs @@ -171,10 +171,12 @@ private static void DrawHSceneCheats(CheatToolsWindow cheatToolsWindow) private static void DrawGeneralCheats(CheatToolsWindow obj) { Hooks.RiggedRng = GUILayout.Toggle(Hooks.RiggedRng, new GUIContent("Rigged RNG (success if above 0%)", null, "All actions with at least 1% chance will always succeed. Must be activated BEFORE talking to a character.\nWARNING: This will affect RNG across the game. NPCs will (probably) always succeed with their actions which will skew the simulation heavily. Some events might never happen or keep repeating until this is turned off.")); + + GUILayout.Space(5); GUILayout.BeginHorizontal(); { - GUILayout.Label("Walking speed"); + GUILayout.Label("Walking speed:"); var normal = Hooks.SpeedMode == Hooks.SpeedModes.Normal || Hooks.SpeedMode == Hooks.SpeedModes.ReturnToNormal; var newNormal = GUILayout.Toggle(normal, "Normal"); @@ -186,6 +188,16 @@ private static void DrawGeneralCheats(CheatToolsWindow obj) Hooks.SpeedMode = Hooks.SpeedModes.Sanic; } GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(); + { + Hooks.InterruptBlock = GUILayout.Toggle(Hooks.InterruptBlock, new GUIContent("Block interrupts", null, "Prevent NPCs from interrupting other characters.")); + Hooks.InterruptBlockAllow3P = GUILayout.Toggle(Hooks.InterruptBlockAllow3P, new GUIContent("except 3P", null, "Do not block NPCs interrupting to ask for a threesome.")); + Hooks.InterruptBlockAllowNonPlayer = GUILayout.Toggle(Hooks.InterruptBlockAllowNonPlayer, new GUIContent("only player", null, "Only block interrupts if player controls one of the involved characters.")); + } + GUILayout.EndHorizontal(); + + GUILayout.Space(5); GUI.enabled = ADV.ADVManager._instance?.IsADV == true; if (GUILayout.Button(new GUIContent("Force Unlock visible talk options", null, "Un-gray and make clickable all currently visible buttons in the talk menu. Mostly for use with the blackmail menu. If the chance is 0% you still won't be able to succeed at the action."))) diff --git a/SVS_CheatTools/Hooks.cs b/SVS_CheatTools/Hooks.cs index 74cf45d..839a0a1 100644 --- a/SVS_CheatTools/Hooks.cs +++ b/SVS_CheatTools/Hooks.cs @@ -1,12 +1,44 @@ using System; using HarmonyLib; using Pathfinding; -using Random = Il2CppSystem.Random; namespace CheatTools; internal static class Hooks { + #region No interruptions + + public static bool InterruptBlock; + public static bool InterruptBlockAllow3P = true; + public static bool InterruptBlockAllowNonPlayer = true; + + [HarmonyPostfix] + [HarmonyPatch(typeof(SV.ReactionManager), nameof(SV.ReactionManager.CheckIntervention))] + private static void ReactionManager_CheckIntervention_Postfix(SV.ReactionManager __instance, + SV.Chara.AI ai, SV.Chara.AI aiTarg1, SV.Chara.AI aiTarg2, + SV.SimulationDefine.CommandNo setCommandNo, + ref bool risSetAction) + { + if (!InterruptBlock) return; + + if (InterruptBlockAllow3P && (setCommandNo == SV.SimulationDefine.CommandNo.LetsHave3P || setCommandNo == SV.SimulationDefine.CommandNo.WantA3P)) return; + + if (InterruptBlockAllowNonPlayer) + { + var includesPc = ai._charaData.IsPC || aiTarg1?._charaData.IsPC == true || aiTarg2?._charaData.IsPC == true; + if (!includesPc) return; + } + +#if DEBUG + Console.WriteLine($"ai={ai._charaData.Name} aiTarg1={aiTarg1._charaData.Name} aiTarg2={aiTarg2._charaData.Name} setCommandNo={setCommandNo} risSetAction={risSetAction}"); +#endif + // Cancel the intervention + ai._charaData.charasGameParam.commandNo = (int)SV.SimulationDefine.CommandNo.None; + risSetAction = false; + } + + #endregion + #region Speedhack [HarmonyPostfix] @@ -72,8 +104,8 @@ private static void ProbabilityCalculation_Detect_Override(ref bool __result) } [HarmonyPostfix] - [HarmonyPatch(typeof(Random), nameof(Random.Next), typeof(int))] - [HarmonyPatch(typeof(Random), nameof(Random.Next), typeof(int), typeof(int))] + [HarmonyPatch(typeof(Il2CppSystem.Random), nameof(Il2CppSystem.Random.Next), typeof(int))] + [HarmonyPatch(typeof(Il2CppSystem.Random), nameof(Il2CppSystem.Random.Next), typeof(int), typeof(int))] private static void Random_Next_Override(int maxValue, ref int __result) { if (RiggedRng) __result = maxValue - 1;