using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Logging; using DiskCardGame; using HarmonyLib; using InscryptionAPI.Card; using InscryptionAPI.Helpers; using OLD_SA.Dialogue; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("OldSa_Infinite_sigil")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("OldSa_Infinite_sigil")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("29dc7318-f797-403f-b9cc-8aa737517d63")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.0")] namespace OLD_SA.Infinite; public static class InfiniteAPI { public static FullAbility ability; public static void Init() { AbilityInfo val = ScriptableObject.CreateInstance(); ((Object)val).name = "Infinite"; val.rulebookName = "Infinite"; val.metaCategories = new List { (AbilityMetaCategory)0 }; val.powerLevel = 5; val.opponentUsable = false; val.canStack = false; Texture imageAsTexture = (Texture)(object)TextureHelper.GetImageAsTexture("OldSa_Infinite.png", (FilterMode)0); FieldInfo field = typeof(AbilityInfo).GetField("rulebookDescription", BindingFlags.Instance | BindingFlags.NonPublic); if (field != null) { field.SetValue(val, "At the start of each turn, [creature] regains lost sigils."); } ability = AbilityManager.Add("OLD_SA", val, typeof(InfiniteBehaviour), imageAsTexture); } } public class InfiniteBehaviour : AbilityBehaviour { public override Ability Ability => InfiniteAPI.ability.Id; public override bool RespondsToUpkeep(bool playerUpkeep) { return false; } public override IEnumerator OnUpkeep(bool playerUpkeep) { yield break; } } [HarmonyPatch(typeof(GlobalTriggerHandler), "TriggerSequence")] public static class InfiniteTriggerSequencePatch { private class AbilitySnapshot { public Ability Ability; public bool IsTemporary; public CardModificationInfo TemporaryMod; public AbilitySnapshot(Ability ability, bool isTemporary, CardModificationInfo temporaryMod) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) Ability = ability; IsTemporary = isTemporary; TemporaryMod = temporaryMod; } } private class LostAbilityData { public Ability Ability; public CardModificationInfo TemporaryMod; public bool IsTemporary => TemporaryMod != null; public LostAbilityData(Ability ability, CardModificationInfo temporaryMod) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) Ability = ability; TemporaryMod = temporaryMod; } } private static readonly Dictionary> LostAbilities = new Dictionary>(); private static bool restoring; private static bool? lastUpkeepSide; [HarmonyPostfix] public static IEnumerator Postfix(IEnumerator result, GlobalTriggerHandler __instance, Trigger trigger, TriggerReceiver receiver, object[] otherArgs) { //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) if ((int)trigger == 0 && !restoring) { bool playerUpkeep = otherArgs != null && otherArgs.Length != 0 && otherArgs[0] is bool && (bool)otherArgs[0]; if (!lastUpkeepSide.HasValue || lastUpkeepSide.Value != playerUpkeep) { lastUpkeepSide = playerUpkeep; yield return RestoreAllForUpkeep(playerUpkeep); } yield return result; yield break; } if (restoring) { yield return result; yield break; } Dictionary> before = CaptureAllInfiniteCards(); yield return result; Dictionary> after = CaptureAllInfiniteCards(); foreach (KeyValuePair> entry in before) { PlayableCard card = entry.Key; if ((Object)(object)card == (Object)null || card.Dead) { continue; } List beforeAbilities = entry.Value; if (!after.TryGetValue(card, out var afterAbilities)) { afterAbilities = new List(); } foreach (AbilitySnapshot previous in beforeAbilities) { if (!ContainsAbility(afterAbilities, previous.Ability)) { AddLostAbility(card, previous); } } afterAbilities = null; } } private static Dictionary> CaptureAllInfiniteCards() { Dictionary> dictionary = new Dictionary>(); if (InfiniteAPI.ability == null || (Object)(object)Singleton.Instance == (Object)null) { return dictionary; } foreach (CardSlot item in Singleton.Instance.PlayerSlotsCopy) { if (!((Object)(object)item == (Object)null) && !((Object)(object)item.Card == (Object)null) && !item.Card.Dead) { PlayableCard card = item.Card; if (HasInfinite(card)) { dictionary[card] = CaptureRuntimeAbilities(card); } } } foreach (CardSlot item2 in Singleton.Instance.OpponentSlotsCopy) { if (!((Object)(object)item2 == (Object)null) && !((Object)(object)item2.Card == (Object)null) && !item2.Card.Dead) { PlayableCard card2 = item2.Card; if (HasInfinite(card2)) { dictionary[card2] = CaptureRuntimeAbilities(card2); } } } return dictionary; } private static bool HasInfinite(PlayableCard card) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)card == (Object)null || InfiniteAPI.ability == null) { return false; } AbilityBehaviour[] components = ((Component)card).GetComponents(); AbilityBehaviour[] array = components; foreach (AbilityBehaviour val in array) { if ((Object)(object)val != (Object)null && val.Ability == InfiniteAPI.ability.Id) { return true; } } return false; } private static List CaptureRuntimeAbilities(PlayableCard card) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) List list = new List(); if ((Object)(object)card == (Object)null) { return list; } AbilityBehaviour[] components = ((Component)card).GetComponents(); AbilityBehaviour[] array = components; foreach (AbilityBehaviour val in array) { if (!((Object)(object)val == (Object)null)) { Ability ability = val.Ability; if ((Object)(object)((Card)card).Info != (Object)null && ((Card)card).Info.Abilities.Contains(ability)) { list.Add(new AbilitySnapshot(ability, isTemporary: false, null)); continue; } CardModificationInfo temporaryMod = FindTemporaryMod(card, ability); list.Add(new AbilitySnapshot(ability, isTemporary: true, temporaryMod)); } } return list; } private static CardModificationInfo FindTemporaryMod(PlayableCard card, Ability ability) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)card == (Object)null) { return null; } foreach (CardModificationInfo temporaryMod in card.TemporaryMods) { if (temporaryMod == null || !temporaryMod.abilities.Contains(ability)) { continue; } return temporaryMod; } return null; } private static bool ContainsAbility(List abilities, Ability ability) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) foreach (AbilitySnapshot ability2 in abilities) { if (ability2.Ability == ability) { return true; } } return false; } private static void AddLostAbility(PlayableCard card, AbilitySnapshot lost) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)card == (Object)null) { return; } if (!LostAbilities.ContainsKey(card)) { LostAbilities.Add(card, new List()); } List list = LostAbilities[card]; foreach (LostAbilityData item in list) { if (item.Ability == lost.Ability) { return; } } list.Add(new LostAbilityData(lost.Ability, lost.TemporaryMod)); } private static IEnumerator RestoreAllForUpkeep(bool playerUpkeep) { if (LostAbilities.Count == 0) { yield break; } restoring = true; try { Singleton.Instance.SwitchToView((View)4, false, false); yield return (object)new WaitForSeconds(0.1f); List>> pending = new List>>(LostAbilities); foreach (KeyValuePair> entry in pending) { PlayableCard card = entry.Key; if ((Object)(object)card == (Object)null || card.Dead || (Object)(object)card.Slot == (Object)null || card.OpponentCard != !playerUpkeep) { continue; } List lost = entry.Value; if (lost == null || lost.Count == 0) { continue; } yield return RevealCard(card); foreach (LostAbilityData data in lost) { if ((Object)(object)card == (Object)null || card.Dead) { break; } if (card.HasAbility(data.Ability)) { continue; } if (!data.IsTemporary) { card.TriggerHandler.AddAbility(data.Ability); continue; } CardModificationInfo mod = CloneTemporaryMod(data.TemporaryMod, data.Ability); if (mod != null) { card.AddTemporaryMod(mod); } } ((Card)card).RenderCard(); card.OnStatsChanged(); card.UpdateFaceUpOnBoardEffects(); yield return SigilDialogueAPI.ShowFirstTime("Infinite", "It never knows contentment.", card); yield return (object)new WaitForSeconds(0.25f); } } finally { LostAbilities.Clear(); restoring = false; } } private static IEnumerator RevealCard(PlayableCard card) { if (!((Object)(object)card == (Object)null) && !card.Dead && ((Card)card).FaceDown) { ((Card)card).SetFaceDown(false, false); yield return (object)new WaitForSeconds(0.15f); } } private static CardModificationInfo CloneTemporaryMod(CardModificationInfo source, Ability ability) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) if (source == null) { CardModificationInfo val = new CardModificationInfo(); val.abilities = new List { ability }; return val; } CardModificationInfo val2 = new CardModificationInfo(); val2.attackAdjustment = source.attackAdjustment; val2.healthAdjustment = source.healthAdjustment; val2.bloodCostAdjustment = source.bloodCostAdjustment; val2.bonesCostAdjustment = source.bonesCostAdjustment; val2.energyCostAdjustment = source.energyCostAdjustment; val2.gemify = source.gemify; val2.fromOverclock = source.fromOverclock; val2.singletonId = source.singletonId; val2.abilities = new List { ability }; foreach (Ability negateAbility in source.negateAbilities) { val2.negateAbilities.Add(negateAbility); } return val2; } } [BepInPlugin("OLD_SA.Infinite", "OLD SA Infinite", "1.0.0")] public class Plugin : BaseUnityPlugin { private Harmony harmony; private unsafe void Awake() { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Expected O, but got Unknown ((BaseUnityPlugin)this).Logger.LogInfo((object)"[OLD SA Infinite] Loading..."); InfiniteAPI.Init(); if (InfiniteAPI.ability == null) { ((BaseUnityPlugin)this).Logger.LogError((object)"[OLD SA Infinite] Failed to register Infinite ability!"); return; } ManualLogSource logger = ((BaseUnityPlugin)this).Logger; Ability id = InfiniteAPI.ability.Id; logger.LogInfo((object)("[OLD SA Infinite] Infinite ability registered. ID = " + ((object)(*(Ability*)(&id))/*cast due to .constrained prefix*/).ToString())); harmony = new Harmony("OLD_SA.Infinite"); harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"[OLD SA Infinite] Harmony patches applied."); ((BaseUnityPlugin)this).Logger.LogInfo((object)"[OLD SA Infinite] Loaded successfully."); } private void OnDestroy() { if (harmony != null) { harmony.UnpatchSelf(); harmony = null; } ((BaseUnityPlugin)this).Logger.LogInfo((object)"[OLD SA Infinite] Unloaded."); } }