Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion InscryptionAPI/Card/CardExtensionsCosts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public static PlayableCard GetPlayableCard(this CardInfo cardInfo)
/// </summary>
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);
Expand All @@ -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;
}

Expand Down Expand Up @@ -105,11 +106,21 @@ public static List<GemType> GemsCost(this PlayableCard card)
return gemsCost;
}

/// <summary>
/// Checks if the given PlayableCard is gemified in either its CardInfo or TemporaryMods.
/// </summary>
/// <returns>True if the PlayableCard is gemified.</returns>
public static bool IsGemified(this PlayableCard card) => card.Info.Gemified || card.TemporaryMods.Exists((CardModificationInfo x) => x.gemify);
/// <summary>
/// Determines if the given PlayableCard's owner possesses a blue gem. Works for the opponent and player.
/// </summary>
public static bool OwnerHasBlueGem(this PlayableCard card)
{
return card.OpponentCard ? OpponentGemsManager.Instance.HasGem(GemType.Blue) : ResourcesManager.Instance.HasGem(GemType.Blue);
}
/// <summary>
/// Whether or not the given PlayableCard is affected by a blue gem and should have its cost reduced.
/// </summary>
public static bool IsUsingBlueGem(this PlayableCard card) => card.IsGemified() && card.OwnerHasBlueGem();

/// <summary>
Expand Down
139 changes: 131 additions & 8 deletions InscryptionAPI/Card/CardManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@

namespace InscryptionAPI.Card;

/// <summary>
/// Class for managing adding, retrieving, tracking custom cards added via the API.
/// </summary>
[HarmonyPatch]
public static class CardManager
{
Expand All @@ -21,14 +24,50 @@ private class CardExt // Needs to be defined first so the implicit static constr
public readonly Dictionary<Type, object> TypeMap = new();
public readonly Dictionary<string, string> StringMap = new();
}
/// <summary>
/// Class for storing the data for custom portrait Sprites added via the API.
/// </summary>
/// <remarks>
/// Only tracks custom API portraits like sacrificable steel trap, etc.
/// </remarks>
public class CardAltPortraits
{
/// <summary>
/// Portrait sprite used when calling GetAlternatePortrait in Act 2.
/// </summary>
public Sprite PixelAlternatePortrait = null;
/// <summary>
/// Portrait sprite used when the Steel Trap sigil is triggered.
/// </summary>
/// <remarks>
/// Example: Leaping Trap
/// </remarks>
public Sprite SteelTrapPortrait = null;
/// <summary>
/// Portrait sprite used when the Steel Trap sigil is triggered in Act 2.
/// </summary>
public Sprite PixelSteelTrapPortrait = null;
/// <summary>
/// Portrait sprite used when a card's shield breaks.
/// </summary>
/// <remarks>
/// Example: Mud Turtle
/// </remarks>
public Sprite BrokenShieldPortrait = null;
/// <summary>
/// Portrait sprite used when a card's shield breaks in Act 2.
/// </summary>
public Sprite PixelBrokenShieldPortrait = null;
/// <summary>
/// Portrait sprite used when a card on the board can be chosen as a sacrifice.
/// </summary>
/// <remarks>
/// Example: Squirrel
/// </remarks>
public Sprite SacrificablePortrait = null;
/// <summary>
/// Portrait sprite used when a card on the board can be chosen as a sacrifice in Act 2.
/// </summary>
public Sprite PixelSacrificablePortrait = null;
}
private static readonly ConditionalWeakTable<CardInfo, CardExt> CardExtensionProperties = new();
Expand All @@ -55,14 +94,16 @@ private static IEnumerable<CardInfo> GetBaseGameCards()
foreach (CardInfo card in Resources.LoadAll<CardInfo>("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;
}
}

