using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Photon.Pun;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("FrogQTEMod")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("FrogQTEMod")]
[assembly: AssemblyTitle("FrogQTEMod")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace FrogQTEMod;
[BepInPlugin("com.peaks.frogqte", "FrogQTE", "1.0.1")]
public class Plugin : BaseUnityPlugin
{
public static Plugin Instance;
internal ManualLogSource Logger;
private Harmony _harmony;
internal static ConfigEntry<bool> Enabled;
internal static ConfigEntry<float> FlyTrapAmount;
internal static ConfigEntry<int> PressesToEscape;
internal static ConfigEntry<float> EscapeTime;
internal static ConfigEntry<float> EscapeThreshold;
internal static ConfigEntry<float> HoldTime;
private void Awake()
{
//IL_0060: Unknown result type (might be due to invalid IL or missing references)
//IL_006a: Expected O, but got Unknown
//IL_0092: Unknown result type (might be due to invalid IL or missing references)
//IL_009c: Expected O, but got Unknown
//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
//IL_00d9: Expected O, but got Unknown
//IL_010c: Unknown result type (might be due to invalid IL or missing references)
//IL_0116: Expected O, but got Unknown
//IL_0149: Unknown result type (might be due to invalid IL or missing references)
//IL_0153: Expected O, but got Unknown
//IL_015e: Unknown result type (might be due to invalid IL or missing references)
//IL_0168: Expected O, but got Unknown
//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
//IL_01b1: Expected O, but got Unknown
Instance = this;
Logger = ((BaseUnityPlugin)this).Logger;
Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable the frog-capture QTE (mash Space to escape)");
FlyTrapAmount = ((BaseUnityPlugin)this).Config.Bind<float>("General", "FlyTrapAmount", 0.05f, new ConfigDescription("FlyTrap status (5% of HP) applied when the frog grabs you", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.025f, 1f), Array.Empty<object>()));
PressesToEscape = ((BaseUnityPlugin)this).Config.Bind<int>("General", "PressesToEscape", 1, new ConfigDescription("How many Space presses it takes to escape", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10), Array.Empty<object>()));
EscapeTime = ((BaseUnityPlugin)this).Config.Bind<float>("General", "EscapeTime", 5f, new ConfigDescription("Seconds you have to mash Space and escape", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 15f), Array.Empty<object>()));
EscapeThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("General", "EscapeThreshold", 0.025f, new ConfigDescription("FlyTrap status below which the frog lets go", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 0.1f), Array.Empty<object>()));
HoldTime = ((BaseUnityPlugin)this).Config.Bind<float>("General", "HoldTime", 1.5f, new ConfigDescription("Seconds the frog holds you (tongue stuck) before pulling", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 5f), Array.Empty<object>()));
_harmony = new Harmony("com.peaks.frogqte");
_harmony.PatchAll(typeof(FrogQTE));
MethodBase methodBase = FrogQTE.FindLickMoveNext();
if (methodBase != null)
{
_harmony.Patch(methodBase, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(FrogQTE), "TranspileLick", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null);
Logger.LogInfo((object)"[FrogQTE] Lock-hold patch applied to frog lick routine");
}
else
{
Logger.LogWarning((object)"[FrogQTE] Frog lick routine not found; hold time will not be extended");
}
Logger.LogInfo((object)"[FrogQTE] Loaded");
}
private void OnDestroy()
{
Harmony harmony = _harmony;
if (harmony != null)
{
harmony.UnpatchSelf();
}
}
}
[HarmonyPatch]
internal static class FrogQTE
{
private static readonly FieldInfo TargetField = AccessTools.Field(typeof(FrogTongue), "_targetCharacter");
private static readonly FieldInfo PullingField = AccessTools.Field(typeof(FrogTongue), "_isPulling");
private static readonly MethodInfo LetGoMethod = AccessTools.Method(typeof(FrogTongue), "LetGo", (Type[])null, (Type[])null);
private static readonly FieldInfo MovementCharField = AccessTools.Field(typeof(CharacterMovement), "character");
internal static readonly Dictionary<int, float> CaptureStart = new Dictionary<int, float>();
internal static readonly Dictionary<int, int> PressCount = new Dictionary<int, int>();
private static bool IsSkeleton(Character character)
{
try
{
return (Object)(object)character?.data != (Object)null && character.data.isSkeleton;
}
catch
{
return false;
}
}
internal static MethodBase FindLickMoveNext()
{
try
{
Type[] nestedTypes = typeof(FrogTongue).GetNestedTypes(BindingFlags.NonPublic);
foreach (Type type in nestedTypes)
{
if (type.Name != null && type.Name.Contains("LickRoutine"))
{
MethodInfo method = type.GetMethod("MoveNext", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (method != null)
{
return method;
}
}
}
}
catch
{
}
return null;
}
internal static IEnumerable<CodeInstruction> TranspileLick(IEnumerable<CodeInstruction> instructions)
{
float num = 1f / Mathf.Max(0.05f, Plugin.HoldTime.Value);
bool flag = false;
List<CodeInstruction> list = new List<CodeInstruction>(instructions);
for (int i = 0; i < list.Count - 2; i++)
{
CodeInstruction val = list[i];
CodeInstruction val2 = list[i + 1];
CodeInstruction val3 = list[i + 2];
if (val.opcode == OpCodes.Call && val.operand is MethodInfo methodInfo && methodInfo.DeclaringType == typeof(Time) && methodInfo.Name == "get_deltaTime" && val2.opcode == OpCodes.Ldc_R4 && val2.operand is float num2 && Mathf.Abs(num2 - 2f) < 0.0001f && val3.opcode == OpCodes.Mul)
{
val2.operand = num;
flag = true;
}
}
if (!flag && (Object)(object)Plugin.Instance != (Object)null)
{
Plugin.Instance.Logger.LogWarning((object)"[FrogQTE] Transpiler did not find the lock loop");
}
return list;
}
[HarmonyPatch(typeof(FrogTongue), "Attack")]
[HarmonyPostfix]
private static void OnAttack(PhotonView characterView)
{
if (!Plugin.Enabled.Value || (Object)(object)characterView == (Object)null)
{
return;
}
Character component = ((Component)characterView).GetComponent<Character>();
if ((Object)(object)component == (Object)null)
{
return;
}
try
{
if (IsSkeleton(component))
{
Plugin.Instance.Logger.LogInfo((object)("[FrogQTE] " + component.characterName + " is a skeleton, immune to FlyTrap"));
}
else
{
component.refs.afflictions.AddStatus((STATUSTYPE)14, Plugin.FlyTrapAmount.Value, true, true, true);
}
CaptureStart[characterView.ViewID] = Time.time;
PressCount[characterView.ViewID] = 0;
Plugin.Instance.Logger.LogInfo((object)("[FrogQTE] " + component.characterName + " grabbed by frog, mash Space to escape"));
}
catch (Exception ex)
{
Plugin.Instance.Logger.LogWarning((object)("[FrogQTE] OnAttack: " + ex.Message));
}
}
[HarmonyPatch(typeof(CharacterMovement), "TryToJump")]
[HarmonyPostfix]
private static void OnTryToJump(CharacterMovement __instance)
{
if (!Plugin.Enabled.Value)
{
return;
}
object? obj = MovementCharField?.GetValue(__instance);
Character val = (Character)((obj is Character) ? obj : null);
if ((Object)(object)val == (Object)null || !val.IsLocal || val.refs == null || (Object)(object)val.refs.afflictions == (Object)null)
{
return;
}
int viewID = ((MonoBehaviourPun)val).photonView.ViewID;
if (!CaptureStart.ContainsKey(viewID))
{
return;
}
bool flag = IsSkeleton(val);
if (!flag && val.refs.afflictions.GetCurrentStatus((STATUSTYPE)14) <= 0f)
{
return;
}
int value;
int num = ((!PressCount.TryGetValue(viewID, out value)) ? 1 : (value + 1));
PressCount[viewID] = num;
if (num >= Plugin.PressesToEscape.Value)
{
if (!flag)
{
val.refs.afflictions.SubtractStatus((STATUSTYPE)14, 1f, false, false);
}
CancelFall(val);
Plugin.Instance.Logger.LogInfo((object)$"[FrogQTE] {val.characterName} pressed Space {num} times, escaped!");
}
}
private static void CancelFall(Character character)
{
try
{
if (!((Object)(object)character?.data == (Object)null) && !(character.data.fallSeconds <= 0f))
{
character.data.fallSeconds = 0f;
if ((Object)(object)character.refs?.view != (Object)null)
{
character.refs.view.RPC("RPCA_UnFall", (RpcTarget)0, Array.Empty<object>());
}
}
}
catch (Exception ex)
{
Plugin instance = Plugin.Instance;
if (instance != null)
{
instance.Logger.LogWarning((object)("[FrogQTE] CancelFall: " + ex.Message));
}
}
}
[HarmonyPatch(typeof(FrogTongue), "FixedUpdate")]
[HarmonyPostfix]
private static void OnFixedUpdate(FrogTongue __instance)
{
//IL_0117: Unknown result type (might be due to invalid IL or missing references)
if (!Plugin.Enabled.Value)
{
return;
}
object? obj = TargetField?.GetValue(__instance);
Character val = (Character)((obj is Character) ? obj : null);
if ((Object)(object)val == (Object)null || (bool?)PullingField?.GetValue(__instance) != true)
{
return;
}
int value;
bool flag = ((!IsSkeleton(val)) ? (val.refs.afflictions.GetCurrentStatus((STATUSTYPE)14) < Plugin.EscapeThreshold.Value) : (PressCount.TryGetValue(((MonoBehaviourPun)val).photonView.ViewID, out value) && value >= Plugin.PressesToEscape.Value));
bool flag2 = false;
if (!flag && CaptureStart.TryGetValue(((MonoBehaviourPun)val).photonView.ViewID, out var value2))
{
flag2 = Time.time - value2 > Plugin.EscapeTime.Value;
}
if (!flag && !flag2)
{
return;
}
if (PhotonNetwork.IsMasterClient)
{
try
{
if (flag)
{
CancelFall(val);
}
((MonoBehaviourPun)__instance).photonView.RPC("RPCA_FrogAction", (RpcTarget)0, new object[3]
{
((MonoBehaviourPun)val).photonView,
(object)(FrogActionType)3,
Vector3.zero
});
}
catch (Exception ex)
{
Plugin.Instance.Logger.LogWarning((object)("[FrogQTE] LetGo RPC: " + ex.Message));
LetGoMethod?.Invoke(__instance, null);
}
}
if (flag)
{
Plugin.Instance.Logger.LogInfo((object)("[FrogQTE] " + val.characterName + " escaped the frog!"));
}
}
[HarmonyPatch(typeof(FrogTongue), "LetGo")]
[HarmonyPrefix]
private static void OnLetGo(FrogTongue __instance)
{
if (!Plugin.Enabled.Value)
{
return;
}
object? obj = TargetField?.GetValue(__instance);
Character val = (Character)((obj is Character) ? obj : null);
if ((Object)(object)val == (Object)null)
{
return;
}
try
{
int viewID = ((MonoBehaviourPun)val).photonView.ViewID;
CaptureStart.Remove(viewID);
PressCount.Remove(viewID);
if (val.refs.afflictions.GetCurrentStatus((STATUSTYPE)14) > 0f)
{
val.refs.afflictions.SubtractStatus((STATUSTYPE)14, 1f, true, false);
}
}
catch (Exception ex)
{
Plugin.Instance.Logger.LogWarning((object)("[FrogQTE] OnLetGo: " + ex.Message));
}
}
}