From 225b0d5584724334ca2bf64afc413687967e3844 Mon Sep 17 00:00:00 2001 From: WhistleWind <69230920+HumabHatterZed@users.noreply.github.com> Date: Tue, 10 Nov 2026 12:16:17 -0800 Subject: [PATCH 1/8] Add XML for the ReduceGemifiesX methods --- InscryptionAPI/Card/CostProperties.cs | 40 +++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/InscryptionAPI/Card/CostProperties.cs b/InscryptionAPI/Card/CostProperties.cs index d6f2d662..db960643 100644 --- a/InscryptionAPI/Card/CostProperties.cs +++ b/InscryptionAPI/Card/CostProperties.cs @@ -131,18 +131,58 @@ public static List ImprovedGemsCost(CardInfo instance) [HarmonyReversePatch, HarmonyPatch(typeof(CardInfo), nameof(CardInfo.EnergyCost), MethodType.Getter), MethodImpl(MethodImplOptions.NoInlining)] public static int OriginalEnergyCost(CardInfo __instance) { return 0; } + /// + /// Determines whether or not Gemified should reduce the blood cost on a multicost card. + /// + /// The gemified PlayableCard we're checking. + /// The PlayableCard's blood cost. Defaults to using the CardInfo's blood cost if null. + /// True if Gemified should reduce the blood cost by 1. + /// + /// Used for multicost cards to determine which cost Gemified should affect. + /// Priority from first choice to last: Energy, Bones, Mox, Blood + /// public static bool ReduceGemifiedBlood(PlayableCard card, int? bloodCost = null) { return (bloodCost ?? OriginalBloodCost(card.Info)) > 0 && !ReduceGemifiedEnergy(card) && !ReduceGemifiedBones(card) && !ReduceGemifiedMox(card); } + /// + /// Determines whether or not Gemified should reduce the gems cost on a multicost card. + /// + /// The gemified PlayableCard we're checking. + /// The PlayableCard's gems cost. Defaults to using the CardInfo's gems cost if null. + /// True if Gemified should reduce the gems cost by 1. + /// + /// Used for multicost cards to determine which cost Gemified should affect. + /// Priority from first choice to last: Energy, Bones, Mox, Blood + /// public static bool ReduceGemifiedMox(PlayableCard card, List gemsCost = null) { return (gemsCost?.Count ?? ImprovedGemsCost(card.Info).Count) > 0 && !ReduceGemifiedBones(card) && !ReduceGemifiedEnergy(card); } + /// + /// Determines whether or not Gemified should reduce the bone cost on a multicost card. + /// + /// The gemified PlayableCard we're checking. + /// The PlayableCard's bone cost. Defaults to using the CardInfo's bone cost if null. + /// True if Gemified should reduce the bone cost by 1. + /// + /// Used for multicost cards to determine which cost Gemified should affect. + /// Priority from first choice to last: Energy, Bones, Mox, Blood + /// public static bool ReduceGemifiedBones(PlayableCard card, int? bonesCost = null) { return (bonesCost ?? OriginalBonesCost(card.Info)) > 0 && !ReduceGemifiedEnergy(card); } + /// + /// Determines whether or not Gemified should reduce the energy cost on a multicost card. + /// + /// The gemified PlayableCard we're checking. + /// The PlayableCard's energy cost. Defaults to using the CardInfo's energy cost if null. + /// True if Gemified should reduce the energy cost by 1. + /// + /// Used for multicost cards to determine which cost Gemified should affect. + /// Priority from first choice to last: Energy, Bones, Mox, Blood + /// public static bool ReduceGemifiedEnergy(PlayableCard card, int? energyCost = null) { return (energyCost ?? OriginalEnergyCost(card.Info)) > 0; From 7dcd2687e24a562ac35047b35bf965b43e58ab5e Mon Sep 17 00:00:00 2001 From: WhistleWind <69230920+HumabHatterZed@users.noreply.github.com> Date: Tue, 10 Nov 2026 12:20:39 -0800 Subject: [PATCH 2/8] Add XML --- InscryptionAPI/Card/CardExtensionsCosts.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/InscryptionAPI/Card/CardExtensionsCosts.cs b/InscryptionAPI/Card/CardExtensionsCosts.cs index 3e452018..899a313f 100644 --- a/InscryptionAPI/Card/CardExtensionsCosts.cs +++ b/InscryptionAPI/Card/CardExtensionsCosts.cs @@ -105,11 +105,21 @@ public static List GemsCost(this PlayableCard card) return gemsCost; } + /// + /// Checks if the given PlayableCard is gemified in either its CardInfo or TemporaryMods. + /// + /// True if the PlayableCard is gemified. public static bool IsGemified(this PlayableCard card) => card.Info.Gemified || card.TemporaryMods.Exists((CardModificationInfo x) => x.gemify); + /// + /// Determines if the given PlayableCard's owner possesses a blue gem. Works for the opponent and player. + /// public static bool OwnerHasBlueGem(this PlayableCard card) { return card.OpponentCard ? OpponentGemsManager.Instance.HasGem(GemType.Blue) : ResourcesManager.Instance.HasGem(GemType.Blue); } + /// + /// Whether or not the given PlayableCard is affected by a blue gem and should have its cost reduced. + /// public static bool IsUsingBlueGem(this PlayableCard card) => card.IsGemified() && card.OwnerHasBlueGem(); /// From c767aea0fcd75b36b13b76a85731cfa970800bac Mon Sep 17 00:00:00 2001 From: WhistleWind <69230920+HumabHatterZed@users.noreply.github.com> Date: Tue, 10 Nov 2026 12:20:58 -0800 Subject: [PATCH 3/8] Privatise patches in internal patch class --- InscryptionAPI/Card/CostProperties.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/InscryptionAPI/Card/CostProperties.cs b/InscryptionAPI/Card/CostProperties.cs index db960643..877d85e4 100644 --- a/InscryptionAPI/Card/CostProperties.cs +++ b/InscryptionAPI/Card/CostProperties.cs @@ -193,7 +193,7 @@ public static bool ReduceGemifiedEnergy(PlayableCard card, int? energyCost = nul internal static class ChangeCardCostGetter { [HarmonyPatch(typeof(CardInfo), nameof(CardInfo.BloodCost), MethodType.Getter), HarmonyPrefix] - public static bool BloodCost(CardInfo __instance, ref int __result) + private static bool BloodCost(CardInfo __instance, ref int __result) { PlayableCard card = __instance.GetPlayableCard(); //Debug.Log($"{card != null}"); @@ -202,7 +202,7 @@ public static bool BloodCost(CardInfo __instance, ref int __result) } [HarmonyPatch(typeof(CardInfo), nameof(CardInfo.BonesCost), MethodType.Getter), HarmonyPrefix] - public static bool BoneCost(CardInfo __instance, ref int __result) + private static bool BoneCost(CardInfo __instance, ref int __result) { PlayableCard card = __instance.GetPlayableCard(); if (card == null) @@ -213,7 +213,7 @@ public static bool BoneCost(CardInfo __instance, ref int __result) } [HarmonyPatch(typeof(CardInfo), nameof(CardInfo.GemsCost), MethodType.Getter), HarmonyPrefix] - public static bool GemsCost(CardInfo __instance, ref List __result) + private static bool GemsCost(CardInfo __instance, ref List __result) { PlayableCard card = __instance.GetPlayableCard(); __result = card?.GemsCost() ?? CostProperties.ImprovedGemsCost(__instance); @@ -221,7 +221,7 @@ public static bool GemsCost(CardInfo __instance, ref List __result) } [HarmonyPatch(typeof(CardInfo), nameof(CardInfo.EnergyCost), MethodType.Getter), HarmonyPrefix] - public static bool EnergyCost(CardInfo __instance, ref int __result) + private static bool EnergyCost(CardInfo __instance, ref int __result) { PlayableCard card = __instance.GetPlayableCard(); __result = card?.EnergyCost ?? CostProperties.OriginalEnergyCost(__instance); @@ -229,7 +229,7 @@ public static bool EnergyCost(CardInfo __instance, ref int __result) } [HarmonyPatch(typeof(PlayableCard), nameof(PlayableCard.EnergyCost), MethodType.Getter), HarmonyPrefix] - public static bool DisableVanillaEnergyCost(PlayableCard __instance, ref int __result) + private static bool DisableVanillaEnergyCost(PlayableCard __instance, ref int __result) { // patch this to follow the same pattern as the other cost methods int energyCost = CostProperties.OriginalEnergyCost(__instance.Info); From e60a53d8c030b56222edb1c2b2c161425a7f7424 Mon Sep 17 00:00:00 2001 From: WhistleWind <69230920+HumabHatterZed@users.noreply.github.com> Date: Tue, 10 Nov 2026 12:54:02 -0800 Subject: [PATCH 4/8] Add missing XML --- InscryptionAPI/Card/CardManager.cs | 139 +++++++++++++++++++++++++++-- 1 file changed, 131 insertions(+), 8 deletions(-) diff --git a/InscryptionAPI/Card/CardManager.cs b/InscryptionAPI/Card/CardManager.cs index b4de2a81..cad99a63 100644 --- a/InscryptionAPI/Card/CardManager.cs +++ b/InscryptionAPI/Card/CardManager.cs @@ -13,6 +13,9 @@ namespace InscryptionAPI.Card; +/// +/// Class for managing adding, retrieving, tracking custom cards added via the API. +/// [HarmonyPatch] public static class CardManager { @@ -21,14 +24,50 @@ private class CardExt // Needs to be defined first so the implicit static constr public readonly Dictionary TypeMap = new(); public readonly Dictionary StringMap = new(); } + /// + /// Class for storing the data for custom portrait Sprites added via the API. + /// + /// + /// Only tracks custom API portraits like sacrificable steel trap, etc. + /// public class CardAltPortraits { + /// + /// Portrait sprite used when calling GetAlternatePortrait in Act 2. + /// public Sprite PixelAlternatePortrait = null; + /// + /// Portrait sprite used when the Steel Trap sigil is triggered. + /// + /// + /// Example: Leaping Trap + /// public Sprite SteelTrapPortrait = null; + /// + /// Portrait sprite used when the Steel Trap sigil is triggered in Act 2. + /// public Sprite PixelSteelTrapPortrait = null; + /// + /// Portrait sprite used when a card's shield breaks. + /// + /// + /// Example: Mud Turtle + /// public Sprite BrokenShieldPortrait = null; + /// + /// Portrait sprite used when a card's shield breaks in Act 2. + /// public Sprite PixelBrokenShieldPortrait = null; + /// + /// Portrait sprite used when a card on the board can be chosen as a sacrifice. + /// + /// + /// Example: Squirrel + /// public Sprite SacrificablePortrait = null; + /// + /// Portrait sprite used when a card on the board can be chosen as a sacrifice in Act 2. + /// public Sprite PixelSacrificablePortrait = null; } private static readonly ConditionalWeakTable CardExtensionProperties = new(); @@ -55,14 +94,16 @@ private static IEnumerable GetBaseGameCards() foreach (CardInfo card in Resources.LoadAll("Data/Cards")) { card.SetBaseGameCard(true); - if (card.name == "Squirrel" || card.name == "AquaSquirrel" || card.name == "Rabbit") + if (card.name == "Squirrel" || card.name == "AquaSquirrel" || card.name == "Rabbit") { card.SetAffectedByTidalLock(); - else if (card.name == "SkeletonParrot") + } + else if (card.name == "SkeletonParrot") { card.AddTribes(Tribe.Bird); - else if (card.name == "MudTurtle") + } + else if (card.name == "MudTurtle") { card.SetBrokenShieldPortrait(card.alternatePortrait); - - yield return card; + } + yield return card; } } @@ -200,7 +241,6 @@ static CardManager() /// /// A copy of all cards in the card pool. /// - /// . public static List AllCardsCopy { get; private set; } = BaseGameCards.ToList(); /// @@ -292,47 +332,130 @@ public static CardInfo New(string modPrefix, string name, string displayName, in } } + /// + /// Retrieves the dictionary of card extended properties associated with the given CardInfo. + /// + /// The CardInfo whose extended properties we wish to retrieve. + /// The extension property dictionary for the given CardInfo. Creates and returns an empty dictionary if none exists. public static Dictionary GetCardExtensionTable(this CardInfo card) => CardExtensionProperties.GetOrCreateValue(card).StringMap; internal static CardAltPortraits GetAltPortraits(this CardInfo card) => CardAlternatePortraits.GetOrCreateValue(card); + /// + /// Retrieves the Sprite for the CardInfo's alternate portrait in Act 2 if it exists. + /// + /// The CardInfo whose portrait we're retrieving. + /// The Sprite for the pixel alternate portrait or null if it doesn't exist. + /// + /// Pixel alternate portraits are added through the API; they are not a vanilla feature. + /// public static Sprite PixelAlternatePortrait(this CardInfo card) { return card.GetAltPortraits().PixelAlternatePortrait; } + /// + /// Retrieves the Sprite for the CardInfo's portrait used when Steel Trap activates if it exists. + /// + /// The CardInfo whose portrait we're retrieving. + /// The Sprite for the Steel Trap portrait or null if it doesn't exist. + /// + /// Steel Trap portraits are added through the API; they are not a vanilla feature. + /// public static Sprite SteelTrapPortrait(this CardInfo card) { return card.GetAltPortraits().SteelTrapPortrait; } + /// + /// Retrieves the Sprite for the CardInfo's portrait emission used when Steel Trap activates if it exists. + /// + /// The CardInfo whose portrait we're retrieving. + /// The Sprite for the Steel Trap portrait emission or null if it doesn't exist. + /// + /// Steel Trap portraits are added through the API; they are not a vanilla feature. + /// public static Sprite EmissiveSteelTrapPortrait(this CardInfo card) { return card.GetAltPortraits().SteelTrapPortrait.GetEmissionSprite(); } + /// + /// Retrieves the Sprite for the CardInfo's Act 2 portrait used when Steel Trap activates if it exists. + /// + /// The CardInfo whose portrait we're retrieving. + /// The Sprite for the pixel Steel Trap portrait or null if it doesn't exist. + /// + /// Pixel Steel Trap portraits are added through the API; they are not a vanilla feature. + /// public static Sprite PixelSteelTrapPortrait(this CardInfo card) { return card.GetAltPortraits().PixelSteelTrapPortrait; } - + /// + /// Retrieves the Sprite for the CardInfo's portrait used when a card's shield breaks if it exists. + /// + /// The CardInfo whose portrait we're retrieving. + /// The Sprite for the broken shield portrait or null if it doesn't exist. + /// + /// Broken shield portraits are added through the API; they are not a vanilla feature. + /// public static Sprite BrokenShieldPortrait(this CardInfo card) { return card.GetAltPortraits().BrokenShieldPortrait; } + /// + /// Retrieves the Sprite for the CardInfo's portrait emission used when a card's shield breaks if it exists. + /// + /// The CardInfo whose portrait we're retrieving. + /// The Sprite for the broken shield portrait emission or null if it doesn't exist. + /// + /// Broken shield portraits are added through the API; they are not a vanilla feature. + /// public static Sprite EmissiveBrokenShieldPortrait(this CardInfo card) { return card.GetAltPortraits().BrokenShieldPortrait.GetEmissionSprite(); } + /// + /// Retrieves the Sprite for the CardInfo's Act 2 portrait used when a card's shield breaks if it exists. + /// + /// The CardInfo whose portrait we're retrieving. + /// The Sprite for the pixel broken shield portrait or null if it doesn't exist. + /// + /// Pixel broken shield portraits are added through the API; they are not a vanilla feature. + /// public static Sprite PixelBrokenShieldPortrait(this CardInfo card) { return card.GetAltPortraits().PixelBrokenShieldPortrait; } - + /// + /// Retrieves the Sprite for the CardInfo's portrait used when a card on the board can be sacrificed if it exists. + /// + /// The CardInfo whose portrait we're retrieving. + /// The Sprite for the sacrificable portrait or null if it doesn't exist. + /// + /// Sacrificable portraits are added through the API; they are not a vanilla feature. + /// public static Sprite SacrificablePortrait(this CardInfo card) { return card.GetAltPortraits().SacrificablePortrait; } + /// + /// Retrieves the Sprite for the CardInfo's portrait emission used when a card on the board can be sacrificed if it exists. + /// + /// The CardInfo whose portrait we're retrieving. + /// The Sprite for the sacrificable portrait emission or null if it doesn't exist. + /// + /// Sacrificable portraits are added through the API; they are not a vanilla feature. + /// public static Sprite EmissiveSacrificablePortrait(this CardInfo card) { return card.GetAltPortraits().SacrificablePortrait.GetEmissionSprite(); } + /// + /// Retrieves the Sprite for the CardInfo's Act 2 portrait used when a card on the board can be sacrificed if it exists. + /// + /// The CardInfo whose portrait we're retrieving. + /// The Sprite for the pixel sacrificable portrait or null if it doesn't exist. + /// + /// Pixel sacrificable portraits are added through the API; they are not a vanilla feature. + /// public static Sprite PixelSacrificablePortrait(this CardInfo card) { return card.GetAltPortraits().PixelSacrificablePortrait; From 85de6193be2211b54ae65feba7ed6556cf732918 Mon Sep 17 00:00:00 2001 From: WhistleWind <69230920+HumabHatterZed@users.noreply.github.com> Date: Tue, 10 Nov 2026 12:59:12 -0800 Subject: [PATCH 5/8] Add some XML --- InscryptionAPI/Card/CardModificationInfoManager.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/InscryptionAPI/Card/CardModificationInfoManager.cs b/InscryptionAPI/Card/CardModificationInfoManager.cs index 765adb38..abcf0641 100644 --- a/InscryptionAPI/Card/CardModificationInfoManager.cs +++ b/InscryptionAPI/Card/CardModificationInfoManager.cs @@ -6,6 +6,10 @@ namespace InscryptionAPI.Card; +/// +/// Class for managing special CardModificationInfos. +/// These include persistent extended properties and custom costs. +/// [HarmonyPatch] public static class CardModificationInfoManager { @@ -69,6 +73,9 @@ internal static Dictionary GetCardModExtensionTable(this CardMod return exp.StringMap; } + /// + /// Re-executes events and rebuilds the special CardModificationInfo pool. + /// public static void SyncCardMods() { // Re-add persistent properties From eca236ccf85686e8afb01f502b2f705a36a890a0 Mon Sep 17 00:00:00 2001 From: WhistleWind <69230920+HumabHatterZed@users.noreply.github.com> Date: Tue, 10 Nov 2026 13:26:38 -0800 Subject: [PATCH 6/8] More XML --- InscryptionAPI/Costs/CardCostManager.cs | 46 ++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/InscryptionAPI/Costs/CardCostManager.cs b/InscryptionAPI/Costs/CardCostManager.cs index 743ca780..fe9ddb46 100644 --- a/InscryptionAPI/Costs/CardCostManager.cs +++ b/InscryptionAPI/Costs/CardCostManager.cs @@ -13,6 +13,9 @@ namespace InscryptionAPI.CardCosts; +/// +/// Class for managing custom card costs. +/// [HarmonyPatch] public static class CardCostManager { @@ -91,6 +94,11 @@ public class FullCardCost /// public Func GetRewardBackTexture = null; + /// + /// Texture used if this card can show up in a card cost choice node. + /// + /// + /// public Texture RewardBackTexture(int amount) { if (GetRewardBackTexture == null) @@ -183,6 +191,10 @@ public FullCardCost(string modGUID, string costName, Type costBehaviour, TypeManager.Add(costName, costBehaviour); } + /// + /// Creates a deep clone of this FullCardCost. + /// + /// A new clone of this FullCardCost. public FullCardCost Clone() { FullCardCost retval = new( @@ -202,18 +214,29 @@ static CardCostManager() SyncCustomCostList(); }; } - + /// + /// A list of all card costs registered with the API. + /// public static List AllCustomCosts { get; private set; } = new(); internal readonly static ObservableCollection NewCosts = new(); + /// + /// This event runs every time the card card list is resynced. By adding listeners to this event, you can modify card costs that have been added to the list after your mod was loaded. + /// public static event Func, List> ModifyCustomCostList; // you don't have the [colour] gem for that. // no [colour] gem on the table? then you can't play it. // you need at least one [colour] gem on the board in order to play that [card] // play the required [colour] gem... then you can play that. + /// + /// The Hint used to tell the player when they cannot play a card that costs multiple gems of the same colour. + /// public static HintsHandler.Hint notEnoughSameColourGemsHint = new("Hint_NotEnoughSameColourGemsHint", 2); + /// + /// The DialogueEvent that is played when a player cannot play a card that costs multiple gems of the same colour. + /// public static DialogueEvent notEnoghSameColourGemsEvent = DialogueManager.GenerateEvent( InscryptionAPIPlugin.ModGUID, "Hint_NotEnoughSameColourGemsHint", new() { "You don't have enough [v:1] gems for that." }, @@ -223,16 +246,37 @@ static CardCostManager() new() { "You need more [v:1] gems on the board in order to play that [v:0]."}, new() { "Play the required [v:1] gems... then you can play that." } }); + /// + /// Re-executes events and rebuilds the card cost pool. + /// public static void SyncCustomCostList() { AllCustomCosts = NewCosts.Select(a => a.Clone()).ToList(); AllCustomCosts = ModifyCustomCostList?.Invoke(AllCustomCosts) ?? AllCustomCosts; } + /// + /// Retrieves the FullCardCost object associated with the given CustomCardCost class Type. + /// + /// Collection of FullCardCost objects to search through. + /// Type of the CustomCardCost to find the FUllCardCost object of. + /// The FullCardCost associated with the given Type, or null if it cannot be found. + /// + /// Intended to be used with the AllCustomCosts getter as a way of searching through all card costs added by the API. + /// public static FullCardCost CostByBehaviour(this IEnumerable customCosts, Type costBehaviour) { return customCosts.FirstOrDefault(x => x.CostBehaviour == costBehaviour); } + /// + /// Registers a new custom card cost with the API. + /// + /// The GUID of the mod adding this card cost. + /// The internal name of this card cost. + /// The type of the CustomCardCost class for this card cost. + /// The function used to determine what texture to display on cards with this cost. + /// The function used to determine what pixel texture to display on cards with this cost. + /// The FullCardCost object containing the new custom card cost's data. public static FullCardCost Register(string modGUID, string costName, Type costBehaviour, Func getCostTexture, Func getPixelCostTexture) { From 383b490d76ef984f3b27d1c6263e1cd57d50ba66 Mon Sep 17 00:00:00 2001 From: WhistleWind <69230920+HumabHatterZed@users.noreply.github.com> Date: Tue, 10 Nov 2026 13:49:24 -0800 Subject: [PATCH 7/8] Replace call to card.Info.BloodCost to card.BloodCost() --- InscryptionAPI/Card/CardExtensionsCosts.cs | 3 ++- InscryptionAPI/Costs/CardCostManager.cs | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/InscryptionAPI/Card/CardExtensionsCosts.cs b/InscryptionAPI/Card/CardExtensionsCosts.cs index 899a313f..36ea9330 100644 --- a/InscryptionAPI/Card/CardExtensionsCosts.cs +++ b/InscryptionAPI/Card/CardExtensionsCosts.cs @@ -31,7 +31,7 @@ public static PlayableCard GetPlayableCard(this CardInfo cardInfo) /// public static int BloodCost(this PlayableCard card) { - //Debug.Log($"{card != null} {card?.Info != null} [{card?.GetType()}] {(card as DiskCardGame.Card)?.Info != null}"); + //InscryptionAPIPlugin.Logger.LogInfo($"{card != null} {card?.Info != null} [{card?.GetType()}] {(card as DiskCardGame.Card)?.Info != null}"); if (card != null && card.Info != null) { int originalBloodCost = CostProperties.CostProperties.OriginalBloodCost(card.Info); @@ -42,6 +42,7 @@ public static int BloodCost(this PlayableCard card) foreach (CardModificationInfo mod in card.TemporaryMods) originalBloodCost += mod.bloodCostAdjustment; + //InscryptionAPIPlugin.Logger.LogInfo(originalBloodCost); return originalBloodCost; } diff --git a/InscryptionAPI/Costs/CardCostManager.cs b/InscryptionAPI/Costs/CardCostManager.cs index fe9ddb46..cf3412b6 100644 --- a/InscryptionAPI/Costs/CardCostManager.cs +++ b/InscryptionAPI/Costs/CardCostManager.cs @@ -2,8 +2,10 @@ using GBC; using HarmonyLib; using InscryptionAPI.Card; +using InscryptionAPI.Card.CostProperties; using InscryptionAPI.Dialogue; using InscryptionAPI.Guid; +using InscryptionAPI.Helpers; using Sirenix.Utilities; using System.Collections; using System.Collections.ObjectModel; @@ -562,7 +564,19 @@ private static bool MultipleSameColourMoxSupport(PlayableCard card) private static IEnumerable FixDialogueSoftlock(IEnumerable instructions) { List codes = new(instructions); - //codes.LogCodeInscryptions(); + //codes.LogCodeInstructions(); + + // this part's for fixing blood cost nonsense I encountered when dealing with duplicate CardInfos + // it just changes the call to card.Info.BloodCost to card.BloodCost() + // and avoiding the janky dynamic cost find playablecard nonsenseseses + int bloodCostIdx = codes.FindIndex(x => x.opcode == OpCodes.Callvirt && x.operand.ToString() == "Int32 get_BloodCost()"); + if (bloodCostIdx > 0) { + bloodCostIdx--; + codes.RemoveRange(bloodCostIdx, 4); + MethodInfo playableCardBloodCost = AccessTools.Method(typeof(CardExtensions), nameof(CardExtensions.BloodCost), + new Type[] { typeof(PlayableCard) }); + codes.Insert(bloodCostIdx, new CodeInstruction(OpCodes.Callvirt, playableCardBloodCost)); + } int methodIndex = codes.FindIndex(x => x.opcode == OpCodes.Callvirt && x.operand.ToString() == "System.Collections.IEnumerator PlayCardOnSlot(DiskCardGame.PlayableCard, DiskCardGame.CardSlot)"); if (methodIndex > 0) From d4fd85eda0ca63dec7042f791dd5eeeae6eeaee2 Mon Sep 17 00:00:00 2001 From: Chaosyr Date: Tue, 10 Nov 2026 18:50:42 -0500 Subject: [PATCH 8/8] Typo Fix --- InscryptionAPI/Costs/CardCostManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/InscryptionAPI/Costs/CardCostManager.cs b/InscryptionAPI/Costs/CardCostManager.cs index cf3412b6..901ccf4b 100644 --- a/InscryptionAPI/Costs/CardCostManager.cs +++ b/InscryptionAPI/Costs/CardCostManager.cs @@ -567,7 +567,7 @@ private static IEnumerable FixDialogueSoftlock(IEnumerable x.opcode == OpCodes.Callvirt && x.operand.ToString() == "Int32 get_BloodCost()"); if (bloodCostIdx > 0) { @@ -878,4 +878,4 @@ public virtual IEnumerator OnPlayed(int cardCost, PlayableCard playableCard) { yield break; } -} \ No newline at end of file +}