Expand Down Expand Up @@ -200,7 +241,6 @@ static CardManager()
/// <summary>
/// A copy of all cards in the card pool.
/// </summary>
/// <returns>.</returns>
public static List<CardInfo> AllCardsCopy { get; private set; } = BaseGameCards.ToList();

/// <summary>
Expand Down Expand Up @@ -292,47 +332,130 @@ public static CardInfo New(string modPrefix, string name, string displayName, in
}
}

/// <summary>
/// Retrieves the dictionary of card extended properties associated with the given CardInfo.
/// </summary>
/// <param name="card">The CardInfo whose extended properties we wish to retrieve.</param>
/// <returns>The extension property dictionary for the given CardInfo. Creates and returns an empty dictionary if none exists.</returns>
public static Dictionary<string, string> GetCardExtensionTable(this CardInfo card) => CardExtensionProperties.GetOrCreateValue(card).StringMap;
internal static CardAltPortraits GetAltPortraits(this CardInfo card) => CardAlternatePortraits.GetOrCreateValue(card);

/// <summary>
/// Retrieves the Sprite for the CardInfo's alternate portrait in Act 2 if it exists.
/// </summary>
/// <param name="card">The CardInfo whose portrait we're retrieving.</param>
/// <returns>The Sprite for the pixel alternate portrait or null if it doesn't exist.</returns>
/// <remarks>
/// Pixel alternate portraits are added through the API; they are not a vanilla feature.
/// </remarks>
public static Sprite PixelAlternatePortrait(this CardInfo card)
{
return card.GetAltPortraits().PixelAlternatePortrait;
}
/// <summary>
/// Retrieves the Sprite for the CardInfo's portrait used when Steel Trap activates if it exists.
/// </summary>
/// <param name="card">The CardInfo whose portrait we're retrieving.</param>
/// <returns>The Sprite for the Steel Trap portrait or null if it doesn't exist.</returns>
/// <remarks>
/// Steel Trap portraits are added through the API; they are not a vanilla feature.
/// </remarks>
public static Sprite SteelTrapPortrait(this CardInfo card)
{
return card.GetAltPortraits().SteelTrapPortrait;
}
/// <summary>
/// Retrieves the Sprite for the CardInfo's portrait emission used when Steel Trap activates if it exists.
/// </summary>
/// <param name="card">The CardInfo whose portrait we're retrieving.</param>
/// <returns>The Sprite for the Steel Trap portrait emission or null if it doesn't exist.</returns>
/// <remarks>
/// Steel Trap portraits are added through the API; they are not a vanilla feature.
/// </remarks>
public static Sprite EmissiveSteelTrapPortrait(this CardInfo card)
{
return card.GetAltPortraits().SteelTrapPortrait.GetEmissionSprite();
}
/// <summary>
/// Retrieves the Sprite for the CardInfo's Act 2 portrait used when Steel Trap activates if it exists.
/// </summary>
/// <param name="card">The CardInfo whose portrait we're retrieving.</param>
/// <returns>The Sprite for the pixel Steel Trap portrait or null if it doesn't exist.</returns>
/// <remarks>
/// Pixel Steel Trap portraits are added through the API; they are not a vanilla feature.
/// </remarks>
public static Sprite PixelSteelTrapPortrait(this CardInfo card)
{
return card.GetAltPortraits().PixelSteelTrapPortrait;
}

