using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Logging; using HarmonyLib; using MMBiomeGeneration; using Microsoft.CodeAnalysis; using Rewired; using Unify.Input; using UnityEngine; using src.UINavigator; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("ClassLibrary2")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ClassLibrary2")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("528f5a23-6efd-4f6b-85e8-1d3d74dfddd6")] [assembly: AssemblyFileVersion("1.0.0.0")] [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.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace COTLMultiplayerTarotAddon { [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("com.cotlmp.tarotaddon", "COTL Multiplayer Tarot Addon", "0.1.0")] public sealed class TarotAddonPlugin : BaseUnityPlugin { internal static ManualLogSource Log; private Harmony _harmony; private void Awake() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; _harmony = new Harmony("com.cotlmp.tarotaddon"); TarotPatches.EnsureClauneckTarotRoomsOnly(null, "Awake"); PatchIfFound(AccessTools.Method(typeof(Interaction_Tarot), "OnInteract", new Type[1] { typeof(StateMachine) }, (Type[])null), "InteractionTarot_OnInteract_Prefix", null, "Interaction_Tarot.OnInteract(StateMachine)"); PatchIfFound(AccessTools.Method(typeof(Interaction_Tarot), "DelayEffectsRoutine", new Type[3] { typeof(TarotCard), typeof(float), typeof(PlayerFarming) }, (Type[])null), "InteractionTarot_DelayEffectsRoutine_Prefix", "InteractionTarot_DelayEffectsRoutine_Postfix", "Interaction_Tarot.DelayEffectsRoutine"); PatchIfFound(AccessTools.Method(typeof(Interaction_Tarot), "OnDisable", (Type[])null, (Type[])null), null, "InteractionTarot_OnDisable_Postfix", "Interaction_Tarot.OnDisable"); PatchIfFound(AccessTools.Method(typeof(Interaction_Tarot), "DoRoutine", (Type[])null, (Type[])null), "InteractionTarot_DoRoutine_Prefix", null, "Interaction_Tarot.DoRoutine()"); PatchIfFound(AccessTools.Method(typeof(Interaction_TarotCard), "OnInteract", new Type[1] { typeof(StateMachine) }, (Type[])null), "InteractionTarotCard_OnInteract_Prefix", null, "Interaction_TarotCard.OnInteract(StateMachine)"); PatchIfFound(AccessTools.Method(typeof(Interaction_TarotCard), "DoRoutine", (Type[])null, (Type[])null), "InteractionTarotCard_DoRoutine_Prefix", null, "Interaction_TarotCard.DoRoutine()"); PatchIfFound(AccessTools.Method(typeof(Interaction_TarotCard), "DelayEffectsRoutine", new Type[1] { typeof(PlayerFarming) }, (Type[])null), "InteractionTarotCard_DelayEffectsRoutine_Prefix", null, "Interaction_TarotCard.DelayEffectsRoutine(PlayerFarming)"); PatchIfFound(AccessTools.Method(typeof(Interaction_TarotCard), "OnDisable", (Type[])null, (Type[])null), null, "InteractionTarotCard_OnDisable_Postfix", "Interaction_TarotCard.OnDisable"); PatchIfFound(AccessTools.Method(typeof(Interaction_Chest), "SelectReward", (Type[])null, (Type[])null), null, "InteractionChest_SelectReward_Postfix", "Interaction_Chest.SelectReward()"); PatchIfFound(AccessTools.Method(typeof(Interaction_Chest), "OnDisableInteraction", Type.EmptyTypes, (Type[])null), null, "InteractionChest_OnDisableInteraction_Postfix", "Interaction_Chest.OnDisableInteraction()"); PatchIfFound(AccessTools.Method(typeof(InventoryItem), "Spawn", new Type[5] { typeof(ITEM_TYPE), typeof(int), typeof(Vector3), typeof(float), typeof(Action) }, (Type[])null), "InventoryItem_Spawn_Prefix", null, "InventoryItem.Spawn(ITEM_TYPE,int,Vector3,float,Action)"); PatchIfFound(AccessTools.Method(typeof(BiomeGenerator), "Generate", Type.EmptyTypes, (Type[])null), "BiomeGenerator_Generate_Prefix", null, "BiomeGenerator.Generate()"); PatchIfFound(AccessTools.Method(typeof(Shrines), "OnInteract", new Type[1] { typeof(StateMachine) }, (Type[])null), "Shrines_OnInteract_Prefix", null, "Shrines.OnInteract(StateMachine)"); PatchIfFound(AccessTools.Method(typeof(Shrines), "DrawCardRoutine", new Type[1] { typeof(PlayerFarming) }, (Type[])null), "Shrines_DrawCardRoutine_Prefix", null, "Shrines.DrawCardRoutine(PlayerFarming)"); PatchIfFound(AccessTools.Method(typeof(Shrines), "DelayEffectsRoutine", new Type[3] { typeof(TarotCard), typeof(float), typeof(PlayerFarming) }, (Type[])null), "Shrines_DelayEffectsRoutine_Prefix", "Shrines_DelayEffectsRoutine_Postfix", "Shrines.DelayEffectsRoutine(TarotCard,float,PlayerFarming)"); PatchIfFound(AccessTools.Method(typeof(Shrines), "OnDisable", Type.EmptyTypes, (Type[])null), null, "Shrines_OnDisable_Postfix", "Shrines.OnDisable()"); Log.LogInfo((object)"Tarot addon loaded."); } private void PatchIfFound(MethodInfo original, string prefix = null, string postfix = null, string originalLabel = null) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Expected O, but got Unknown if (original == null) { Log.LogWarning((object)("[Tarot] Skipped patch (method missing): " + (originalLabel ?? "unknown"))); return; } HarmonyMethod val = null; HarmonyMethod val2 = null; if (!string.IsNullOrEmpty(prefix)) { val = new HarmonyMethod(typeof(TarotPatches), prefix, (Type[])null); } if (!string.IsNullOrEmpty(postfix)) { val2 = new HarmonyMethod(typeof(TarotPatches), postfix, (Type[])null); } _harmony.Patch((MethodBase)original, val, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } internal static class TarotPatches { private static bool VERBOSE_LOGS = false; private const string ClauneckTarotRoomPath = "Assets/_Rooms/Reward Room Tarot.prefab"; private const string CardsOnlyTarotRoomPath = "Assets/_Rooms/Special Free Tarot Cards.prefab"; private static bool _loggedTarotRoomPolicy = false; private static readonly Dictionary TarotOwnerByInstance = new Dictionary(); private static readonly Dictionary> PendingTarotQueueByInstance = new Dictionary>(); private static readonly HashSet WarnedSuppressedDiscardByInstance = new HashSet(); private static readonly Dictionary TarotCardOwnerByInstance = new Dictionary(); private static readonly Dictionary ShrineTarotOwnerByInstance = new Dictionary(); private static readonly Dictionary> PendingShrineTarotQueueByInstance = new Dictionary>(); private static readonly HashSet WarnedSuppressedShrineDiscardByInstance = new HashSet(); private static readonly Dictionary PendingChestTarotExtraByChest = new Dictionary(); private static readonly Dictionary PendingChestTarotExpiryByChest = new Dictionary(); private static int PendingChestTarotExtraAny = 0; private static float PendingChestTarotAnyExpiry = -1f; private static int PendingChestTarotSourceChestId = 0; private static readonly Dictionary RecentChestRewardWindowByChest = new Dictionary(); private static readonly Dictionary RecentChestRewardPositionByChest = new Dictionary(); private static int RecentChestRewardSourceChestId = 0; private static float RecentChestRewardAnyExpiry = -1f; private const float RecentChestRewardWindowSeconds = 8f; private const float ChestTarotFallbackRadius = 6f; private static readonly FieldInfo InteractionChestRewardField = typeof(Interaction_Chest).GetField("Reward", BindingFlags.Instance | BindingFlags.NonPublic); private static bool IsSpawningExtraChestTarot = false; public static void BiomeGenerator_Generate_Prefix(BiomeGenerator __instance) { EnsureClauneckTarotRoomsOnly(__instance, "BiomeGenerator.Generate"); } internal static void EnsureClauneckTarotRoomsOnly(BiomeGenerator biomeGenerator, string reason) { try { if (!_loggedTarotRoomPolicy) { _loggedTarotRoomPolicy = true; TarotAddonPlugin.Log.LogInfo((object)"[TarotRoom] Vanilla tarot-room behavior preserved (no tarot room path filtering)."); } } catch (Exception ex) { TarotAddonPlugin.Log.LogWarning((object)("[TarotRoom] Failed to enforce tarot room policy during " + reason + ": " + ex.Message)); } } private static int RemoveDisallowedTarotRoomPaths(List roomPaths) { return 0; } private static bool IsDisallowedTarotRoomPath(string candidate) { if (string.IsNullOrEmpty(candidate)) { return false; } string text = NormalizeRoomPath(candidate); if (string.Equals(text, NormalizeRoomPath("Assets/_Rooms/Reward Room Tarot.prefab"), StringComparison.OrdinalIgnoreCase)) { return false; } return text.IndexOf("tarot", StringComparison.OrdinalIgnoreCase) >= 0; } private static string NormalizeRoomPath(string path) { if (string.IsNullOrEmpty(path)) { return string.Empty; } return path.Replace('\\', '/').Trim(); } public static void InteractionTarot_OnInteract_Prefix(Interaction_Tarot __instance, StateMachine state) { if ((Object)(object)__instance == (Object)null || (Object)(object)state == (Object)null) { return; } PlayerFarming val = ResolvePlayerFromState(state); if ((Object)(object)val == (Object)null) { return; } TrySetAllowedInputPlayer(val); SetInteractionContext(__instance, val, state); int instanceID = ((Object)__instance).GetInstanceID(); if (PendingTarotQueueByInstance.ContainsKey(instanceID) || __instance.Activated) { return; } Queue queue = BuildTarotQueue(val); if (queue.Count > 0) { PendingTarotQueueByInstance[instanceID] = queue; if (VERBOSE_LOGS) { TarotAddonPlugin.Log.LogInfo((object)("[Tarot] Queue created for instance " + instanceID + ".")); } } } public static bool InteractionTarot_DelayEffectsRoutine_Prefix(Interaction_Tarot __instance, TarotCard card, float delay, ref PlayerFarming playerFarming, ref IEnumerator __result) { if ((Object)(object)__instance == (Object)null) { return true; } PlayerFarming trackedTarotOwner = GetTrackedTarotOwner(__instance); if ((Object)(object)trackedTarotOwner == (Object)null) { return true; } if (trackedTarotOwner.playerID >= 2 && (Object)(object)playerFarming != (Object)(object)trackedTarotOwner) { int instanceID = ((Object)__instance).GetInstanceID(); if (WarnedSuppressedDiscardByInstance.Add(instanceID)) { TarotAddonPlugin.Log.LogInfo((object)("[Tarot] Suppressed extra discard grant from P" + (trackedTarotOwner.playerID + 1) + ".")); } __result = SuppressedDelayRoutine(delay); return false; } if ((Object)(object)playerFarming == (Object)null) { playerFarming = trackedTarotOwner; } return true; } public static void InteractionTarot_DelayEffectsRoutine_Postfix(Interaction_Tarot __instance, TarotCard card, float delay, PlayerFarming playerFarming, ref IEnumerator __result) { if (!((Object)(object)__instance == (Object)null) && __result != null) { PlayerFarming trackedTarotOwner = GetTrackedTarotOwner(__instance); if (!((Object)(object)trackedTarotOwner == (Object)null) && !((Object)(object)playerFarming != (Object)(object)trackedTarotOwner)) { __result = WrapAndAdvanceTarotQueue(__result, __instance, trackedTarotOwner); } } } public static void InteractionTarot_OnDisable_Postfix(Interaction_Tarot __instance) { if (!((Object)(object)__instance == (Object)null)) { int instanceID = ((Object)__instance).GetInstanceID(); TarotOwnerByInstance.Remove(instanceID); PendingTarotQueueByInstance.Remove(instanceID); WarnedSuppressedDiscardByInstance.Remove(instanceID); } } public static void InteractionTarot_DoRoutine_Prefix(Interaction_Tarot __instance) { if ((Object)(object)__instance == (Object)null) { return; } int instanceID = ((Object)__instance).GetInstanceID(); PlayerFarming trackedTarotOwner = GetTrackedTarotOwner(__instance); if ((Object)(object)trackedTarotOwner == (Object)null) { return; } StateMachine val = TryResolveInteractionState(__instance); if ((Object)(object)val == (Object)null && (Object)(object)trackedTarotOwner != (Object)null) { val = trackedTarotOwner.state; } TrySetAllowedInputPlayer(trackedTarotOwner); SetInteractionContext(__instance, trackedTarotOwner, val); if (!PendingTarotQueueByInstance.ContainsKey(instanceID)) { Queue queue = BuildTarotQueue(trackedTarotOwner); if (queue.Count > 0) { PendingTarotQueueByInstance[instanceID] = queue; TarotAddonPlugin.Log.LogInfo((object)("[Tarot] Bootstrapped chained queue for P" + (trackedTarotOwner.playerID + 1) + ".")); } } } public static void Shrines_OnInteract_Prefix(Shrines __instance, StateMachine state) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Invalid comparison between Unknown and I4 if ((Object)(object)__instance == (Object)null || (Object)(object)state == (Object)null || (int)__instance.TypeOfShrine != 7) { return; } PlayerFarming val = ResolvePlayerFromState(state); if ((Object)(object)val == (Object)null) { return; } TrySetAllowedInputPlayer(val); SetInteractionContext(__instance, val, state); int instanceID = ((Object)__instance).GetInstanceID(); ShrineTarotOwnerByInstance[instanceID] = val; if (!PendingShrineTarotQueueByInstance.ContainsKey(instanceID)) { Queue queue = BuildTarotQueue(val); if (queue.Count > 0) { PendingShrineTarotQueueByInstance[instanceID] = queue; TarotAddonPlugin.Log.LogInfo((object)("[ShrineTarot] Queue created for instance " + instanceID + ".")); } } } public static void Shrines_DrawCardRoutine_Prefix(Shrines __instance, ref PlayerFarming playerFarming) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Invalid comparison between Unknown and I4 if ((Object)(object)__instance == (Object)null || (int)__instance.TypeOfShrine != 7) { return; } PlayerFarming val = playerFarming; if ((Object)(object)val == (Object)null) { val = GetTrackedShrineTarotOwner(__instance); } if ((Object)(object)val == (Object)null) { val = TryResolveInteractionPlayer(__instance); } if ((Object)(object)val == (Object)null) { return; } playerFarming = val; TrySetAllowedInputPlayer(val); SetInteractionContext(__instance, val, val.state); int instanceID = ((Object)__instance).GetInstanceID(); ShrineTarotOwnerByInstance[instanceID] = val; if (!PendingShrineTarotQueueByInstance.ContainsKey(instanceID)) { Queue queue = BuildTarotQueue(val); if (queue.Count > 0) { PendingShrineTarotQueueByInstance[instanceID] = queue; TarotAddonPlugin.Log.LogInfo((object)("[ShrineTarot] Bootstrapped queue for P" + (val.playerID + 1) + ".")); } } } public static bool Shrines_DelayEffectsRoutine_Prefix(Shrines __instance, TarotCard card, float delay, ref PlayerFarming playerFarming, ref IEnumerator __result) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Invalid comparison between Unknown and I4 if ((Object)(object)__instance == (Object)null) { return true; } if ((int)__instance.TypeOfShrine != 7) { return true; } PlayerFarming trackedShrineTarotOwner = GetTrackedShrineTarotOwner(__instance); if ((Object)(object)trackedShrineTarotOwner == (Object)null) { return true; } if (trackedShrineTarotOwner.playerID >= 2 && (Object)(object)playerFarming != (Object)(object)trackedShrineTarotOwner) { int instanceID = ((Object)__instance).GetInstanceID(); if (WarnedSuppressedShrineDiscardByInstance.Add(instanceID)) { TarotAddonPlugin.Log.LogInfo((object)("[ShrineTarot] Suppressed extra discard grant from P" + (trackedShrineTarotOwner.playerID + 1) + ".")); } __result = SuppressedDelayRoutine(delay); return false; } if ((Object)(object)playerFarming == (Object)null) { playerFarming = trackedShrineTarotOwner; } return true; } public static void Shrines_DelayEffectsRoutine_Postfix(Shrines __instance, TarotCard card, float delay, PlayerFarming playerFarming, ref IEnumerator __result) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Invalid comparison between Unknown and I4 if (!((Object)(object)__instance == (Object)null) && __result != null && (int)__instance.TypeOfShrine == 7) { PlayerFarming trackedShrineTarotOwner = GetTrackedShrineTarotOwner(__instance); if (!((Object)(object)trackedShrineTarotOwner == (Object)null) && !((Object)(object)playerFarming != (Object)(object)trackedShrineTarotOwner)) { __result = WrapAndAdvanceShrineTarotQueue(__result, __instance, trackedShrineTarotOwner); } } } public static void Shrines_OnDisable_Postfix(Shrines __instance) { if (!((Object)(object)__instance == (Object)null)) { CleanupShrineTarotState(((Object)__instance).GetInstanceID()); } } public static void InteractionTarotCard_OnInteract_Prefix(Interaction_TarotCard __instance, StateMachine state) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)state == (Object)null)) { PlayerFarming val = ResolvePlayerFromState(state); if (!((Object)(object)val == (Object)null)) { TrySetAllowedInputPlayer(val); SetInteractionContext(__instance, val, state); int instanceID = ((Object)__instance).GetInstanceID(); TarotCardOwnerByInstance[instanceID] = val; } } } public static void InteractionTarotCard_DoRoutine_Prefix(Interaction_TarotCard __instance) { if ((Object)(object)__instance == (Object)null) { return; } int instanceID = ((Object)__instance).GetInstanceID(); if (!TarotCardOwnerByInstance.TryGetValue(instanceID, out var value) || (Object)(object)value == (Object)null) { value = TryResolveInteractionPlayer(__instance); } if (!((Object)(object)value == (Object)null)) { StateMachine val = TryResolveInteractionState(__instance); if ((Object)(object)val == (Object)null && (Object)(object)value != (Object)null) { val = value.state; } TrySetAllowedInputPlayer(value); SetInteractionContext(__instance, value, val); TarotCardOwnerByInstance[instanceID] = value; } } public static bool InteractionTarotCard_DelayEffectsRoutine_Prefix(Interaction_TarotCard __instance, ref PlayerFarming playerFarming) { if ((Object)(object)__instance == (Object)null) { return true; } int instanceID = ((Object)__instance).GetInstanceID(); if (!TarotCardOwnerByInstance.TryGetValue(instanceID, out var value)) { value = TryResolveInteractionPlayer(__instance); } if ((Object)(object)value == (Object)null) { return true; } if ((Object)(object)playerFarming == (Object)null || (Object)(object)playerFarming != (Object)(object)value) { playerFarming = value; if (VERBOSE_LOGS) { TarotAddonPlugin.Log.LogInfo((object)("[TarotCard] Rebound reward ownership to P" + (value.playerID + 1) + ".")); } } return true; } public unsafe static void InteractionChest_SelectReward_Postfix(Interaction_Chest __instance) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: 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) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Invalid comparison between Unknown and I4 if ((Object)(object)__instance == (Object)null) { return; } int instanceID = ((Object)__instance).GetInstanceID(); ClearPendingChestTarot(instanceID); Vector3 value = Vector3.zero; bool flag = false; try { value = ((Component)__instance).transform.position; flag = true; } catch { } int effectivePlayerCountForChestTarot = GetEffectivePlayerCountForChestTarot(); int num = Mathf.Clamp(effectivePlayerCountForChestTarot - 2, 0, 2); if (num <= 0) { return; } RecentChestRewardWindowByChest[instanceID] = Time.unscaledTime + 8f; if (flag) { RecentChestRewardPositionByChest[instanceID] = value; } RecentChestRewardSourceChestId = instanceID; RecentChestRewardAnyExpiry = Time.unscaledTime + 6f; if (TryGetChestReward(__instance, out var reward)) { TarotAddonPlugin.Log.LogInfo((object)("[TarotCard] Chest reward rolled: " + ((object)(*(ITEM_TYPE*)(&reward))/*cast due to .constrained prefix*/).ToString())); if ((int)reward != 26) { TarotAddonPlugin.Log.LogInfo((object)"[TarotCard] Chest did not roll tarot card this time."); return; } PendingChestTarotExtraByChest[instanceID] = num; PendingChestTarotExpiryByChest[instanceID] = Time.unscaledTime + 10f; PendingChestTarotExtraAny = num; PendingChestTarotAnyExpiry = Time.unscaledTime + 6f; PendingChestTarotSourceChestId = instanceID; TarotAddonPlugin.Log.LogInfo((object)("[TarotCard] Chest tarot bonus prepared: +" + num + " card(s) for effectivePlayers=" + effectivePlayerCountForChestTarot + " (playersCount=" + PlayerFarming.playersCount + ").")); } } public static void InteractionChest_OnDisableInteraction_Postfix(Interaction_Chest __instance) { _ = (Object)(object)__instance == (Object)null; } public static void InventoryItem_Spawn_Prefix(ITEM_TYPE type, int quantity, Vector3 position, float StartSpeed, Action result) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Invalid comparison between Unknown and I4 //IL_028b: Unknown result type (might be due to invalid IL or missing references) //IL_028d: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_0290: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) if (IsSpawningExtraChestTarot || (int)type != 26 || quantity <= 0) { return; } int value = 0; int num = 0; Interaction_Chest instance = Interaction_Chest.Instance; if ((Object)(object)instance != (Object)null) { int instanceID = ((Object)instance).GetInstanceID(); num = instanceID; if (PendingChestTarotExpiryByChest.TryGetValue(instanceID, out var value2) && Time.unscaledTime > value2) { ClearPendingChestTarot(instanceID); } else if (!PendingChestTarotExtraByChest.TryGetValue(instanceID, out value)) { value = 0; } } if (value <= 0 && PendingChestTarotExtraAny > 0) { if (PendingChestTarotAnyExpiry > 0f && Time.unscaledTime > PendingChestTarotAnyExpiry) { ClearPendingChestTarotAny(); } else { value = PendingChestTarotExtraAny; if (num == 0) { num = PendingChestTarotSourceChestId; } } } if (value <= 0) { Interaction_Chest instance2 = Interaction_Chest.Instance; if ((Object)(object)instance2 != (Object)null) { int instanceID2 = ((Object)instance2).GetInstanceID(); if (RecentChestRewardWindowByChest.TryGetValue(instanceID2, out var value3)) { if (Time.unscaledTime > value3) { ClearRecentChestRewardState(instanceID2); } else { bool flag = true; try { flag = Vector3.Distance(((Component)instance2).transform.position, position) <= 6f; } catch { flag = true; } if (flag) { int effectivePlayerCountForChestTarot = GetEffectivePlayerCountForChestTarot(); value = Mathf.Clamp(effectivePlayerCountForChestTarot - 2, 0, 2); if (value > 0) { num = instanceID2; TarotAddonPlugin.Log.LogInfo((object)("[TarotCard] Chest tarot fallback engaged: +" + value + " card(s) for effectivePlayers=" + effectivePlayerCountForChestTarot + ".")); } } } } } else if (RecentChestRewardAnyExpiry > 0f) { if (Time.unscaledTime > RecentChestRewardAnyExpiry) { if (RecentChestRewardSourceChestId != 0) { RecentChestRewardPositionByChest.Remove(RecentChestRewardSourceChestId); } RecentChestRewardAnyExpiry = -1f; RecentChestRewardSourceChestId = 0; } else { int recentChestRewardSourceChestId = RecentChestRewardSourceChestId; bool flag2 = true; if (recentChestRewardSourceChestId != 0 && RecentChestRewardPositionByChest.TryGetValue(recentChestRewardSourceChestId, out var value4)) { flag2 = Vector3.Distance(value4, position) <= 6f; } if (flag2) { int effectivePlayerCountForChestTarot2 = GetEffectivePlayerCountForChestTarot(); value = Mathf.Clamp(effectivePlayerCountForChestTarot2 - 2, 0, 2); if (value > 0) { num = recentChestRewardSourceChestId; TarotAddonPlugin.Log.LogInfo((object)("[TarotCard] Chest tarot fallback(any) engaged: +" + value + " card(s) for effectivePlayers=" + effectivePlayerCountForChestTarot2 + ".")); } } } } } if (value <= 0) { return; } try { IsSpawningExtraChestTarot = true; Vector3 val = default(Vector3); for (int i = 0; i < value; i++) { ((Vector3)(ref val))..ctor(Random.Range(-0.35f, 0.35f), Random.Range(-0.2f, 0.2f), 0f); InventoryItem.Spawn(type, 1, position + val, StartSpeed, result); } TarotAddonPlugin.Log.LogInfo((object)("[TarotCard] Chest tarot multiplied: base drop + " + value + " extra.")); } catch (Exception ex) { TarotAddonPlugin.Log.LogWarning((object)("[TarotCard] Failed chest tarot multiply: " + ex.Message)); } finally { IsSpawningExtraChestTarot = false; if (num != 0) { if (PendingChestTarotExpiryByChest.TryGetValue(num, out var value5) && Time.unscaledTime > value5) { ClearPendingChestTarot(num); } if (RecentChestRewardWindowByChest.TryGetValue(num, out var value6) && Time.unscaledTime > value6) { ClearRecentChestRewardState(num); } } if (PendingChestTarotAnyExpiry > 0f && Time.unscaledTime > PendingChestTarotAnyExpiry) { ClearPendingChestTarotAny(); } if (RecentChestRewardAnyExpiry > 0f && Time.unscaledTime > RecentChestRewardAnyExpiry) { if (RecentChestRewardSourceChestId != 0) { RecentChestRewardPositionByChest.Remove(RecentChestRewardSourceChestId); } RecentChestRewardAnyExpiry = -1f; RecentChestRewardSourceChestId = 0; } } } public static void InteractionTarotCard_OnDisable_Postfix(Interaction_TarotCard __instance) { if (!((Object)(object)__instance == (Object)null)) { CleanupTarotCardState(((Object)__instance).GetInstanceID()); } } private static void CleanupTarotCardState(int interactionId) { TarotCardOwnerByInstance.Remove(interactionId); } private static bool TryGetChestReward(Interaction_Chest chest, out ITEM_TYPE reward) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected I4, but got Unknown reward = (ITEM_TYPE)0; if ((Object)(object)chest == (Object)null || InteractionChestRewardField == null) { return false; } try { object value = InteractionChestRewardField.GetValue(chest); if (value is ITEM_TYPE) { reward = (ITEM_TYPE)(int)(ITEM_TYPE)value; return true; } } catch { } return false; } private static int GetEffectivePlayerCountForChestTarot() { int num = Mathf.Clamp(PlayerFarming.playersCount, 0, 4); HashSet hashSet = new HashSet(); int num2 = CountRelaxedActivePlayerSlots(); if (CoopManager.AllPlayerGameObjects != null) { int num3 = Mathf.Min(CoopManager.AllPlayerGameObjects.Length, 4); for (int i = 0; i < num3; i++) { GameObject val = CoopManager.AllPlayerGameObjects[i]; if ((Object)(object)val != (Object)null && val.activeInHierarchy) { hashSet.Add(i); } } } int num4 = Mathf.Max(hashSet.Count, num2); int num5 = 0; for (int j = 0; j < 4; j++) { if (HasInputAssignedToSlot(j)) { num5++; } } int num6 = Mathf.Max(new int[3] { num, num4, num5 }); if (num6 <= 0) { num6 = 1; } return Mathf.Clamp(num6, 1, 4); } private static int CountRelaxedActivePlayerSlots() { if (PlayerFarming.players == null) { return 0; } HashSet hashSet = new HashSet(); for (int i = 0; i < PlayerFarming.players.Count; i++) { PlayerFarming val = PlayerFarming.players[i]; if (!((Object)(object)val == (Object)null) && val.playerID >= 0 && val.playerID <= 3 && !((Object)(object)val.state == (Object)null) && !((Object)(object)((Component)val).gameObject == (Object)null) && ((Component)val).gameObject.activeInHierarchy && HasUsableInput(val)) { hashSet.Add(val.playerID); } } return hashSet.Count; } private static bool HasInputAssignedToSlot(int slot) { try { Player player = RewiredInputManager.GetPlayer(slot); if (player == null || player.controllers == null) { return false; } if (player.controllers.hasKeyboard) { return true; } return player.controllers.Joysticks != null && player.controllers.Joysticks.Count > 0; } catch { return false; } } private static void ClearPendingChestTarot(int chestId) { PendingChestTarotExtraByChest.Remove(chestId); PendingChestTarotExpiryByChest.Remove(chestId); } private static void ClearPendingChestTarotAny() { PendingChestTarotExtraAny = 0; PendingChestTarotAnyExpiry = -1f; PendingChestTarotSourceChestId = 0; } private static void ClearRecentChestRewardState(int chestId) { if (chestId != 0) { RecentChestRewardWindowByChest.Remove(chestId); RecentChestRewardPositionByChest.Remove(chestId); if (RecentChestRewardSourceChestId == chestId) { RecentChestRewardSourceChestId = 0; RecentChestRewardAnyExpiry = -1f; } } } private static IEnumerator WrapAndAdvanceTarotQueue(IEnumerator original, Interaction_Tarot interaction, PlayerFarming owner) { while (SafeMoveNext(original)) { yield return original.Current; } if ((Object)(object)interaction == (Object)null) { yield break; } int id = ((Object)interaction).GetInstanceID(); if (!PendingTarotQueueByInstance.TryGetValue(id, out var queue) || queue == null || queue.Count == 0) { CleanupInteractionState(id); yield break; } yield return (object)new WaitForSeconds(0.05f); while (queue.Count > 0) { PlayerFarming activePlayerBySlot = GetActivePlayerBySlot(queue.Dequeue()); if (!((Object)(object)activePlayerBySlot == (Object)null) && (!((Object)(object)owner != (Object)null) || !((Object)(object)activePlayerBySlot == (Object)(object)owner))) { if (!((Behaviour)interaction).isActiveAndEnabled) { CleanupInteractionState(id); } else { TriggerNextTarotInteraction(interaction, activePlayerBySlot); } yield break; } } CleanupInteractionState(id); } private static void TriggerNextTarotInteraction(Interaction_Tarot interaction, PlayerFarming player) { if ((Object)(object)interaction == (Object)null || (Object)(object)player == (Object)null || (Object)(object)player.state == (Object)null) { return; } try { TrySetAllowedInputPlayer(player); SetInteractionContext(interaction, player, player.state); interaction.Activated = false; TarotAddonPlugin.Log.LogInfo((object)("[Tarot] Chained selection owner -> P" + (player.playerID + 1) + ".")); ((Interaction)interaction).OnInteract(player.state); if (VERBOSE_LOGS) { TarotAddonPlugin.Log.LogInfo((object)("[Tarot] Triggered chained interaction for P" + (player.playerID + 1) + ".")); } } catch (Exception ex) { TarotAddonPlugin.Log.LogWarning((object)("[Tarot] Failed to trigger chained interaction: " + ex.Message)); CleanupInteractionState(((Object)interaction).GetInstanceID()); } } private static IEnumerator WrapAndAdvanceShrineTarotQueue(IEnumerator original, Shrines shrine, PlayerFarming owner) { while (SafeMoveNext(original)) { yield return original.Current; } if ((Object)(object)shrine == (Object)null) { yield break; } int id = ((Object)shrine).GetInstanceID(); if (!PendingShrineTarotQueueByInstance.TryGetValue(id, out var queue) || queue == null || queue.Count == 0) { CleanupShrineTarotState(id); yield break; } yield return (object)new WaitForSeconds(0.05f); while (queue.Count > 0) { PlayerFarming activePlayerBySlot = GetActivePlayerBySlot(queue.Dequeue()); if (!((Object)(object)activePlayerBySlot == (Object)null) && (!((Object)(object)owner != (Object)null) || !((Object)(object)activePlayerBySlot == (Object)(object)owner))) { if (!((Behaviour)shrine).isActiveAndEnabled) { CleanupShrineTarotState(id); } else { TriggerNextShrineTarotInteraction(shrine, activePlayerBySlot); } yield break; } } CleanupShrineTarotState(id); } private static void TriggerNextShrineTarotInteraction(Shrines shrine, PlayerFarming player) { if ((Object)(object)shrine == (Object)null || (Object)(object)player == (Object)null || (Object)(object)player.state == (Object)null) { return; } int instanceID = ((Object)shrine).GetInstanceID(); try { TrySetAllowedInputPlayer(player); SetInteractionContext(shrine, player, player.state); ShrineTarotOwnerByInstance[instanceID] = player; if (!(Traverse.Create((object)shrine).Method("DrawCardRoutine", new object[1] { player }).GetValue() is IEnumerator enumerator)) { TarotAddonPlugin.Log.LogWarning((object)("[ShrineTarot] Failed to resolve DrawCardRoutine for P" + (player.playerID + 1) + ".")); CleanupShrineTarotState(instanceID); } else { TarotAddonPlugin.Log.LogInfo((object)("[ShrineTarot] Chained purchase owner -> P" + (player.playerID + 1) + ".")); ((MonoBehaviour)shrine).StartCoroutine(enumerator); } } catch (Exception ex) { TarotAddonPlugin.Log.LogWarning((object)("[ShrineTarot] Failed to trigger chained purchase: " + ex.Message)); CleanupShrineTarotState(instanceID); } } private static Queue BuildTarotQueue(PlayerFarming starter) { Queue queue = new Queue(); if ((Object)(object)starter == (Object)null) { return queue; } int playerID = starter.playerID; if (playerID <= 1) { EnqueueSlotIfActive(queue, 2); EnqueueSlotIfActive(queue, 3); return queue; } int preferredVanillaOwnerSlot = GetPreferredVanillaOwnerSlot(starter); EnqueueSlotIfActive(queue, preferredVanillaOwnerSlot); switch (playerID) { case 2: EnqueueSlotIfActive(queue, 3); break; case 3: EnqueueSlotIfActive(queue, 2); break; } return queue; } private static void EnqueueSlotIfActive(Queue queue, int slot) { if (queue != null && (Object)(object)GetActivePlayerBySlot(slot) != (Object)null) { queue.Enqueue(slot); } } private static PlayerFarming GetActivePlayerBySlot(int slot) { if (PlayerFarming.players == null) { return null; } for (int i = 0; i < PlayerFarming.players.Count; i++) { PlayerFarming val = PlayerFarming.players[i]; if (!((Object)(object)val == (Object)null) && val.playerID == slot && (PlayerFarming.playersCount <= 0 || val.playerID < PlayerFarming.playersCount) && !((Object)(object)val.state == (Object)null) && !((Object)(object)((Component)val).gameObject == (Object)null) && ((Component)val).gameObject.activeInHierarchy && HasUsableInput(val)) { return val; } } return null; } private static int GetPreferredVanillaOwnerSlot(PlayerFarming directStarter) { if ((Object)(object)directStarter != (Object)null && directStarter.playerID == 1) { return 1; } if ((Object)(object)GetActivePlayerBySlot(0) != (Object)null) { return 0; } return 1; } private static PlayerFarming ResolvePlayerFromState(StateMachine state) { if ((Object)(object)state == (Object)null) { return null; } PlayerFarming component = ((Component)state).GetComponent(); if ((Object)(object)component != (Object)null) { return component; } try { if ((Object)(object)((Component)state).gameObject != (Object)null) { return PlayerFarming.GetPlayerFarmingComponent(((Component)state).gameObject); } } catch { } return PlayerFarming.Instance; } private static PlayerFarming GetTrackedTarotOwner(Interaction_Tarot interaction) { if ((Object)(object)interaction == (Object)null) { return null; } if (TarotOwnerByInstance.TryGetValue(((Object)interaction).GetInstanceID(), out var value) && (Object)(object)value != (Object)null) { return value; } value = TryResolveInteractionPlayer(interaction); if ((Object)(object)value != (Object)null) { TarotOwnerByInstance[((Object)interaction).GetInstanceID()] = value; } return value; } private static PlayerFarming GetTrackedShrineTarotOwner(Shrines shrine) { if ((Object)(object)shrine == (Object)null) { return null; } int instanceID = ((Object)shrine).GetInstanceID(); if (ShrineTarotOwnerByInstance.TryGetValue(instanceID, out var value) && (Object)(object)value != (Object)null) { return value; } value = TryResolveInteractionPlayer(shrine); if ((Object)(object)value != (Object)null) { ShrineTarotOwnerByInstance[instanceID] = value; } return value; } private static void SetInteractionContext(object interaction, PlayerFarming player, StateMachine state) { if (interaction != null) { if ((Object)(object)player != (Object)null) { TrySetInteractionPlayer(interaction, player); } if ((Object)(object)state != (Object)null) { TrySetInteractionState(interaction, state); } Interaction_Tarot val = (Interaction_Tarot)((interaction is Interaction_Tarot) ? interaction : null); if ((Object)(object)val != (Object)null && (Object)(object)player != (Object)null) { TarotOwnerByInstance[((Object)val).GetInstanceID()] = player; } Interaction_TarotCard val2 = (Interaction_TarotCard)((interaction is Interaction_TarotCard) ? interaction : null); if ((Object)(object)val2 != (Object)null && (Object)(object)player != (Object)null) { TarotCardOwnerByInstance[((Object)val2).GetInstanceID()] = player; } Shrines val3 = (Shrines)((interaction is Shrines) ? interaction : null); if ((Object)(object)val3 != (Object)null && (Object)(object)player != (Object)null) { ShrineTarotOwnerByInstance[((Object)val3).GetInstanceID()] = player; } } } private static void CleanupInteractionState(int interactionId) { TarotOwnerByInstance.Remove(interactionId); PendingTarotQueueByInstance.Remove(interactionId); WarnedSuppressedDiscardByInstance.Remove(interactionId); } private static void CleanupShrineTarotState(int interactionId) { ShrineTarotOwnerByInstance.Remove(interactionId); PendingShrineTarotQueueByInstance.Remove(interactionId); WarnedSuppressedShrineDiscardByInstance.Remove(interactionId); } private static IEnumerator SuppressedDelayRoutine(float delay) { yield return (object)new WaitForSeconds(0.2f + delay); } private static bool HasUsableInput(PlayerFarming player) { if ((Object)(object)player == (Object)null) { return false; } try { if (player.isLamb) { return true; } if (player.rewiredPlayer == null || player.rewiredPlayer.controllers == null) { return false; } return player.rewiredPlayer.controllers.hasKeyboard || player.rewiredPlayer.controllers.joystickCount > 0; } catch { return true; } } private static void TrySetAllowedInputPlayer(PlayerFarming player) { if ((Object)(object)player == (Object)null) { return; } try { UINavigatorNew instance = MonoSingleton.Instance; if (!((Object)(object)instance == (Object)null)) { instance.AllowInputOnlyFromPlayer = player; instance.TemporarilyAllowInputOnlyFromAnyPlayer = false; } } catch { } } private static bool SafeMoveNext(IEnumerator iterator) { if (iterator == null) { return false; } try { return iterator.MoveNext(); } catch (Exception ex) { TarotAddonPlugin.Log.LogWarning((object)("[Tarot] Coroutine iteration failed: " + ex.Message)); return false; } } private static T TryGetField(object instance, string fieldName) where T : class { if (instance == null || string.IsNullOrEmpty(fieldName)) { return null; } try { return Traverse.Create(instance).Field(fieldName).GetValue() as T; } catch { return null; } } private static T TryGetProperty(object instance, string propertyName) where T : class { if (instance == null || string.IsNullOrEmpty(propertyName)) { return null; } try { return Traverse.Create(instance).Property(propertyName, (object[])null).GetValue() as T; } catch { return null; } } private static bool TrySetField(object instance, string fieldName, object value) { if (instance == null || string.IsNullOrEmpty(fieldName)) { return false; } try { Traverse.Create(instance).Field(fieldName).SetValue(value); return true; } catch { return false; } } private static bool TrySetProperty(object instance, string propertyName, object value) { if (instance == null || string.IsNullOrEmpty(propertyName)) { return false; } try { Traverse.Create(instance).Property(propertyName, (object[])null).SetValue(value); return true; } catch { return false; } } private static PlayerFarming TryResolveInteractionPlayer(object interaction) { if (interaction == null) { return null; } PlayerFarming val = TryGetProperty(interaction, "playerFarming"); if ((Object)(object)val != (Object)null) { return val; } val = TryGetField(interaction, "playerFarming"); if ((Object)(object)val != (Object)null) { return val; } val = TryGetField(interaction, "_playerFarming"); if ((Object)(object)val != (Object)null) { return val; } return TryGetField(interaction, "k__BackingField"); } private static StateMachine TryResolveInteractionState(object interaction) { if (interaction == null) { return null; } StateMachine val = TryGetProperty(interaction, "state"); if ((Object)(object)val != (Object)null) { return val; } val = TryGetField(interaction, "state"); if ((Object)(object)val != (Object)null) { return val; } val = TryGetField(interaction, "_state"); if ((Object)(object)val != (Object)null) { return val; } return TryGetField(interaction, "k__BackingField"); } private static void TrySetInteractionPlayer(object interaction, PlayerFarming player) { if (interaction != null && !TrySetProperty(interaction, "playerFarming", player) && !TrySetField(interaction, "playerFarming", player) && !TrySetField(interaction, "_playerFarming", player)) { TrySetField(interaction, "k__BackingField", player); } } private static void TrySetInteractionState(object interaction, StateMachine state) { if (interaction != null && !TrySetProperty(interaction, "state", state) && !TrySetField(interaction, "state", state) && !TrySetField(interaction, "_state", state)) { TrySetField(interaction, "k__BackingField", state); } } } }