Repository navigation
Add way to easily patch and modify the default bone gain when a player's card dies #341
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Chaosyr
merged 10 commits into
InscryptionModding:Update-Installation-Guides-and-Documentation-and-Bug-Fixes
from
HumabHatterZed:bone-hooks
Oct 30, 2026
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
6ea927e
Stop compiling causing the bin folder to fill with local lock assembl…
HumabHatterZed 9fb5225
Add way to easily patch and modify the default bone gain when a playe…
HumabHatterZed 2736595
Remove debug logging
HumabHatterZed 9a05678
Remove erroneously copied-over method
HumabHatterZed 59846b9
Remove changelog to avoid merge conflict
HumabHatterZed 100d9b7
Add XML documentation
HumabHatterZed b511fdc
Remove unneeded usings
HumabHatterZed f806ecd
(Hopefully) revert changes to csproj files in lieu of changes in #339
HumabHatterZed 3de3513
Merge branch 'Update-Installation-Guides-and-Documentation-and-Bug-Fi…
HumabHatterZed 8b31c7f
Update CHANGELOG.md
Chaosyr File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,135 @@ | ||
| using DiskCardGame; | ||
| using HarmonyLib; | ||
| using System.Collections; | ||
| using System.Reflection; | ||
| using System.Reflection.Emit; | ||
|
|
||
| namespace InscryptionAPI.Card; | ||
|
|
||
| /// <summary> | ||
| /// Class for handling exposing the bone-on-death behaviour present in the vanilla PlayableCard.Die method. | ||
| /// Allows for modifying the default behaviour through Harmony patches. | ||
| /// </summary> | ||
| [HarmonyPatch] | ||
| public class DefaultBoneGainOnDeath { | ||
| // this method does not need XML documentation since it's purely internal to make the other two methods work. | ||
| // I also don't want to explain how transpilers work. | ||
| [HarmonyTranspiler] | ||
| [HarmonyPatch(typeof(PlayableCard), nameof(PlayableCard.Die), MethodType.Enumerator)] | ||
| private static IEnumerable<CodeInstruction> InsertBoneMethodHook(IEnumerable<CodeInstruction> instructions) | ||
| { | ||
| // === We want to turn this | ||
|
|
||
| // if (!HasAbility(Ability.QuadrupleBones) && slotBeforeDeath.IsPlayerSlot) { | ||
| // yield return Singleton<ResourcesManager>.Instance.AddBones(1, slotBeforeDeath); | ||
| // } | ||
|
|
||
| // === Into this | ||
|
|
||
| // if (ShouldDoDefaultBoneGain(base.Card, slotBeforeDeath) { | ||
| // yield return DoDefaultBoneGain(base.Card, slotBeforeDeath, 1); | ||
| // } | ||
|
|
||
| // === | ||
| List<CodeInstruction> codes = new(instructions); | ||
|
|
||
| for (int i = 0; i < codes.Count; i++) { | ||
| // there are two instances where this is true, but we only care about the first instance | ||
| // the second instance will be ignored | ||
| if (codes[i].opcode == OpCodes.Ldc_I4_S && codes[i].operand.ToString() == "12") { | ||
| /* | ||
| * // if (!playableCard.HasAbility(Ability.QuadrupleBones) && <slotBeforeDeath>5__2.IsPlayerSlot) | ||
| * ldloc.1 | ||
| * ldc.i4.s 12 | ||
| * call instance bool DiskCardGame.PlayableCard::HasAbility(valuetype DiskCardGame.Ability) | ||
| * brtrue.s IL_022f | ||
| * | ||
| * ldarg.0 | ||
| * ldfld class DiskCardGame.CardSlot DiskCardGame.PlayableCard/'<Die>d__98'::'<slotBeforeDeath>5__2' | ||
| * callvirt instance bool DiskCardGame.CardSlot::get_IsPlayerSlot() | ||
| * brfalse.s IL_022f | ||
| * | ||
| * = | ||
| * | ||
| * // if (ShouldDoDefaultBoneGain(playableCard, <slotBeforeDeath>5__2) | ||
| * ldloc.1 | ||
| * ldarg.0 | ||
| * ldfld class DiskCardGame.CardSlot DiskCardGame.PlayableCard/'<Die>d__98'::'<slotBeforeDeath>5__2' | ||
| * callvirt ShouldDo... | ||
| * brfalse.s IL_022f | ||
| */ | ||
| MethodInfo validationMethod = AccessTools.Method( | ||
| typeof(DefaultBoneGainOnDeath), nameof(ShouldDoDefaultBoneGain), | ||
| new Type[] { typeof(PlayableCard), typeof(CardSlot) }); | ||
|
|
||
| codes.RemoveAt(i); | ||
| codes.RemoveAt(i); | ||
| codes.RemoveAt(i); | ||
| i += 2; | ||
| codes[i] = new CodeInstruction(OpCodes.Callvirt, validationMethod); | ||
|
|
||
| /* | ||
| * // <>2__current = Singleton<ResourcesManager>.Instance.AddBones(1, <slotBeforeDeath>5__2); | ||
| * ldarg.0 | ||
| * call !0 class Singleton`1<class DiskCardGame.ResourcesManager>::get_Instance() | ||
| * ldc.i4.1 | ||
| * ldarg.0 | ||
| * ldfld class DiskCardGame.CardSlot DiskCardGame.PlayableCard/'<Die>d__98'::'<slotBeforeDeath>5__2' | ||
| * callvirt instance class [netstandard]System.Collections.IEnumerator DiskCardGame.ResourcesManager::AddBones(int32, class DiskCardGame.CardSlot) | ||
| * stfld object DiskCardGame.PlayableCard/'<Die>d__98'::'<>2__current' | ||
| * | ||
| * = | ||
| * | ||
| * // <>2__current = DoDefaultBoneGain(playableCard, slotBeforeDeath, 1); | ||
| * ldarg.0 | ||
| * ldloc.1 | ||
| * ldarg.0 | ||
| * ldfld class DiskCardGame.CardSlot DiskCardGame.PlayableCard/'<Die>d__98'::'<slotBeforeDeath>5__2' | ||
| * ldc.i4.1 | ||
| * callvirt DoDefaultBoneGain | ||
| * stfld object DiskCardGame.PlayableCard/'<Die>d__98'::'<>2__current' | ||
| */ | ||
|
|
||
| MethodInfo executionMethod = AccessTools.Method( | ||
| typeof(DefaultBoneGainOnDeath), nameof(DoDefaultBoneGain), | ||
| new Type[] { typeof(PlayableCard), typeof(CardSlot), typeof(int) }); | ||
|
|
||
| i += 3; | ||
| codes[i] = new CodeInstruction(OpCodes.Ldloc_1); | ||
| i++; | ||
|
|
||
| // since codes are taken from the top of the stack, we need to move the ldc.i4.1 to be AFTER we call slotBeforeDeath | ||
| codes.RemoveAt(i); | ||
|
|
||
| i += 2; | ||
|
|
||
| codes.Insert(i, new CodeInstruction(OpCodes.Ldc_I4_1)); | ||
| i++; | ||
|
|
||
| codes[i] = new CodeInstruction(OpCodes.Callvirt, executionMethod); | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| return codes; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Simple boolean check that by default replicates the vanilla check for whether a card should award a Bone on death. | ||
| /// </summary> | ||
| /// <param name="card">The PlayableCard that has died.</param> | ||
| /// <param name="slotBeforeDeath">The CardSlot of card.</param> | ||
| /// <returns>True if card should give a Bone (calls DoDefaultBoneGain).</returns> | ||
| public static bool ShouldDoDefaultBoneGain(PlayableCard card, CardSlot slotBeforeDeath) { | ||
|
Chaosyr marked this conversation as resolved.
Resolved
|
||
| return slotBeforeDeath.IsPlayerSlot && !card.HasAbility(Ability.QuadrupleBones); | ||
| } | ||
| /// <summary> | ||
| /// A simple call to ResourcesManager.AddBones, intended to give modders some more flexibility over the default death behaviour of player cards giving 1 Bone. | ||
| /// </summary> | ||
| /// <param name="card">The PlayableCard that has died.</param> | ||
| /// <param name="slotBeforeDeath">The CardSlot of card.</param> | ||
| /// <param name="amount">How many Bones to drop whenever a player's card dies (default is 1).</param> | ||
| public static IEnumerator DoDefaultBoneGain(PlayableCard card, CardSlot slotBeforeDeath, int amount) { | ||
| yield return Singleton<ResourcesManager>.Instance.AddBones(amount, slotBeforeDeath); | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.