/// <summary>
/// Retrieves the Sprite for the CardInfo's portrait used when a card's shield breaks if it exists.
/// </summary>
/// <param name="card">The CardInfo whose portrait we're retrieving.</param>
/// <returns>The Sprite for the broken shield portrait or null if it doesn't exist.</returns>
/// <remarks>
/// Broken shield portraits are added through the API; they are not a vanilla feature.
/// </remarks>
public static Sprite BrokenShieldPortrait(this CardInfo card)
{
return card.GetAltPortraits().BrokenShieldPortrait;
}
/// <summary>
/// Retrieves the Sprite for the CardInfo's portrait emission used when a card's shield breaks if it exists.
/// </summary>
/// <param name="card">The CardInfo whose portrait we're retrieving.</param>
/// <returns>The Sprite for the broken shield portrait emission or null if it doesn't exist.</returns>
/// <remarks>
/// Broken shield portraits are added through the API; they are not a vanilla feature.
/// </remarks>
public static Sprite EmissiveBrokenShieldPortrait(this CardInfo card)
{
return card.GetAltPortraits().BrokenShieldPortrait.GetEmissionSprite();
}
/// <summary>
/// Retrieves the Sprite for the CardInfo's Act 2 portrait used when a card's shield breaks if it exists.
/// </summary>
/// <param name="card">The CardInfo whose portrait we're retrieving.</param>
/// <returns>The Sprite for the pixel broken shield portrait or null if it doesn't exist.</returns>
/// <remarks>
/// Pixel broken shield portraits are added through the API; they are not a vanilla feature.
/// </remarks>
public static Sprite PixelBrokenShieldPortrait(this CardInfo card)
{
return card.GetAltPortraits().PixelBrokenShieldPortrait;
}

