Skip to content

Commit ace7036

Browse files
authored
Merge pull request #329 from HumabHatterZed/main
2.23.6 - Fix Ice Cube card mods not being added
2 parents 3fca80d + 21f1675 commit ace7036

11 files changed

Lines changed: 234 additions & 115 deletions

File tree

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
# 2.23.6
2+
- Fixed card modifications added to a card's base ice cube card via CardInfo.SetIceCube being ignored
3+
- Fixed PlayableCard.CanPlay not consistently accounting for temporary mod cost adjustments
4+
- Fixed dynamic play costs not consistently updating
5+
- Added additional methods for adding specific types of resources to the ResourceBank
6+
- Added CardSlot.ClearSlotModification extension method
7+
- Added additional FullAbility helper extension methods for setting act-specific rulebook categories
8+
19
# 2.23.5
210
- Fixed cards appearing as blank outside Act 1
311
- Added extension methods for FullAbility that mirror AbilityInfo extension methods

InscryptionAPI/Card/AbilityExtensions.cs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -487,10 +487,27 @@ public static FullAbility SetKeywordAbility(this FullAbility fullAbility, bool k
487487
/// <returns>The same AbilityInfo so a chain can continue.</returns>
488488
public static AbilityInfo ResetDescription(this AbilityInfo abilityInfo)
489489
{
490-
abilityInfo.rulebookDescription = AllAbilities.Find(x => x.Info == abilityInfo).BaseRulebookDescription;
490+
abilityInfo.rulebookDescription = AllAbilities.AbilityByID(abilityInfo.ability).BaseRulebookDescription;
491491
return abilityInfo;
492492
}
493493

494+
public static FullAbility SetPart1Rulebook(this FullAbility full) {
495+
full.Info.AddMetaCategories(AbilityMetaCategory.Part1Rulebook);
496+
return full;
497+
}
498+
public static FullAbility SetPart3Rulebook(this FullAbility full) {
499+
full.Info.AddMetaCategories(AbilityMetaCategory.Part3Rulebook);
500+
return full;
501+
}
502+
public static FullAbility SetGrimoraRulebook(this FullAbility full) {
503+
full.Info.AddMetaCategories(AbilityMetaCategory.GrimoraRulebook);
504+
return full;
505+
}
506+
public static FullAbility SetMagnificusRulebook(this FullAbility full) {
507+
full.Info.AddMetaCategories(AbilityMetaCategory.MagnificusRulebook);
508+
return full;
509+
}
510+
494511
public static bool HasMetaCategories(this AbilityInfo info, params AbilityMetaCategory[] categories)
495512
{
496513
foreach (AbilityMetaCategory app in categories)

InscryptionAPI/Card/AbilityManager.cs

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using InscryptionAPI.Helpers;
55
using InscryptionAPI.Helpers.Extensions;
66
using InscryptionAPI.RuleBook;
7+
using Sirenix.Utilities;
78
using System.Collections;
89
using System.Collections.ObjectModel;
910
using System.Reflection;
@@ -683,6 +684,38 @@ private static void LogAbilityInfo(Ability ability, AbilityInfo abilityInfo, Car
683684
InscryptionAPIPlugin.Logger.LogError("Cannot find ability " + ability + " for " + info.displayedName);
684685
}
685686

687+
[HarmonyPatch(typeof(IceCube), nameof(IceCube.OnDie), MethodType.Enumerator)]
688+
[HarmonyTranspiler]
689+
private static IEnumerable<CodeInstruction> AddInherentModsToIceCube(IEnumerable<CodeInstruction> instructions) {
690+
List<CodeInstruction> codes = new(instructions);
691+
692+
for (int i = 0; i < codes.Count; i++) {
693+
if (codes[i].opcode == OpCodes.Ldloc_2) {
694+
// this probably belongs in the community patches but this transpiler was already here, so eh
695+
// overrides the transformer icon so it can display numbers
696+
MethodInfo customMethod = AccessTools.Method(typeof(AbilityManager), nameof(AbilityManager.GetIceCubeInfoWithMods),
697+
new Type[] { typeof(IceCube), typeof(string) });
698+
699+
// ldloc_1 <- IceCube
700+
// ldloc_2 <- name
701+
// call (customMethod)
702+
codes[i + 1] = new(OpCodes.Call, customMethod);
703+
codes.Insert(i, new(OpCodes.Ldloc_1));
704+
break;
705+
}
706+
}
707+
708+
return codes;
709+
}
710+
711+
private static CardInfo GetIceCubeInfoWithMods(IceCube instance, string cardName) {
712+
CardInfo info = CardLoader.GetCardByName(cardName);
713+
if (instance.Card.Info.iceCubeParams != null && instance.Card.Info.iceCubeParams.creatureWithin != null && instance.Card.Info.iceCubeParams.creatureWithin.mods != null && instance.Card.Info.iceCubeParams.creatureWithin.mods.Count > 0) {
714+
info.Mods.AddRange(instance.Card.Info.iceCubeParams.creatureWithin.mods);
715+
}
716+
return info;
717+
}
718+
686719
#region Evolve Changes
687720
[HarmonyPatch(typeof(Evolve), nameof(Evolve.OnUpkeep), MethodType.Enumerator)]
688721
[HarmonyTranspiler]
@@ -734,13 +767,6 @@ private static bool OverrideTransformIcon(ref Texture __result, AbilityIconInter
734767
}
735768
return true;
736769
}
737-
//[HarmonyPrefix, HarmonyPatch(typeof(AbilitiesUtil), nameof(AbilitiesUtil.LoadAbilityIcon))]
738-
//private static bool OverrideEvolveAndTransformerIcon(ref Texture __result, string abilityName) {
739-
// if (abilityName.StartsWith("Evolve") || abilityName.StartsWith("Transformer")) {
740-
// return false;
741-
// }
742-
// return true;
743-
//}
744770
private static void OverrideEvolveDerivedIcon(Evolve evolve, int turnsLeftToEvolve)
745771
{
746772
if (evolve.Ability == Ability.Evolve)

InscryptionAPI/Card/CardExtensionsCosts.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public static PlayableCard GetPlayableCard(this CardInfo cardInfo)
3232
public static int BloodCost(this PlayableCard card)
3333
{
3434
//Debug.Log($"{card != null} {card?.Info != null} [{card?.GetType()}] {(card as DiskCardGame.Card)?.Info != null}");
35-
if (card && card.Info)
35+
if (card != null && card.Info != null)
3636
{
3737
int originalBloodCost = CostProperties.CostProperties.OriginalBloodCost(card.Info);
3838
if (card.IsUsingBlueGem() && CostProperties.CostProperties.ReduceGemifiedBlood(card, originalBloodCost))
@@ -45,7 +45,7 @@ public static int BloodCost(this PlayableCard card)
4545
return originalBloodCost;
4646
}
4747

48-
InscryptionAPIPlugin.Logger.LogError("[BloodCost] Couldn't find Card or CardInfo for blood cost??? How is this possible?");
48+
InscryptionAPIPlugin.Logger.LogWarning("[BloodCost] Couldn't find PlayableCard or CardInfo, returning 0");
4949
return 0;
5050
}
5151

@@ -55,7 +55,7 @@ public static int BloodCost(this PlayableCard card)
5555
/// </summary>
5656
public static int BonesCost(this PlayableCard card)
5757
{
58-
if (card && card.Info)
58+
if (card != null && card.Info != null)
5959
{
6060
int originalBonesCost = CostProperties.CostProperties.OriginalBonesCost(card.Info);
6161
if (card.IsUsingBlueGem() && CostProperties.CostProperties.ReduceGemifiedBones(card, originalBonesCost))
@@ -68,7 +68,7 @@ public static int BonesCost(this PlayableCard card)
6868
return originalBonesCost;
6969
}
7070

71-
InscryptionAPIPlugin.Logger.LogError("Couldn't find Card or CardInfo for bone cost??? How is this possible?");
71+
InscryptionAPIPlugin.Logger.LogWarning("[BonesCost] Couldn't find PlayableCard or CardInfo, returning 0");
7272
return 0;
7373
}
7474

@@ -78,8 +78,10 @@ public static int BonesCost(this PlayableCard card)
7878
/// </summary>
7979
public static List<GemType> GemsCost(this PlayableCard card)
8080
{
81-
if (card?.Info == null)
81+
if (card != null && card.Info != null) {
82+
InscryptionAPIPlugin.Logger.LogWarning("[GemsCost] Couldn't find PlayableCard or CardInfo, returning empty list");
8283
return new();
84+
}
8385

8486
List<CardModificationInfo> mods = card.TemporaryMods.Concat(card.Info.Mods).ToList();
8587
if (mods.Exists(x => x.nullifyGemsCost))

InscryptionAPI/Card/CostProperties.cs

Lines changed: 60 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ public bool GemsChanged<T>(List<T> a, List<T> b)
6969

7070
public static ConditionalWeakTable<CardInfo, List<WeakReference<PlayableCard>>> CardInfoToCard = new();
7171

72+
73+
// a table that maps a CardInfo object to a list of weak references to every PlayableCard that uses that same CardInfo
74+
public static ConditionalWeakTable<CardInfo, List<WeakReference<PlayableCard>>> CardInfoToPlayableCardReferences = new();
75+
76+
7277
/// <summary>
7378
/// ChangeCardCostGetter patches BloodCost so we can change the cost on the fly
7479
/// This reverse patch gives us access to the original method without any changes.
@@ -151,6 +156,7 @@ internal static class ChangeCardCostGetter
151156
public static bool BloodCost(CardInfo __instance, ref int __result)
152157
{
153158
PlayableCard card = __instance.GetPlayableCard();
159+
//Debug.Log($"{card != null}");
154160
__result = Mathf.Max(0, card?.BloodCost() ?? CostProperties.OriginalBloodCost(__instance));
155161
return false;
156162
}
@@ -196,94 +202,72 @@ public static bool DisableVanillaEnergyCost(PlayableCard __instance, ref int __r
196202
__result = Mathf.Max(0, energyCost);
197203
return false;
198204
}
205+
206+
//[HarmonyPostfix, HarmonyPatch(typeof(PlayableCard), nameof(PlayableCard.SetInfo))]
207+
//private static void GetCardInfoReferences(PlayableCard __instance) {
208+
209+
// // if this is a new PlayableCard being associated with the given CardInfo
210+
// // returns true if the CardInfo is in the table
211+
// if (CostProperties.CardInfoToPlayableCardReferences.TryGetValue(__instance.Info, out List<WeakReference<PlayableCard>> connectedCards)) {
212+
// PlayableCard card = null;
213+
// for (int i = connectedCards.Count - 1; i >= 0; i--) {
214+
// // NOTE: We store a list of cards so if we don't clear this list then it will fill up forever
215+
// // remove PlayableCard references that no longer point to anything
216+
// if (!connectedCards[i].TryGetTarget(out PlayableCard cardReference) || cardReference == null) {
217+
// connectedCards.RemoveAt(i);
218+
// }
219+
// else if (cardReference == __instance) {
220+
// card = cardReference;
221+
// }
222+
// }
223+
224+
// if (card == null) {
225+
// connectedCards.Add(new WeakReference<PlayableCard>(__instance));
226+
// if (connectedCards.Count > 1) {
227+
// InscryptionAPIPlugin.Logger.LogWarning($"More than 1 card are using the same card info. This can cause unexpected problems with dynamic costs! {__instance.Info.displayedName}");
228+
// }
229+
// }
230+
// }
231+
// else {
232+
// // add CardInfo to table with reference to this PlayableCard
233+
// CostProperties.CardInfoToPlayableCardReferences.Add(__instance.Info, new() { new(__instance) });
234+
// }
235+
//}
199236
}
200237

201-
/*[HarmonyPatch(typeof(DiskCardGame.Card), nameof(DiskCardGame.Card.Info), MethodType.Setter)]
202-
internal static class Card_SetInfo
238+
[HarmonyPatch(typeof(PlayableCard), nameof(PlayableCard.SetInfo))]
239+
internal static class AddRefreshBehaviourToCard
203240
{
204-
public static void Postfix(DiskCardGame.Card __instance)
241+
private static void Postfix(PlayableCard __instance)
205242
{
206-
//return;
207-
if (__instance is not PlayableCard playableCard)
208-
return;
209-
210-
CardInfo info = playableCard.Info;
211-
212-
if (CostProperties.CardInfoToCard.TryGetValue(info, out List<WeakReference<PlayableCard>> cardList))
213-
{
243+
// add the refresh component if it doesn't exist, then set the Card to the calling instance
244+
CostProperties.RefreshCostMonoBehaviour refreshCostDisplay = __instance.GetComponent<CostProperties.RefreshCostMonoBehaviour>() ?? __instance.gameObject.AddComponent<CostProperties.RefreshCostMonoBehaviour>();
245+
refreshCostDisplay.playableCard = __instance;
246+
247+
// if this is a new PlayableCard being associated with the given CardInfo
248+
// returns true if the CardInfo is in the table
249+
if (CostProperties.CardInfoToCard.TryGetValue(__instance.Info, out List<WeakReference<PlayableCard>> cardList)) {
214250
PlayableCard card = null;
215-
for (int i = cardList.Count - 1; i >= 0; i--)
216-
{
251+
for (int i = cardList.Count - 1; i >= 0; i--) {
252+
// NOTE: We store a list of cards so if we don't clear this list then it will fill up forever
253+
// remove PlayableCard references that no longer point to anything
217254
if (!cardList[i].TryGetTarget(out PlayableCard innerCard) || innerCard == null)
218-
{
219-
// NOTE: We store a list of cards so if we don't clear this list then it will fill up forever
220255
cardList.RemoveAt(i);
221-
}
222-
else if(innerCard == playableCard)
223-
{
256+
257+
else if (innerCard == __instance)
224258
card = innerCard;
225-
}
226259
}
227-
228-
if (card == null)
229-
{
230-
cardList.Add(new WeakReference<PlayableCard>(playableCard));
231-
if (cardList.Count > 1)
232-
{
233-
InscryptionAPIPlugin.Logger.LogWarning($"More than 1 card are using the same card info. This can cause unexpected problems with dynamic costs! {info.displayedName}");
234-
}
235-
}
236-
}
237-
else
238-
{
239-
Debug.Log($"New-un");
240-
CostProperties.CardInfoToCard.Add(info, new List<WeakReference<PlayableCard>>()
241-
{
242-
new WeakReference<PlayableCard>(playableCard)
243-
});
244-
}
245-
}
246-
}*/
247-
248-
[HarmonyPatch(typeof(PlayableCard), nameof(PlayableCard.SetInfo))]
249-
internal static class AddRefreshBehaviourToCard
250-
{
251-
private static void Postfix(PlayableCard __instance)
252-
{
253-
// add the refresh component if it doesn't exist, then set the Card to the calling instance
254-
if (__instance.GetComponent<CostProperties.RefreshCostMonoBehaviour>() == null)
255-
{
256-
__instance.gameObject.AddComponent<CostProperties.RefreshCostMonoBehaviour>().playableCard = __instance;
257-
if (CostProperties.CardInfoToCard.TryGetValue(__instance.Info, out List<WeakReference<PlayableCard>> cardList))
258-
{
259-
PlayableCard card = null;
260-
for (int i = cardList.Count - 1; i >= 0; i--)
261-
{
262-
// NOTE: We store a list of cards so if we don't clear this list then it will fill up forever
263-
if (!cardList[i].TryGetTarget(out PlayableCard innerCard) || innerCard == null)
264-
cardList.RemoveAt(i);
265-
266-
else if (innerCard == __instance)
267-
card = innerCard;
268-
}
269260

270-
if (card == null)
271-
{
272-
cardList.Add(new WeakReference<PlayableCard>(__instance));
273-
if (cardList.Count > 1)
274-
{
275-
InscryptionAPIPlugin.Logger.LogWarning($"More than 1 card are using the same card info. This can cause unexpected problems with dynamic costs! {__instance.Info.displayedName}");
276-
}
261+
if (card == null) {
262+
cardList.Add(new WeakReference<PlayableCard>(__instance));
263+
if (cardList.Count > 1) {
264+
InscryptionAPIPlugin.Logger.LogWarning($"More than 1 card are using the same CardInfo. This can cause unexpected problems with dynamic costs! {__instance.Info.displayedName}");
277265
}
278266
}
279-
else
280-
{
281-
CostProperties.CardInfoToCard.Add(__instance.Info, new List<WeakReference<PlayableCard>>()
282-
{
283-
new WeakReference<PlayableCard>(__instance)
284-
});
285-
}
286-
267+
}
268+
else {
269+
// add CardInfo to table with reference to this PlayableCard
270+
CostProperties.CardInfoToCard.Add(__instance.Info, new() { new (__instance) });
287271
}
288272
}
289273
}

InscryptionAPI/Costs/CardCostManager.cs

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -324,18 +324,17 @@ public static FullCardCost SetFoundAtChoiceNodes(this FullCardCost fullCardCost,
324324

325325
#region Patches
326326
[HarmonyPostfix, HarmonyPatch(typeof(PlayableCard), nameof(PlayableCard.CanPlay))]
327-
private static void CanPlayCustomCosts(ref bool __result, ref PlayableCard __instance)
328-
{
329-
if (!__result)
330-
return;
331-
332-
foreach (CustomCardCost cost in __instance.GetCustomCardCosts())
333-
{
334-
FullCardCost fullCost = AllCustomCosts.CostByBehaviour(cost.GetType());
335-
if (!cost.CostSatisfied(__instance.GetCustomCost(fullCost), __instance))
336-
{
337-
__result = false;
338-
return;
327+
private static void CanPlayCustomCosts(ref bool __result, ref PlayableCard __instance) {
328+
if (__instance.BloodCost() <= Singleton<BoardManager>.Instance.AvailableSacrificeValue && __instance.BonesCost() <= Singleton<ResourcesManager>.Instance.PlayerBones && __instance.EnergyCost <= Singleton<ResourcesManager>.Instance.PlayerEnergy && __instance.GemsCostRequirementMet()) {
329+
if (Singleton<BoardManager>.Instance.SacrificesCreateRoomForCard(__instance, Singleton<BoardManager>.Instance.PlayerSlotsCopy)) {
330+
foreach (CustomCardCost cost in __instance.GetCustomCardCosts()) {
331+
FullCardCost fullCost = AllCustomCosts.CostByBehaviour(cost.GetType());
332+
if (!cost.CostSatisfied(__instance.GetCustomCost(fullCost), __instance)) {
333+
__result = false;
334+
return;
335+
}
336+
}
337+
__result = true;
339338
}
340339
}
341340
}

InscryptionAPI/InscryptionAPI.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<DebugType>full</DebugType>
1111
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
1212
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
13-
<Version>2.23.5</Version>
13+
<Version>2.23.6</Version>
1414
</PropertyGroup>
1515

1616
<PropertyGroup>

InscryptionAPI/InscryptionAPIPlugin.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public class InscryptionAPIPlugin : BaseUnityPlugin
3131
{
3232
public const string ModGUID = "cyantist.inscryption.api";
3333
public const string ModName = "InscryptionAPI";
34-
public const string ModVer = "2.23.5";
34+
public const string ModVer = "2.23.6";
3535

3636
public static string Directory = "";
3737

0 commit comments

Comments
 (0)