diff --git a/CHANGELOG.md b/CHANGELOG.md index f0f3fd6f..5705f6a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,17 @@
View Changelog +## 2.18.6 +- Added missing null checks to ResourceDrone patches +- Added pixel icon to Transformer +- Fixed Royal fight softlocking if config option 'Hide Act 1 Scenery' is set to true +- Fixed activated custom challenges not remaining activated when returning to the challenge screen +- Fixed TransformIntoCardInHand and TransformIntoCardAboveHand not checking for TriggersOncePerStack +- Transformer sigil icon will now display the number of turns till evolution if it's greater than 1 +- Transformer and Fledgling sigils now correctly update their display when evolving into another card with the Fledgling/Transformer sigil +- Certain shield-giving effects no longer reset shields to prevent incorrect shield totals +- Improved the 'Custom Card Costs' section of the wiki + ## 2.18.5 - Added missing null checks - Added PlayableCard.GetStatIconHealthBuffs() diff --git a/InscryptionAPI/Ascension/AscensionChallengePaginator.cs b/InscryptionAPI/Ascension/AscensionChallengePaginator.cs index 1da28390..ed3b475c 100644 --- a/InscryptionAPI/Ascension/AscensionChallengePaginator.cs +++ b/InscryptionAPI/Ascension/AscensionChallengePaginator.cs @@ -15,32 +15,26 @@ public void Initialize(AscensionChallengeScreen screen, AscensionMenuScreenTrans { if (challengeObjectsForPages == null) { + List toSort = new(); if (screen != null) { pageLength = screen.icons.Count; - List toSort = screen.icons.ConvertAll((x) => x.gameObject); - challengeObjectsForPages = new List> - { - toSort - }; + toSort = screen.icons.ConvertAll((x) => x.gameObject); } else { - List icons = new(transition.screenInteractables.FindAll((x) => x.GetComponent() != null).ConvertAll((x) => - x.GetComponent())); + List icons = new( + transition.screenInteractables.FindAll((x) => x.GetComponent() != null) + .ConvertAll((x) => x.GetComponent()) + ); pageLength = icons.Count; - List toSort = icons.ConvertAll((x) => x.gameObject); - challengeObjectsForPages = new List> - { - toSort - }; + toSort = icons.ConvertAll((x) => x.gameObject); } + challengeObjectsForPages = new List> { toSort }; } this.screen = screen; if (screen == null) - { this.transition = transition; - } } public void AddPage(List page) @@ -92,10 +86,9 @@ public void AddPage(List page) public void NextPage() { pageIndex++; - if (pageIndex >= challengeObjectsForPages.Count) - { + if (pageIndex >= challengeObjectsForPages.Count) // wrap-around pageIndex = 0; - } + LoadPage(pageIndex); } @@ -103,37 +96,35 @@ public void PreviousPage() { pageIndex--; if (pageIndex < 0) - { - pageIndex = challengeObjectsForPages.Count - 1; - } + pageIndex = challengeObjectsForPages.Count - 1; // wrap-around + LoadPage(pageIndex); } public void LoadPage(int page) { + // if page index corresponds to an index in challengeObjects if (page >= 0 && page < challengeObjectsForPages.Count) { + // for every list of objects for (int i = 0; i < challengeObjectsForPages.Count; i++) { - var value = challengeObjectsForPages[i]; + List value = challengeObjectsForPages[i]; + value.RemoveAll(x => x == null); // remove null game objects if (i == page) { - value.RemoveAll(x => x == null); - value.ForEach((x) => + value.ForEach(x => { - if (x != null) - { - x?.SetActive( - x?.GetComponentInChildren()?.Info == null || - x?.GetComponentInChildren().Info.challengeType != AscensionChallenge.FinalBoss || - AscensionUnlockSchedule.ChallengeIsUnlockedForLevel(AscensionChallenge.FinalBoss, AscensionSaveData.Data.challengeLevel)); - } + AscensionChallenge currentChallenge = x.GetComponentInChildren()?.Info?.challengeType ?? AscensionChallenge.FinalBoss; + x.SetActive( + currentChallenge != AscensionChallenge.FinalBoss || + AscensionUnlockSchedule.ChallengeIsUnlockedForLevel(AscensionChallenge.FinalBoss, AscensionSaveData.Data.challengeLevel)); + x.GetComponent()?.ShowActivated(AscensionSaveData.Data.activeChallenges.Contains(currentChallenge)); }); } else { - value.RemoveAll(x => x == null); - value.ForEach((x) => { if (x != null) { x?.SetActive(false); } }); + value.ForEach(x => x.SetActive(false)); } } } @@ -150,7 +141,7 @@ public void OnEnable() Destroy(leftArrow); for (int i = 1; i < challengeObjectsForPages.Count; i++) { - challengeObjectsForPages[i].ForEach(x => DestroyImmediate(x)); + challengeObjectsForPages[i].ForEach(DestroyImmediate); } challengeObjectsForPages.Clear(); screen?.icons?.RemoveAll(x => x == null); @@ -159,23 +150,16 @@ public void OnEnable() { icons = screen.icons; pageLength = screen.icons.Count; - List toSort = screen.icons.ConvertAll((x) => x.gameObject); - challengeObjectsForPages = new List> - { - toSort - }; } else { icons = new(transition.screenInteractables.FindAll((x) => x.GetComponent() != null).ConvertAll((x) => x.GetComponent())); pageLength = icons.Count; - List toSort = icons.ConvertAll((x) => x.gameObject); - challengeObjectsForPages = new List> - { - toSort - }; } + List toSort = icons.ConvertAll((x) => x.gameObject); + challengeObjectsForPages = new List> { toSort }; + List fcs = ChallengeManager.AllChallenges.ToList(); List<(ChallengeManager.FullChallenge, AscensionChallengeInfo)> challengesToAdd = new(fcs.ConvertAll(x => (x, x.Challenge).Repeat(x.AppearancesInChallengeScreen)).SelectMany(x => x)); List sortedicons = new(screen.icons); @@ -258,7 +242,7 @@ public void OnEnable() // if the arrows would be offscreen/clipped by the screen edge, // or if the arrows' positions have been overriden by the config - if (screenContinue.position.x < rightArrowPos.x || InscryptionAPIPlugin.configOverrideArrows.Value) + if (InscryptionAPIPlugin.configOverrideArrows.Value || screenContinue.position.x < rightArrowPos.x) { rightArrowPos = screenContinue.position + Vector3.left / 2f; diff --git a/InscryptionAPI/Ascension/AscensionChallengeScreen.cs b/InscryptionAPI/Ascension/AscensionChallengeScreen.cs index 04f4cfb0..70b3b52c 100644 --- a/InscryptionAPI/Ascension/AscensionChallengeScreen.cs +++ b/InscryptionAPI/Ascension/AscensionChallengeScreen.cs @@ -101,39 +101,24 @@ public static bool UpdateFooterText(AscensionChallengeScreen __instance, Ascensi if (challengeInfo.pointValue < 0) { string arg = Localization.ToUpper(Localization.Translate(challengeInfo.title)); - string text; - if (activated) - { - text = string.Format(Localization.Translate("{0} ENABLED"), arg); - } - else - { - text = string.Format(Localization.Translate("{0} DISABLED"), arg); - } + string text = string.Format(Localization.Translate(activated ? "{0} ENABLED" : "{0} DISABLED"), arg); + string text2; if (activated) - { text2 = string.Format(Localization.Translate("{0} Challenge Points Subtracted"), (-challengeInfo.pointValue).ToString()); - } else - { text2 = string.Format(Localization.Translate("{0} Challenge Points Added"), (-challengeInfo.pointValue).ToString()); - } + int challengeLevel = AscensionSaveData.Data.challengeLevel; int activeChallengePoints = AscensionSaveData.Data.GetActiveChallengePoints(); string text3; if (activeChallengePoints > AscensionSaveData.GetChallengePointsForLevel(challengeLevel)) - { text3 = string.Format(Localization.Translate("WARNING(!) Lvl Reqs EXCEEDED"), Array.Empty()); - } else if (activeChallengePoints == AscensionSaveData.GetChallengePointsForLevel(challengeLevel)) - { text3 = string.Format(Localization.Translate("Lvl Reqs Met"), Array.Empty()); - } else - { text3 = string.Format(Localization.Translate("Lvl Reqs NOT MET"), Array.Empty()); - } + __instance.footerLines.ShowText(0.1f, new string[] { text, @@ -161,6 +146,7 @@ public static void Postfix(AscensionMenuScreens __instance) [HarmonyPostfix] public static void Postfix(AscensionChallengeScreen __instance) { + Debug.Log($"{AscensionSaveData.Data.activeChallenges.Count}"); if (__instance.GetComponent() == null) { ChallengeManager.SyncChallengeList(); diff --git a/InscryptionAPI/Ascension/ChallengeDisplayerPlus.cs b/InscryptionAPI/Ascension/ChallengeDisplayerPlus.cs index 48d1158f..de7cbfd8 100644 --- a/InscryptionAPI/Ascension/ChallengeDisplayerPlus.cs +++ b/InscryptionAPI/Ascension/ChallengeDisplayerPlus.cs @@ -95,12 +95,9 @@ public void DisplayChallenge(AscensionChallengeInfo challengeInfo, bool immediat { List dependencies = challengeInfo?.GetFullChallenge()?.DependantChallengeGetter?.Invoke(ChallengeManager.GetChallengeIcons())?.ToList(); List incompatibilities = challengeInfo?.GetFullChallenge()?.IncompatibleChallengeGetter?.Invoke(ChallengeManager.GetChallengeIcons())?.ToList(); - if (dependencies != null && incompatibilities != null) - { - incompatibilities.RemoveAll(x => dependencies.Contains(x)); - } if (dependencies != null) { + incompatibilities?.RemoveAll(dependencies.Contains); dependencies.RemoveAll(x => x == challengeInfo.challengeType); if (dependencies.Count > 0) { @@ -117,10 +114,12 @@ public void DisplayChallenge(AscensionChallengeInfo challengeInfo, bool immediat } else { - PrefixedString pstr = new(); - pstr.prefix = Localization.Translate(info.title); - pstr.challenge = d; - pstr.number = 1; + PrefixedString pstr = new() + { + prefix = Localization.Translate(info.title), + challenge = d, + number = 1 + }; dependencyStrings.Add(pstr); } } @@ -155,9 +154,7 @@ public void DisplayChallenge(AscensionChallengeInfo challengeInfo, bool immediat } } if (incompatibilityStrings.Count > 0) - { incompatibility = "Incompatible with: " + string.Join(", ", incompatibilityStrings); - } } } } diff --git a/InscryptionAPI/Ascension/ChallengeManager.cs b/InscryptionAPI/Ascension/ChallengeManager.cs index c88dc675..4fa4e726 100644 --- a/InscryptionAPI/Ascension/ChallengeManager.cs +++ b/InscryptionAPI/Ascension/ChallengeManager.cs @@ -323,14 +323,16 @@ internal static FullChallenge[] GetChallengeIcons() private static AscensionChallengeInfo CloneChallengeInfo(AscensionChallengeInfo info) { - AscensionChallengeInfo retval = new(); - retval.activatedSprite = info.activatedSprite; - retval.challengeType = info.challengeType; - retval.description = info.description; - retval.iconSprite = info.iconSprite; - retval.name = info.name; - retval.pointValue = info.pointValue; - retval.title = info.title; + AscensionChallengeInfo retval = new() + { + activatedSprite = info.activatedSprite, + challengeType = info.challengeType, + description = info.description, + iconSprite = info.iconSprite, + name = info.name, + pointValue = info.pointValue, + title = info.title + }; return retval; } @@ -679,9 +681,7 @@ private static IEnumerator ActivateChallenges(IEnumerator result, TurnManager __ foreach (ChallengeBehaviour bb in cbs) { if (bb != null && bb.RespondsToPostBattleSetup()) - { yield return bb.OnPostBattleSetup(); - } } yield break; } @@ -712,18 +712,14 @@ private static IEnumerator Postfix(IEnumerator result) foreach (ChallengeBehaviour bb in cbs) { if (bb != null && bb.RespondsToPreBattleCleanup()) - { yield return bb.OnPreBattleCleanup(); - } } yield return result; cbs = ChallengeBehaviour.Instances.ToArray(); foreach (ChallengeBehaviour bb in cbs) { if (bb != null && bb.RespondsToPostBattleCleanup()) - { yield return bb.OnPostBattleCleanup(); - } } ChallengeBehaviour.DestroyAllInstances(); yield break; @@ -804,17 +800,14 @@ private static void DoDependenciesAndIncompatibilities(AscensionIconInteractable { List dependencies2 = icon?.challengeInfo?.GetFullChallenge()?.DependantChallengeGetter?.Invoke(GetChallengeIcons())?.ToList(); List incompatibilities2 = icon?.challengeInfo?.GetFullChallenge()?.IncompatibleChallengeGetter?.Invoke(GetChallengeIcons())?.ToList(); - if (dependencies2 != null && incompatibilities2 != null) - { - incompatibilities.RemoveAll(x => dependencies2.Contains(x)); - } if (incompatibilities2 != null) { + if (dependencies2 != null) + incompatibilities.RemoveAll(dependencies2.Contains); + incompatibilities2.RemoveAll(x => x == icon.challengeInfo.challengeType); if (screen.icons.Exists(x => x.Unlocked && x.clickable && x.Info != null && x.activatedRenderer != null && x.activatedRenderer.enabled && incompatibilities2.Contains(x.Info.challengeType))) - { icon?.OnCursorSelectStart(); - } } } } @@ -837,33 +830,25 @@ private static void DoDependenciesAndIncompatibilities(AscensionIconInteractable { List dependencies = icon?.challengeInfo?.GetFullChallenge()?.DependantChallengeGetter?.Invoke(GetChallengeIcons())?.ToList(); List incompatibilities = icon?.challengeInfo?.GetFullChallenge()?.IncompatibleChallengeGetter?.Invoke(GetChallengeIcons())?.ToList(); - if (dependencies != null && incompatibilities != null) - { - incompatibilities.RemoveAll(x => dependencies.Contains(x)); - } if (dependencies != null) { + incompatibilities?.RemoveAll(dependencies.Contains); + dependencies.RemoveAll(x => x == icon.challengeInfo.challengeType); List dependenciesClone = new(dependencies); foreach (var icon2 in screen.icons.Where(x => x.Unlocked && x.clickable && x.Info != null && x.activatedRenderer != null && x.activatedRenderer.enabled && dependencies.Contains(x.Info.challengeType))) { if (dependenciesClone.Contains(icon2.Info.challengeType)) - { dependenciesClone.Remove(icon2.Info.challengeType); - } } if (dependenciesClone.Count > 0) - { icon?.OnCursorSelectStart(); - } } } } } if (setCurrentIcon) - { currentIcon = null; - } } } diff --git a/InscryptionAPI/Assets/ability_transformer_1.png b/InscryptionAPI/Assets/ability_transformer_1.png new file mode 100644 index 00000000..5a6d6780 Binary files /dev/null and b/InscryptionAPI/Assets/ability_transformer_1.png differ diff --git a/InscryptionAPI/Assets/ability_transformer_2.png b/InscryptionAPI/Assets/ability_transformer_2.png new file mode 100644 index 00000000..0458789f Binary files /dev/null and b/InscryptionAPI/Assets/ability_transformer_2.png differ diff --git a/InscryptionAPI/Assets/ability_transformer_3.png b/InscryptionAPI/Assets/ability_transformer_3.png new file mode 100644 index 00000000..6b2353e4 Binary files /dev/null and b/InscryptionAPI/Assets/ability_transformer_3.png differ diff --git a/InscryptionAPI/Card/AbilityManager.cs b/InscryptionAPI/Card/AbilityManager.cs index 439fbd07..d232236b 100644 --- a/InscryptionAPI/Card/AbilityManager.cs +++ b/InscryptionAPI/Card/AbilityManager.cs @@ -236,13 +236,10 @@ private static List GenBaseGameAbilityList() if (Part2ModularAbilities.BasePart2Modular.Contains(ability.ability)) ability.SetDefaultPart2Ability(); - if (name == "DeathShield") + if (name == "DeathShield") // add the API ability behaviour to DeathShield { - ability.SetPassive(false); - ability.SetCanStack(true); - ability.SetHideSingleStacks(true); - baseGame.Add(new FullAbility - ( + ability.SetPassive(false).SetCanStack(true).SetHideSingleStacks(true); + baseGame.Add(new FullAbility ( null, ability.ability, ability, @@ -251,8 +248,7 @@ private static List GenBaseGameAbilityList() )); continue; } - baseGame.Add(new FullAbility - ( + baseGame.Add(new FullAbility ( null, ability.ability, ability, @@ -344,7 +340,7 @@ internal static Dictionary GetAbilityExtensionTable(this Ability return AbilityExtensionProperties.GetOrCreateValue(info).StringMap; } - + #region LoadAbilityIcon [HarmonyReversePatch(HarmonyReversePatchType.Original)] [HarmonyPatch(typeof(AbilitiesUtil), nameof(AbilitiesUtil.LoadAbilityIcon))] [MethodImpl(MethodImplOptions.NoInlining)] @@ -380,13 +376,13 @@ private static bool LoadAbilityIconReplacement(string abilityName, ref Texture _ return true; } + #endregion [HarmonyPrefix] [HarmonyPatch(typeof(AbilitiesUtil), nameof(AbilitiesUtil.GetLearnedAbilities))] private static bool GetLearnedAbilitesReplacement(bool opponentUsable, int minPower, int maxPower, AbilityMetaCategory categoryCriteria, ref List __result) { __result = new(); - foreach (var ability in AllAbilityInfos) { bool canUse = true; @@ -402,6 +398,7 @@ private static bool GetLearnedAbilitesReplacement(bool opponentUsable, int minPo return false; } + #region Rulebook Description [HarmonyPostfix, HarmonyPatch(typeof(AbilityInfo), nameof(AbilityInfo.ParseAndTranslateDescription))] private static void CleanUpParsedDescription(ref string __result) { @@ -419,10 +416,7 @@ private static void CleanUpParsedDescription(ref string __result) [HarmonyPrefix, HarmonyPatch(typeof(RuleBookController), nameof(RuleBookController.OpenToAbilityPage))] private static bool UpdateRulebookDescription(PlayableCard card) { - if (!card) - return true; - - ExtendedActivatedAbilityBehaviour component = card.GetComponent(); + ExtendedActivatedAbilityBehaviour component = card?.GetComponent(); if (component != null) { foreach (FullAbility ab in AllAbilities.Where(ai => ai.Info.activated && card.HasAbility(ai.Id))) @@ -438,14 +432,14 @@ private static bool UpdateRulebookDescription(PlayableCard card) [HarmonyPrefix, HarmonyPatch(typeof(RuleBookController), nameof(RuleBookController.SetShown))] private static bool ResetAlteredDescriptions(bool shown) { - if (!shown) + if (shown) + return true; + + foreach (FullAbility ab in AllAbilities.Where(a => !BaseGameAbilities.Contains(a) && a.Info.activated)) { - foreach (FullAbility ab in AllAbilities.Where(a => !BaseGameAbilities.Contains(a) && a.Info.activated)) - { - AbilityInfo info = AbilitiesUtil.GetInfo(ab.Id); - if (info.rulebookDescription != ab.BaseRulebookDescription) - info.ResetDescription(); - } + AbilityInfo info = AbilitiesUtil.GetInfo(ab.Id); + if (info.rulebookDescription != ab.BaseRulebookDescription) + info.ResetDescription(); } return true; } @@ -572,11 +566,16 @@ private static void FixRulebook(AbilityMetaCategory metaCategory, RuleBookInfo _ } } + #endregion + [HarmonyPostfix, HarmonyPatch(typeof(PlayableCard), nameof(PlayableCard.TransformIntoCard))] private static IEnumerator TriggerStacksOnceAfterEvolve(IEnumerator enumerator, PlayableCard __instance) { yield return enumerator; - + FixStackTriggers(__instance); + } + internal static void FixStackTriggers(PlayableCard __instance) + { // get all triggered abilities List abilities = __instance.TriggerHandler.triggeredAbilities.ConvertAll(x => x.Item1); @@ -584,17 +583,14 @@ private static IEnumerator TriggerStacksOnceAfterEvolve(IEnumerator enumerator, foreach (var ab in abilities.Distinct()) { AbilityInfo info = AllAbilityInfos.AbilityByID(ab); - if (info.passive) + if (info.passive || !info.canStack || !info.GetTriggersOncePerStack()) continue; - if (info.canStack && info.GetTriggersOncePerStack()) + // since evolving doubles the triggers, remove half of them + for (int i = 0; i < abilities.Count(x => x == ab) / 2; i++) { - // since evolving doubles the triggers, remove half of them - for (int i = 0; i < abilities.Count(x => x == ab) / 2; i++) - { - var tuple = __instance.TriggerHandler.triggeredAbilities.Find(x => x.Item1 == ab); - __instance.TriggerHandler.triggeredAbilities.Remove(tuple); - } + var tuple = __instance.TriggerHandler.triggeredAbilities.Find(x => x.Item1 == ab); + __instance.TriggerHandler.triggeredAbilities.Remove(tuple); } } } @@ -604,53 +600,48 @@ private static IEnumerator TriggerStacksOnceAfterEvolve(IEnumerator enumerator, private static IEnumerator WaterborneFix(IEnumerator result, Trigger trigger, bool triggerFacedown, params object[] otherArgs) { yield return result; - if (!triggerFacedown) + if (triggerFacedown) + yield break; + + bool RespondsToTrigger(CardTriggerHandler r, Trigger trigger, params object[] otherArgs) { - bool RespondsToTrigger(CardTriggerHandler r, Trigger trigger, params object[] otherArgs) + foreach (TriggerReceiver receiver in r.GetAllReceivers()) { - foreach (TriggerReceiver receiver in r.GetAllReceivers()) - { - if (GlobalTriggerHandler.ReceiverRespondsToTrigger(trigger, receiver, otherArgs) && ((receiver is IActivateWhenFacedown && (receiver as IActivateWhenFacedown).ShouldTriggerWhenFaceDown(trigger, otherArgs)))) - return true; + if (GlobalTriggerHandler.ReceiverRespondsToTrigger(trigger, receiver, otherArgs) && ((receiver is IActivateWhenFacedown && (receiver as IActivateWhenFacedown).ShouldTriggerWhenFaceDown(trigger, otherArgs)))) + return true; - } - return false; } - IEnumerator OnTrigger(CardTriggerHandler r, Trigger trigger, params object[] otherArgs) + return false; + } + IEnumerator OnTrigger(CardTriggerHandler r, Trigger trigger, params object[] otherArgs) + { + foreach (TriggerReceiver receiver in r.GetAllReceivers()) { - foreach (TriggerReceiver receiver in r.GetAllReceivers()) - { - if (GlobalTriggerHandler.ReceiverRespondsToTrigger(trigger, receiver, otherArgs) && ((receiver is IActivateWhenFacedown && (receiver as IActivateWhenFacedown).ShouldTriggerWhenFaceDown(trigger, otherArgs)))) - yield return Singleton.Instance.TriggerSequence(trigger, receiver, otherArgs); + if (GlobalTriggerHandler.ReceiverRespondsToTrigger(trigger, receiver, otherArgs) && ((receiver is IActivateWhenFacedown && (receiver as IActivateWhenFacedown).ShouldTriggerWhenFaceDown(trigger, otherArgs)))) + yield return Singleton.Instance.TriggerSequence(trigger, receiver, otherArgs); - } - yield break; } - List list = new(Singleton.Instance.CardsOnBoard); - foreach (PlayableCard playableCard in list) - { - if (playableCard != null && playableCard.FaceDown && RespondsToTrigger(playableCard.TriggerHandler, trigger, otherArgs)) - yield return OnTrigger(playableCard.TriggerHandler, trigger, otherArgs); + yield break; + } + List list = new(Singleton.Instance.CardsOnBoard); + foreach (PlayableCard playableCard in list) + { + if (playableCard != null && playableCard.FaceDown && RespondsToTrigger(playableCard.TriggerHandler, trigger, otherArgs)) + yield return OnTrigger(playableCard.TriggerHandler, trigger, otherArgs); - } } yield break; } - [HarmonyPatch(typeof(AbilityIconInteractable), nameof(AbilityIconInteractable.AssignAbility))] - [HarmonyTranspiler] + [HarmonyTranspiler, HarmonyPatch(typeof(AbilityIconInteractable), nameof(AbilityIconInteractable.AssignAbility))] public static IEnumerable AbilityIconInteractable_AssignAbility(IEnumerable instructions) { - // === We want to turn this - + // === We want to turn this: // AbilityInfo info2 = AbilitiesUtil.GetInfo(ability); - // === Into this - + // === Into this: // AbilityInfo info2 = AbilitiesUtil.GetInfo(ability); // Log(info2); - - // === List codes = new(instructions); MethodInfo LogAbilityMethodInfo = SymbolExtensions.GetMethodInfo(() => LogAbilityInfo(Ability.Apparition, null, null)); @@ -675,24 +666,36 @@ private static void LogAbilityInfo(Ability ability, AbilityInfo abilityInfo, Car InscryptionAPIPlugin.Logger.LogError("Cannot find ability " + ability + " for " + info.displayedName); } - #region Remove Duplicate Evolve Mods + #region Evolve Changes [HarmonyPatch(typeof(Evolve), nameof(Evolve.OnUpkeep), MethodType.Enumerator)] [HarmonyTranspiler] - private static IEnumerable EvolveDoesntCopyMods(IEnumerable instructions) + private static IEnumerable EvolveOnUpkeepPatches(IEnumerable instructions) { List codes = new(instructions); - for (int i = 0; i < codes.Count; i++) { - if (codes[i].opcode == OpCodes.Stfld && codes[i].operand.ToString() == "DiskCardGame.CardInfo 5__2") + if (codes[i].opcode == OpCodes.Ldc_I4_5) { + // this probably belongs in the community patches but this transpiler was already here, so eh + // overrides the transformer icon so it can display numbers + MethodInfo customMethod = AccessTools.Method(typeof(AbilityManager), nameof(AbilityManager.OverrideEvolveDerivedIcon), + new Type[] { typeof(Evolve), typeof(int) }); + + i -= 2; + int end = codes.FindIndex(i, x => x.opcode == OpCodes.Ldloc_1); + codes.RemoveRange(i, end - i); + codes.Insert(i++, new(OpCodes.Ldloc_3)); + codes.Insert(i++, new(OpCodes.Call, customMethod)); + } + else if (codes[i].opcode == OpCodes.Stfld && codes[i].operand.ToString() == "DiskCardGame.CardInfo 5__2") + { + // evolve doesn't copy mods object operand = codes[i].operand; MethodInfo customMethod = AccessTools.Method(typeof(AbilityManager), nameof(AbilityManager.RemoveDuplicateMods), new Type[] { typeof(Evolve), typeof(CardInfo) }); i += 2; - - codes.Insert(i, new(OpCodes.Ldloc_1)); + codes.Insert(i++, new(OpCodes.Ldloc_1)); codes.Insert(i++, new(OpCodes.Ldarg_0)); codes.Insert(i++, new(OpCodes.Ldfld, operand)); codes.Insert(i++, new(OpCodes.Call, customMethod)); @@ -702,9 +705,33 @@ private static IEnumerable EvolveDoesntCopyMods(IEnumerable("Art/Cards/AbilityIcons/ability_evolve_" + turnsLeftToEvolve) + ); + } + else if (evolve.Ability == Ability.Transformer && (evolve.Card.Info.evolveParams?.turnsToEvolve ?? 1) != 1) + { + evolve.Card.RenderInfo.OverrideAbilityIcon( + Ability.Transformer, TextureHelper.GetImageAsTexture($"ability_transformer_{turnsLeftToEvolve}.png", typeof(AbilityManager).Assembly) + ); + } + } + private static void RemoveDuplicateMods(Evolve instance, CardInfo evolution) => evolution.Mods.RemoveAll(instance.Card.Info.Mods.Contains); + + [HarmonyPostfix, HarmonyPatch(typeof(Evolve), nameof(Evolve.RemoveTemporaryModsWithEvolve))] + private static void ResetOverrideAndTurnsInPlay(Evolve __instance) { - evolution.Mods.RemoveAll(x => instance.Card.Info.Mods.Contains(x)); + // this stuff is needed to fix problems relating to (intentional) chain evolutions that have different evolution delays + __instance.numTurnsInPlay = 0; + if (__instance.Card.RenderInfo.overriddenAbilityIcons.ContainsKey(__instance.Ability)) + { + __instance.Card.RenderInfo.overriddenAbilityIcons.Remove(__instance.Ability); + __instance.Card.StatsLayer.RenderCard(__instance.Card.RenderInfo); + } } #endregion @@ -714,9 +741,7 @@ private static void ModifyOtherTransformerCosts(ref CardModificationInfo __resul { __result.SetBloodCost(botModeCard.BloodCost - beastModeCard.BloodCost) .SetBonesCost(botModeCard.BonesCost - beastModeCard.BonesCost); - - // no way of nullifying specific gem costs so we leave this out for now - // __result.SetGemsCost(new List(beastModeCard.GemsCost.FindAll(x => !botModeCard.GemsCost.Contains(x)))); + // currently no way of nullifying specific gem costs } [HarmonyPostfix, HarmonyPatch(typeof(Transformer), nameof(Transformer.GetTransformCardInfo))] private static void ChangeTransformerInfoMethod(Transformer __instance, ref CardInfo __result) @@ -725,25 +750,28 @@ private static void ChangeTransformerInfoMethod(Transformer __instance, ref Card } private static CardInfo NewGetTransformCardInfo(PlayableCard card) { - // mods carry over when transforming, so we need to make sure that the name isn't the current card name - // so we don't end up just transforming into the same card over and over again + // mods carry over when transforming now, so make sure that we aren't transforming into ourselves endlessly + // if a modder wants that logic for whatever reason, they can use the evolveParams string transformCardId = card.Info.Mods.Find(x => !string.IsNullOrEmpty(x.transformerBeastCardId) && x.transformerBeastCardId != card.Info.name)?.transformerBeastCardId; - transformCardId ??= card.Info.GetTransformerCardId(); // use the API-defined TransformerCardId - transformCardId ??= card.Info.evolveParams?.evolution?.name; // use the evolution params - transformCardId ??= "CXformerAdder"; // use Robo-Adder as a fallback + // use the API-defined TransformerCardId, evolveParams evolution name, or CSformerAdder as a fallback + transformCardId ??= ((card.Info.GetTransformerCardId() ?? card.Info.evolveParams?.evolution?.name) ?? "CXformerAdder"); CardInfo cardByName = CardLoader.GetCardByName(transformCardId); CardModificationInfo beastModeStatsMod = Transformer.GetBeastModeStatsMod(cardByName, card.Info); beastModeStatsMod.nameReplacement = card.Info.DisplayedNameEnglish; beastModeStatsMod.nonCopyable = true; cardByName.Mods.Add(beastModeStatsMod); - CardModificationInfo item = new(Ability.Transformer) + + // if the evolution already has transformer, assume the modder's set up their own logic we don't want to override + if (cardByName.LacksAbility(Ability.Transformer)) { - nonCopyable = true - }; - cardByName.Mods.Add(item); - cardByName.SetEvolve(card.Info, 1); + cardByName.Mods.Add(new(Ability.Transformer) + { + nonCopyable = true + }); + cardByName.SetEvolve(card.Info, 1); + } if (card.Info.HasSpecialAbility(SpecialTriggeredAbility.TalkingCardChooser)) { @@ -754,6 +782,20 @@ private static CardInfo NewGetTransformCardInfo(PlayableCard card) } return cardByName; } + + [HarmonyPostfix, HarmonyPatch(typeof(AbilityIconInteractable), nameof(AbilityIconInteractable.LoadIcon))] + private static void LoadTransformerIcon(ref Texture __result, CardInfo info, AbilityInfo ability) + { + if (ability.ability != Ability.Transformer) + return; + + // if the num of turns to evolve is 1, use the default, numberless icon so we don't mess with too much of the vanilla visuals + int turnsToEvolve = info?.evolveParams?.turnsToEvolve ?? 1; + if (turnsToEvolve <= 1) + return; + + __result = TextureHelper.GetImageAsTexture($"ability_transformer_{turnsToEvolve}.png", typeof(AbilityManager).Assembly); + } #endregion #region Better Squirrel Orbit @@ -764,7 +806,6 @@ private static bool FixSquirrelOrbit(SquirrelOrbit __instance, ref IEnumerator _ __result = BetterSquirrelOrbit(__instance); return false; } - private static IEnumerator BetterSquirrelOrbit(SquirrelOrbit instance) { List affectedSlots = new(); diff --git a/InscryptionAPI/Card/CardExtensionsHelpers.cs b/InscryptionAPI/Card/CardExtensionsHelpers.cs index 9de3474e..d87f9233 100644 --- a/InscryptionAPI/Card/CardExtensionsHelpers.cs +++ b/InscryptionAPI/Card/CardExtensionsHelpers.cs @@ -611,6 +611,7 @@ public static IEnumerator TransformIntoCardInHand(this PlayableCard card, CardIn preTransformCallback?.Invoke(); card.SetInfo(evolvedInfo); onTransformedCallback?.Invoke(); + AbilityManager.FixStackTriggers(card); } /// /// A version of TransformIntoCardInHand that incorporates MoveCardAboveHand. @@ -626,6 +627,7 @@ public static IEnumerator TransformIntoCardAboveHand(this PlayableCard card, Car preTransformCallback?.Invoke(); card.SetInfo(evolvedInfo); onTransformedCallback?.Invoke(); + AbilityManager.FixStackTriggers(card); } #endregion diff --git a/InscryptionAPI/Card/CardExtensionsSetters.cs b/InscryptionAPI/Card/CardExtensionsSetters.cs index f7a1511f..cad68238 100644 --- a/InscryptionAPI/Card/CardExtensionsSetters.cs +++ b/InscryptionAPI/Card/CardExtensionsSetters.cs @@ -300,17 +300,16 @@ public static CardInfo SetEvolve(this CardInfo info, CardInfo evolveCard, int nu { info.evolveParams = new() { - evolution = evolveCard + evolution = evolveCard, + turnsToEvolve = numberOfTurns }; if (mods != null && mods.Any()) { - info.evolveParams.evolution = CardLoader.Clone(info.evolveParams.evolution); + info.evolveParams.evolution = CardLoader.Clone(info.evolveParams.evolution); // set the evolution to a clone of the evolveCard info (info.evolveParams.evolution.mods ??= new()).AddRange(mods); } - info.evolveParams.turnsToEvolve = numberOfTurns; - return info; } diff --git a/InscryptionAPI/Card/ShieldManager.cs b/InscryptionAPI/Card/ShieldManager.cs index 3b74a203..f15aa690 100644 --- a/InscryptionAPI/Card/ShieldManager.cs +++ b/InscryptionAPI/Card/ShieldManager.cs @@ -1,5 +1,6 @@ using BepInEx.Logging; using DiskCardGame; +using DiskCardGame.CompositeRules; using HarmonyLib; using InscryptionAPI.Helpers; using System.Reflection; @@ -81,8 +82,46 @@ public static bool NewHasShield(PlayableCard instance) return false; } + [HarmonyPrefix, HarmonyPatch(typeof(LatchDeathShield), nameof(LatchDeathShield.OnSuccessfullyLatched))] + private static bool PreventShieldReset() => false; + + //[HarmonyPrefix, HarmonyPatch(typeof(ShieldGeneratorItem), nameof(ShieldGeneratorItem.AddShieldsToCards))] + private static void DontResetShields(ref List resetShieldsSlots) => resetShieldsSlots.Clear(); + + [HarmonyTranspiler, HarmonyPatch(typeof(ShieldGeneratorItem), nameof(ShieldGeneratorItem.ActivateSequence), MethodType.Enumerator)] + private static IEnumerable DontResetOnActivate(IEnumerable instructions) + { + List codes = new(instructions); + int index = codes.FindIndex(x => x.operand?.ToString() == "DiskCardGame.BoardManager get_Instance()"); + MethodBase method = AccessTools.Method(typeof(ShieldManager), nameof(ShieldManager.EmptyList)); + codes.RemoveRange(index, 2); + codes.Insert(index, new(OpCodes.Callvirt, method)); + return codes; + } + [HarmonyTranspiler, HarmonyPatch(typeof(ShieldGems), nameof(ShieldGems.OnResolveOnBoard), MethodType.Enumerator)] + private static IEnumerable DontResetOnResolve(IEnumerable instructions) + { + List codes = new(instructions); + int index = codes.FindLastIndex(x => x.operand?.ToString() == "0.25") - 4; + MethodBase method = AccessTools.Method(typeof(ShieldManager), nameof(ShieldManager.EmptyList)); + codes.RemoveRange(index, 2); + codes.Insert(index, new(OpCodes.Callvirt, method)); + return codes; + } + [HarmonyTranspiler, HarmonyPatch(typeof(RandomCardGainsShieldEffect), nameof(RandomCardGainsShieldEffect.Execute), MethodType.Enumerator)] + private static IEnumerable DontResetOnExecute(IEnumerable instructions) + { + List codes = new(instructions); + int index = codes.FindLastIndex(x => x.opcode == OpCodes.Newobj); + MethodBase method = AccessTools.Method(typeof(ShieldManager), nameof(ShieldManager.EmptyList)); + codes.RemoveRange(index, 4); + codes.Insert(index, new(OpCodes.Callvirt, method)); + return codes; + } + + [HarmonyPrefix, HarmonyPatch(typeof(PlayableCard), nameof(PlayableCard.ResetShield), new Type[] { } )] - private static void ResetModShields(PlayableCard __instance) + private static void ResetModShields(PlayableCard __instance) // runs before the base ResetShield logic { foreach (var com in __instance.GetComponents()) com.ResetShields(false); @@ -91,8 +130,8 @@ private static void ResetModShields(PlayableCard __instance) com.ResetShields(false); __instance.SwitchToDefaultPortrait(); - // base ResetShield runs after this } + private static List EmptyList() => new(); // for transpiler logic (why can't i just pass an empty list?) [HarmonyTranspiler, HarmonyPatch(typeof(PlayableCard), nameof(PlayableCard.UpdateFaceUpOnBoardEffects))] private static IEnumerable BetterHideShieldLogic(IEnumerable instructions) diff --git a/InscryptionAPI/Encounters/OpponentManager.cs b/InscryptionAPI/Encounters/OpponentManager.cs index b8caa827..f9ab05ea 100644 --- a/InscryptionAPI/Encounters/OpponentManager.cs +++ b/InscryptionAPI/Encounters/OpponentManager.cs @@ -260,40 +260,51 @@ public static List RunStateOpponents } #endregion - + #region Optimization Patches [HarmonyPatch] internal class SpawnScenery_Patches { - public static IEnumerable TargetMethods() - { - yield return AccessTools.Method(typeof(Part1BossOpponent), nameof(Part1BossOpponent.SpawnScenery)); - } - - public static bool Prefix(Part1BossOpponent __instance) + [HarmonyPrefix, HarmonyPatch(typeof(Part1BossOpponent), nameof(Part1BossOpponent.SpawnScenery))] + private static bool DisableTableScenery(Part1BossOpponent __instance) { // Show run method if scenery is disabled if (InscryptionAPIPlugin.configHideAct1BossScenery.Value) { __instance.sceneryObject = new GameObject("TemporaryScenary"); __instance.sceneryObject.AddComponent(); + if (__instance is PirateSkullBossOpponent) + __instance.sceneryObject.AddComponent(); return false; } - + + return true; + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(PirateSkullBossCannons), nameof(PirateSkullBossCannons.AimCannons))] + [HarmonyPatch(typeof(PirateSkullBossCannons), nameof(PirateSkullBossCannons.FireLeftSide))] + [HarmonyPatch(typeof(PirateSkullBossCannons), nameof(PirateSkullBossCannons.FireRightSide))] + [HarmonyPatch(typeof(PirateSkullBossCannons), nameof(PirateSkullBossCannons.ResetLeftSide))] + [HarmonyPatch(typeof(PirateSkullBossCannons), nameof(PirateSkullBossCannons.ResetRightSide))] + private static bool DisableCannonAnims() + { + if (InscryptionAPIPlugin.configHideAct1BossScenery.Value) + return false; + return true; } } - + [HarmonyPatch] internal class PreventCallsOnScenary_Patches { - static Type StartNewPhaseSequence = Type.GetType("DiskCardGame.TrapperTraderBossOpponent+d__6, Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"); - static MethodInfo PlayAnimationInfo = AccessTools.Method(typeof(PreventCallsOnScenary_Patches), nameof(PlayAnimation), new[] { typeof(Animation), typeof(string) }); + private static readonly Type StartNewPhaseSequence = Type.GetType("DiskCardGame.TrapperTraderBossOpponent+d__6, Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"); + private static readonly MethodInfo PlayAnimationInfo = AccessTools.Method(typeof(PreventCallsOnScenary_Patches), nameof(PlayAnimation), new[] { typeof(Animation), typeof(string) }); - public static IEnumerable TargetMethods() + private static IEnumerable TargetMethods() { - yield return AccessTools.Method(StartNewPhaseSequence, "MoveNext"); } diff --git a/InscryptionAPI/Guid/GuidManager.cs b/InscryptionAPI/Guid/GuidManager.cs index 54b7d807..202754c4 100644 --- a/InscryptionAPI/Guid/GuidManager.cs +++ b/InscryptionAPI/Guid/GuidManager.cs @@ -51,7 +51,6 @@ unsafe public static T GetEnumValue(string guid, string value) where T : unma string saveKey = $"{typeof(T).Name}_{guid}_{value}"; int enumValue = ModdedSaveManager.SaveData.GetValueAsInt(InscryptionAPIPlugin.ModGUID, saveKey); - if (enumValue == default) { lock (lockObject) @@ -68,7 +67,6 @@ unsafe public static T GetEnumValue(string guid, string value) where T : unma } reverseMapper[enumValue] = typeof(T); - return *(T*)&enumValue; } diff --git a/InscryptionAPI/InscryptionAPI.csproj b/InscryptionAPI/InscryptionAPI.csproj index 92770ac7..c2bba128 100644 --- a/InscryptionAPI/InscryptionAPI.csproj +++ b/InscryptionAPI/InscryptionAPI.csproj @@ -10,7 +10,7 @@ full false true - 2.18.5 + 2.18.6 diff --git a/InscryptionAPI/InscryptionAPIPlugin.cs b/InscryptionAPI/InscryptionAPIPlugin.cs index ec07c1fa..9267643a 100644 --- a/InscryptionAPI/InscryptionAPIPlugin.cs +++ b/InscryptionAPI/InscryptionAPIPlugin.cs @@ -27,7 +27,7 @@ public class InscryptionAPIPlugin : BaseUnityPlugin { public const string ModGUID = "cyantist.inscryption.api"; public const string ModName = "InscryptionAPI"; - public const string ModVer = "2.18.5"; + public const string ModVer = "2.18.6"; public static string Directory = ""; diff --git a/InscryptionCommunityPatch/Assets/PixelTransformer.png b/InscryptionCommunityPatch/Assets/PixelTransformer.png new file mode 100644 index 00000000..4fc6a490 Binary files /dev/null and b/InscryptionCommunityPatch/Assets/PixelTransformer.png differ diff --git a/InscryptionCommunityPatch/Assets/pixel_evolve_0.png b/InscryptionCommunityPatch/Assets/pixel_evolve_0.png deleted file mode 100644 index 4358c189..00000000 Binary files a/InscryptionCommunityPatch/Assets/pixel_evolve_0.png and /dev/null differ diff --git a/InscryptionCommunityPatch/Assets/pixel_transformer_1.png b/InscryptionCommunityPatch/Assets/pixel_transformer_1.png new file mode 100644 index 00000000..cad69c19 Binary files /dev/null and b/InscryptionCommunityPatch/Assets/pixel_transformer_1.png differ diff --git a/InscryptionCommunityPatch/Assets/pixel_transformer_2.png b/InscryptionCommunityPatch/Assets/pixel_transformer_2.png new file mode 100644 index 00000000..de4b91fb Binary files /dev/null and b/InscryptionCommunityPatch/Assets/pixel_transformer_2.png differ diff --git a/InscryptionCommunityPatch/Assets/pixel_transformer_3.png b/InscryptionCommunityPatch/Assets/pixel_transformer_3.png new file mode 100644 index 00000000..d48ce46e Binary files /dev/null and b/InscryptionCommunityPatch/Assets/pixel_transformer_3.png differ diff --git a/InscryptionCommunityPatch/Card/ArtPatches.cs b/InscryptionCommunityPatch/Card/ArtPatches.cs index 0deb7fcc..d7e4052c 100644 --- a/InscryptionCommunityPatch/Card/ArtPatches.cs +++ b/InscryptionCommunityPatch/Card/ArtPatches.cs @@ -58,6 +58,7 @@ internal static class CommunityArtPatches Ability.ShieldGems, Ability.Sniper, Ability.TailOnHit, + Ability.Transformer, Ability.SquirrelOrbit, Ability.DrawVesselOnHit }; diff --git a/InscryptionCommunityPatch/Card/Part2CardCostRender.cs b/InscryptionCommunityPatch/Card/Part2CardCostRender.cs index 97b62f3e..5aa12450 100644 --- a/InscryptionCommunityPatch/Card/Part2CardCostRender.cs +++ b/InscryptionCommunityPatch/Card/Part2CardCostRender.cs @@ -16,11 +16,11 @@ public static class Part2CardCostRender public static event Action> UpdateCardCost; + public static bool RightAct2Cost => PatchPlugin.rightAct2Cost.Value; + public static Texture2D BlankPixelCost() => TextureHelper.GetImageAsTexture("pixel_blank.png", typeof(Part2CardCostRender).Assembly); + public static Texture2D CombineIconAndCount(int cardCost, Texture2D artCost) { - bool left = !PatchPlugin.rightAct2Cost.Value; - Texture2D baseTexture = TextureHelper.GetImageAsTexture("pixel_blank.png", typeof(Part2CardCostRender).Assembly); - List list = new(); if (cardCost <= 4) { @@ -33,14 +33,12 @@ public static Texture2D CombineIconAndCount(int cardCost, Texture2D artCost) list.Add(TextureHelper.GetImageAsTexture($"pixel_L_{cardCost}.png", typeof(Part2CardCostRender).Assembly)); } - int xOffset = left ? 0 : cardCost >= 10 ? 30 - 20 - artCost.width : cardCost <= 4 ? 30 - artCost.width * cardCost : 30 - 14 - artCost.width; - return TextureHelper.CombineTextures(list, baseTexture, xOffset: xOffset, xStep: artCost.width); + int xOffset = !RightAct2Cost ? 0 : cardCost >= 10 ? 30 - 20 - artCost.width : cardCost <= 4 ? 30 - artCost.width * cardCost : 30 - 14 - artCost.width; + return TextureHelper.CombineTextures(list, BlankPixelCost(), xOffset: xOffset, xStep: artCost.width); } public static Sprite Part2SpriteFinal(CardInfo card) { - bool left = !PatchPlugin.rightAct2Cost.Value; - // A list to hold the textures (important later, to combine them all) List masterList = new(); @@ -57,7 +55,7 @@ public static Sprite Part2SpriteFinal(CardInfo card) { List gemCost = new(); - //If a card has a green mox, set the green mox + // Order of: green, orange, blue if (card.GemsCost.Contains(GemType.Green)) gemCost.Add(TextureHelper.GetImageAsTexture("pixel_mox_green.png", typeof(Part2CardCostRender).Assembly)); @@ -67,12 +65,11 @@ public static Sprite Part2SpriteFinal(CardInfo card) if (card.GemsCost.Contains(GemType.Blue)) gemCost.Add(TextureHelper.GetImageAsTexture("pixel_mox_blue.png", typeof(Part2CardCostRender).Assembly)); - Texture2D gemBaseTexture = TextureHelper.GetImageAsTexture("pixel_blank.png", typeof(Part2CardCostRender).Assembly); - - if (!left) + if (RightAct2Cost) gemCost.Reverse(); - masterList.Add(TextureHelper.CombineTextures(gemCost, gemBaseTexture, xOffset: left ? 0 : 30 - 7 * gemCost.Count, xStep: 7)); + masterList.Add(TextureHelper.CombineTextures(gemCost, BlankPixelCost(), + xOffset: !RightAct2Cost ? 0 : (30 - 7 * gemCost.Count), xStep: 7)); } // Call the event and allow others to modify the list of textures @@ -86,7 +83,7 @@ public static Sprite Part2SpriteFinal(CardInfo card) Texture2D finalTexture = TextureHelper.CombineTextures(masterList, baseTexture, yStep: 8); //Convert the final texture to a sprite - Sprite finalSprite = TextureHelper.ConvertTexture(finalTexture, left ? TextureHelper.SpriteType.Act2CostDecalLeft : TextureHelper.SpriteType.Act2CostDecalRight); + Sprite finalSprite = TextureHelper.ConvertTexture(finalTexture, !RightAct2Cost ? TextureHelper.SpriteType.Act2CostDecalLeft : TextureHelper.SpriteType.Act2CostDecalRight); return finalSprite; } diff --git a/InscryptionCommunityPatch/Card/StackAbilityIcons.cs b/InscryptionCommunityPatch/Card/StackAbilityIcons.cs index 0301a422..d3799333 100644 --- a/InscryptionCommunityPatch/Card/StackAbilityIcons.cs +++ b/InscryptionCommunityPatch/Card/StackAbilityIcons.cs @@ -425,15 +425,24 @@ private static void AddStackCount(SpriteRenderer abilityRenderer, Tuple()?.numTurnsInPlay ?? 0; int turnsToEvolve = Mathf.Max(1, (cardInfo.evolveParams == null ? 1 : cardInfo.evolveParams.turnsToEvolve) - turnsInPlay); int pngIndex = turnsToEvolve > 3 ? 0 : turnsToEvolve; + + if (pngIndex == 0) + return abilityInfo.pixelIcon; - Texture2D texture = TextureHelper.GetImageAsTexture($"pixel_evolve_{pngIndex}.png", typeof(StackAbilityIcons).Assembly); + Texture2D texture; + if (abilityInfo.ability == Ability.Evolve) + texture = TextureHelper.GetImageAsTexture($"pixel_evolve_{pngIndex}.png", typeof(StackAbilityIcons).Assembly); + else + texture = TextureHelper.GetImageAsTexture($"pixel_transformer_{pngIndex}.png", typeof(StackAbilityIcons).Assembly); + return TextureHelper.ConvertTexture(texture, TextureHelper.SpriteType.PixelAbilityIcon); } + if (card && card.RenderInfo.overriddenAbilityIcons.ContainsKey(abilityInfo.ability)) { card.RenderInfo.overriddenAbilityIcons.TryGetValue(abilityInfo.ability, out Texture texture); diff --git a/InscryptionCommunityPatch/Card/Vanilla Ability Patches/DefaultEvolveFix.cs b/InscryptionCommunityPatch/Card/Vanilla Ability Patches/DefaultEvolveFix.cs index 41b6a5b6..26f483d4 100644 --- a/InscryptionCommunityPatch/Card/Vanilla Ability Patches/DefaultEvolveFix.cs +++ b/InscryptionCommunityPatch/Card/Vanilla Ability Patches/DefaultEvolveFix.cs @@ -13,7 +13,6 @@ public class DefaultEvolveFix private static void FixDefaultEvolveParamsIL(ILContext il) { ILCursor c = new(il); - int modLoc = -1; c.GotoNext(MoveType.Before, x => x.MatchNewobj(AccessTools.DeclaredConstructor(typeof(CardModificationInfo), new[] { typeof(int), typeof(int) }))); diff --git a/InscryptionCommunityPatch/ResourceManagers/ActOneEnergyDrone.cs b/InscryptionCommunityPatch/ResourceManagers/ActOneEnergyDrone.cs index 4381f1c8..4fdba02b 100644 --- a/InscryptionCommunityPatch/ResourceManagers/ActOneEnergyDrone.cs +++ b/InscryptionCommunityPatch/ResourceManagers/ActOneEnergyDrone.cs @@ -20,6 +20,14 @@ public class EnergyConfigInfo public bool ConfigDroneMox => PoolHasGems || PatchPlugin.configDroneMox.Value; } + public static Dictionary ZoneConfigs = new() + { + { CardTemple.Nature, new() }, + { CardTemple.Undead, new() }, + { CardTemple.Tech, new() }, + { CardTemple.Wizard, new() } + }; + public static bool SceneCanHaveEnergyDrone(string sceneName) { string activeSceneName = sceneName.ToLowerInvariant(); @@ -38,14 +46,6 @@ public static bool CurrentSceneCanHaveEnergyDrone } } - public static Dictionary ZoneConfigs = new() - { - { CardTemple.Nature, new() }, - { CardTemple.Undead, new() }, - { CardTemple.Tech, new() }, - { CardTemple.Wizard, new() } - }; - private static EnergyConfigInfo EnergyConfig { get @@ -91,13 +91,31 @@ internal static void TryEnableEnergy(string sceneName) PoolHasGems = CardManager.AllCardsCopy.Any(ci => ci.gemsCost.Count > 0 && ci.CardIsVisible(targetTemple)); PatchPlugin.Logger.LogDebug($"Card pool has Energy cards? {PoolHasEnergy}. Card pool has Gem cards? {PoolHasGems}."); - - ResourceDrone drone = UnityObject.Instantiate(Resources.Load("prefabs/cardbattle/ResourceModules")); + UnityObject.Instantiate(Resources.Load("prefabs/cardbattle/ResourceModules")); if (EnergyConfig.ConfigDrone) PatchPlugin.Instance.StartCoroutine(AwakeDrone()); } + private static IEnumerator AwakeDrone() + { + // pretty sure the drone can't be null in this method, but we'll check just in case + if (ResourceDrone.m_Instance == null) + yield break; + + if (PatchPlugin.configFullDebug.Value) + PatchPlugin.Logger.LogDebug($"Awaking ResourceDrone, instance exists? {ResourceDrone.Instance != null}."); + + yield return new WaitForSeconds(1f); + ResourceDrone.Instance.Awake(); + yield return new WaitForSeconds(1f); + ResourceDrone.Instance.AttachGemsModule(); + + if (EnergyConfig.ConfigDefaultDrone) + ResourceDrone.Instance.gameObject.transform.localPosition = ResourceDrone.Instance.boardPosition + Vector3.up * 5f; + else + AttachDroneToScale(); + } private static void AttachDroneToScale() { try @@ -117,26 +135,6 @@ private static void AttachDroneToScale() } catch { PatchPlugin.Logger.LogError("Couldn't attach ResourceDrone to LifeManager.Scale3D!"); } } - private static IEnumerator AwakeDrone() - { - yield return new WaitForSeconds(1f); - - if (PatchPlugin.configFullDebug.Value) - PatchPlugin.Logger.LogDebug($"Awaking ResourceDrone, instance exists? {ResourceDrone.Instance != null}."); - - ResourceDrone.Instance?.Awake(); - yield return new WaitForSeconds(1f); - ResourceDrone.Instance?.AttachGemsModule(); - - // not sure if the drone can be null in this method, but we'll check just in case - if (ResourceDrone.m_Instance != null) - { - if (EnergyConfig.ConfigDefaultDrone) - ResourceDrone.Instance.gameObject.transform.localPosition = ResourceDrone.Instance.boardPosition + Vector3.up * 5f; - else - AttachDroneToScale(); - } - } [HarmonyPatch(typeof(ResourceDrone), nameof(ResourceDrone.SetOnBoard))] [HarmonyPrefix] @@ -180,11 +178,10 @@ private static bool Act1ResourceDrone_SetOnBoard(ResourceDrone __instance, bool [HarmonyPrefix] private static void Part1ResourcesManager_CleanUp(Part1ResourcesManager __instance) { - ResourcesManager baseResourceManager = __instance; if (EnergyConfig.ConfigEnergy) { - baseResourceManager.PlayerEnergy = 0; - baseResourceManager.PlayerMaxEnergy = 0; + __instance.PlayerEnergy = 0; + __instance.PlayerMaxEnergy = 0; } if (EnergyConfig.ConfigDrone && ResourceDrone.m_Instance != null) @@ -192,7 +189,7 @@ private static void Part1ResourcesManager_CleanUp(Part1ResourcesManager __instan ResourceDrone.Instance.CloseAllCells(false); ResourceDrone.Instance.SetOnBoard(false, false); if (EnergyConfig.ConfigDroneMox) - ResourceDrone.Instance.Gems.SetAllGemsOn(false, false); + ResourceDrone.Instance.Gems?.SetAllGemsOn(false, false); } if (EnergyConfig.ConfigMox) __instance.gems.Clear(); @@ -202,13 +199,13 @@ private static void Part1ResourcesManager_CleanUp(Part1ResourcesManager __instan [HarmonyPrefix] private static void ResourcesManager_Setup(ResourcesManager __instance) { - if (__instance is Part1ResourcesManager && EnergyConfig.ConfigDrone) + if (__instance is Part1ResourcesManager && EnergyConfig.ConfigDrone && ResourceDrone.m_Instance != null) { - ResourceDrone.Instance?.SetOnBoard(true, false); + ResourceDrone.Instance.SetOnBoard(true, false); if (EnergyConfig.ConfigDroneMox) { - PatchPlugin.Logger.LogDebug("Setting up extra resources for the drone."); - ResourceDrone.Instance?.Gems.SetAllGemsOn(false, true); + PatchPlugin.Logger.LogDebug("Setting up extra drone resources."); + ResourceDrone.Instance.Gems.SetAllGemsOn(false, true); } } } @@ -217,10 +214,10 @@ private static void ResourcesManager_Setup(ResourcesManager __instance) [HarmonyPostfix] private static IEnumerator ResourcesManager_ShowAddMaxEnergy(IEnumerator result, ResourcesManager __instance) { - if (__instance is Part1ResourcesManager && EnergyConfig.ConfigDrone) + if (__instance is Part1ResourcesManager && EnergyConfig.ConfigDrone && ResourceDrone.m_Instance != null) { int cellsToOpen = __instance.PlayerMaxEnergy - 1; - ResourceDrone.Instance?.OpenCell(cellsToOpen); + ResourceDrone.Instance.OpenCell(cellsToOpen); yield return new WaitForSeconds(0.4f); } @@ -231,12 +228,12 @@ private static IEnumerator ResourcesManager_ShowAddMaxEnergy(IEnumerator result, [HarmonyPostfix] private static IEnumerator ResourcesManager_ShowAddEnergy(IEnumerator result, int amount, ResourcesManager __instance) { - if (__instance is Part1ResourcesManager && EnergyConfig.ConfigDrone) + if (__instance is Part1ResourcesManager && EnergyConfig.ConfigDrone && ResourceDrone.m_Instance != null) { int num; for (int i = __instance.PlayerEnergy - amount; i < __instance.PlayerEnergy; i = num + 1) { - ResourceDrone.Instance?.SetCellOn(i, true, false); + ResourceDrone.Instance.SetCellOn(i, true, false); yield return new WaitForSeconds(0.05f); num = i; } @@ -249,7 +246,7 @@ private static IEnumerator ResourcesManager_ShowAddEnergy(IEnumerator result, in [HarmonyPostfix] private static IEnumerator ResourcesManager_ShowSpendEnergy(IEnumerator result, int amount, ResourcesManager __instance) { - if (__instance is Part1ResourcesManager && EnergyConfig.ConfigDrone) + if (__instance is Part1ResourcesManager && EnergyConfig.ConfigDrone && ResourceDrone.m_Instance != null) { int num; for (int i = __instance.PlayerEnergy + amount - 1; i >= __instance.PlayerEnergy; i = num - 1) @@ -258,7 +255,7 @@ private static IEnumerator ResourcesManager_ShowSpendEnergy(IEnumerator result, __instance.transform.position, 0.4f, 0f, new AudioParams.Pitch(0.9f + (float)(__instance.PlayerEnergy + i) * 0.05f), null, null, null, false); - ResourceDrone.Instance?.SetCellOn(i, false, false); + ResourceDrone.Instance.SetCellOn(i, false, false); yield return new WaitForSeconds(0.05f); num = i; } @@ -289,7 +286,6 @@ private static IEnumerator ResourcesManager_ShowLoseGem(IEnumerator result, GemT __instance.SetGemOnImmediate(gem, false); yield return new WaitForSeconds(0.05f); } - yield return result; } @@ -297,7 +293,7 @@ private static IEnumerator ResourcesManager_ShowLoseGem(IEnumerator result, GemT [HarmonyPostfix] private static void ResourcesManager_SetGemOnImmediate(GemType gem, bool on, ResourcesManager __instance) { - if (__instance is Part1ResourcesManager) + if (__instance is Part1ResourcesManager && ResourceDrone.m_Instance != null) ResourceDrone.Instance.Gems?.SetGemOn(gem, on, false); } @@ -309,7 +305,7 @@ private static IEnumerator TurnManager_UpkeepPhase(IEnumerator sequence, bool pl // If the game is not going to automatically update the energy, I'll do it yield return sequence; - if (CurrentSceneCanHaveEnergyDrone && EnergyConfig.ConfigEnergy && playerUpkeep) + if (playerUpkeep && CurrentSceneCanHaveEnergyDrone && EnergyConfig.ConfigEnergy) { bool showEnergyModule = !ResourcesManager.Instance.EnergyAtMax || ResourcesManager.Instance.PlayerEnergy < ResourcesManager.Instance.PlayerMaxEnergy; if (showEnergyModule) diff --git a/docs/wiki/custom_costs.md b/docs/wiki/custom_costs.md index 2e756918..139453cd 100644 --- a/docs/wiki/custom_costs.md +++ b/docs/wiki/custom_costs.md @@ -2,8 +2,8 @@ --- The Inscryption Community Patch allows for custom card costs to be displayed in all three main acts of the game: -### Acts 1 and Act 2 -If you want to have your card display a custom card cost in either Act 1 (Leshy's Cabin) or Act 2 (pixel/GBC cards), you can simply hook into one of the following events: +### Acts 1 +If you want to have your card display a custom card cost in either Act 1 (Leshy's Cabin), you can simply hook into one of the following events: ```c# using InscryptionCommunityPatch.Card; @@ -11,18 +11,39 @@ using InscryptionAPI.Helpers; Part1CardCostRender.UpdateCardCost += delegate(CardInfo card, List costs) { - int myCustomCost = card.GetExtensionPropertyAsInt("myCustomCardCost"); + int myCustomCost = card.GetExtensionPropertyAsInt("myCustomCardCost") ?? 0; // GetExtensionPropertyAsInt can return null, so remember to check for that if (myCustomCost > 0) costs.Add(TextureHelper.GetImageAsTexture($"custom_cost_{myCustomCost}.png")); } +``` + +### Act 2 +For adding custom costs to Act 2, you have two main ways of going about it: +```c# +using InscryptionCommunityPatch.Card; +using InscryptionAPI.Helpers; + +// if you want the API to handle adding stack numbers, provide a - 7x8 - texture representing your cost's icon. Part2CardCostRender.UpdateCardCost += delegate(CardInfo card, List costs) { - int myCustomCost = card.GetExtensionPropertyAsInt("myCustomCardCost_pixel"); + int myCustomCost = card.GetExtensionPropertyAsInt("myCustomCardCost_pixel") ?? 0; if (myCustomCost > 0) + { + Texture2D customCostTexture = TextureHelper.GetImageAsTexture($"custom_cost_pixel.png"); + costs.Add(Part2CardCostRender.CombineIconAndCount(myCustomCost, customCostTexture)); + } +} + +// if you want more control over your cost's textures, or don't want to use stack numbers, provide a - 30x8 - texture for your custom cost. +Part2CardCostRender.UpdateCardCost += delegate(CardInfo card, List costs) +{ + int myCustomCost = card.GetExtensionPropertyAsInt("myCustomCardCost_pixel") ?? 0; + if (myCustomCost > 0) + { costs.Add(TextureHelper.GetImageAsTexture($"custom_cost_{myCustomCost}_pixel.png")); + } } ``` - ### Act 3 Custom card costs in Act 3 are a little more complex due to the fact that the Disk Card model displays card costs as 3D objects instead of texture rendered on the card art. As such, you actually have a little more control over how your custom costs are displayed if you want it.