/// <summary>
/// Retrieves the Sprite for the CardInfo's portrait used when a card on the board can be sacrificed if it exists.
/// </summary>
/// <param name="card">The CardInfo whose portrait we're retrieving.</param>
/// <returns>The Sprite for the sacrificable portrait or null if it doesn't exist.</returns>
/// <remarks>
/// Sacrificable portraits are added through the API; they are not a vanilla feature.
/// </remarks>
public static Sprite SacrificablePortrait(this CardInfo card)
{
return card.GetAltPortraits().SacrificablePortrait;
}
/// <summary>
/// Retrieves the Sprite for the CardInfo's portrait emission used when a card on the board can be sacrificed if it exists.
/// </summary>
/// <param name="card">The CardInfo whose portrait we're retrieving.</param>
/// <returns>The Sprite for the sacrificable portrait emission or null if it doesn't exist.</returns>
/// <remarks>
/// Sacrificable portraits are added through the API; they are not a vanilla feature.
/// </remarks>
public static Sprite EmissiveSacrificablePortrait(this CardInfo card)
{
return card.GetAltPortraits().SacrificablePortrait.GetEmissionSprite();
}
/// <summary>
/// Retrieves the Sprite for the CardInfo's Act 2 portrait used when a card on the board can be sacrificed if it exists.
/// </summary>
/// <param name="card">The CardInfo whose portrait we're retrieving.</param>
/// <returns>The Sprite for the pixel sacrificable portrait or null if it doesn't exist.</returns>
/// <remarks>
/// Pixel sacrificable portraits are added through the API; they are not a vanilla feature.
/// </remarks>
public static Sprite PixelSacrificablePortrait(this CardInfo card)
{
return card.GetAltPortraits().PixelSacrificablePortrait;
Expand Down
7 changes: 7 additions & 0 deletions InscryptionAPI/Card/CardModificationInfoManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@

namespace InscryptionAPI.Card;

/// <summary>
/// Class for managing special CardModificationInfos.
/// These include persistent extended properties and custom costs.
/// </summary>
[HarmonyPatch]
public static class CardModificationInfoManager
{
Expand Down Expand Up @@ -69,6 +73,9 @@ internal static Dictionary<string, string> GetCardModExtensionTable(this CardMod

return exp.StringMap;
}
/// <summary>
/// Re-executes events and rebuilds the special CardModificationInfo pool.
/// </summary>
public static void SyncCardMods()
{
// Re-add persistent properties
Expand Down
50 changes: 45 additions & 5 deletions InscryptionAPI/Card/CostProperties.cs
Original file line number Diff line number Diff line change
Expand Up @@ -131,18 +131,58 @@ public static List<GemType> ImprovedGemsCost(CardInfo instance)
[HarmonyReversePatch, HarmonyPatch(typeof(CardInfo), nameof(CardInfo.EnergyCost), MethodType.Getter), MethodImpl(MethodImplOptions.NoInlining)]
public static int OriginalEnergyCost(CardInfo __instance) { return 0; }

/// <summary>
/// Determines whether or not Gemified should reduce the blood cost on a multicost card.
/// </summary>
/// <param name="card">The gemified PlayableCard we're checking.</param>
/// <param name="bloodCost">The PlayableCard's blood cost. Defaults to using the CardInfo's blood cost if null.</param>
/// <returns>True if Gemified should reduce the blood cost by 1.</returns>
/// <remarks>
/// Used for multicost cards to determine which cost Gemified should affect.
/// Priority from first choice to last: Energy, Bones, Mox, Blood
/// </remarks>
public static bool ReduceGemifiedBlood(PlayableCard card, int? bloodCost = null)
{
return (bloodCost ?? OriginalBloodCost(card.Info)) > 0 && !ReduceGemifiedEnergy(card) && !ReduceGemifiedBones(card) && !ReduceGemifiedMox(card);
}
/// <summary>
/// Determines whether or not Gemified should reduce the gems cost on a multicost card.
/// </summary>
/// <param name="card">The gemified PlayableCard we're checking.</param>
/// <param name="gemsCost">The PlayableCard's gems cost. Defaults to using the CardInfo's gems cost if null.</param>
/// <returns>True if Gemified should reduce the gems cost by 1.</returns>
/// <remarks>
/// Used for multicost cards to determine which cost Gemified should affect.
/// Priority from first choice to last: Energy, Bones, Mox, Blood
/// </remarks>
public static bool ReduceGemifiedMox(PlayableCard card, List<GemType> gemsCost = null)
{
return (gemsCost?.Count ?? ImprovedGemsCost(card.Info).Count) > 0 && !ReduceGemifiedBones(card) && !ReduceGemifiedEnergy(card);
}
/// <summary>
/// Determines whether or not Gemified should reduce the bone cost on a multicost card.
/// </summary>
/// <param name="card">The gemified PlayableCard we're checking.</param>
/// <param name="bonesCost">The PlayableCard's bone cost. Defaults to using the CardInfo's bone cost if null.</param>
/// <returns>True if Gemified should reduce the bone cost by 1.</returns>
/// <remarks>
/// Used for multicost cards to determine which cost Gemified should affect.
/// Priority from first choice to last: Energy, Bones, Mox, Blood
/// </remarks>
public static bool ReduceGemifiedBones(PlayableCard card, int? bonesCost = null)
{
return (bonesCost ?? OriginalBonesCost(card.Info)) > 0 && !ReduceGemifiedEnergy(card);
}
/// <summary>
/// Determines whether or not Gemified should reduce the energy cost on a multicost card.
/// </summary>
/// <param name="card">The gemified PlayableCard we're checking.</param>
/// <param name="energyCost">The PlayableCard's energy cost. Defaults to using the CardInfo's energy cost if null.</param>
/// <returns>True if Gemified should reduce the energy cost by 1.</returns>
/// <remarks>
/// Used for multicost cards to determine which cost Gemified should affect.
/// Priority from first choice to last: Energy, Bones, Mox, Blood
/// </remarks>
public static bool ReduceGemifiedEnergy(PlayableCard card, int? energyCost = null)
{
return (energyCost ?? OriginalEnergyCost(card.Info)) > 0;
Expand All @@ -153,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}");
Expand All @@ -162,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)
Expand All @@ -173,23 +213,23 @@ 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<GemType> __result)
private static bool GemsCost(CardInfo __instance, ref List<GemType> __result)
{
PlayableCard card = __instance.GetPlayableCard();
__result = card?.GemsCost() ?? CostProperties.ImprovedGemsCost(__instance);
return false;
}

[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);
return false;
}

[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);
Expand Down
Loading
Loading