diff --git a/CHANGELOG.md b/CHANGELOG.md
index a68919c9..238714d5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,11 +9,13 @@
- This comes with 5 new Dictionaries `BaseGameCustomAppearances` (Internal), `BaseGameCustomAppearancesPublic`, `ModdedCustomAppearancesDictionary` (Internal), `ModdedCustomAppearancesDictionaryPublic`, `CombinedCustomAppearancesDictionaryPublic`.
- This system is stored under the `TextureHelper` class.
* Improved In-Code Documentation via XML Comments.
+* Added a way to easily patch and modify the default bone gain when a player's card dies.
+* Added the following class: `DefaultBoneGainOnDeath` and the following methods within that class: `DefaultBoneGainOnDeath.ShouldDoDefaultBoneGain` and `DefaultBoneGainOnDeeath.DoDefaultBoneGain`
# 2.24.1
-* Added Extensions for setting the IconTexture of a Starter Deck.
-* Added 2 Alternate Constructors for making a StarterDeck with a Display Name different from its Internal Name.
-* Added Getters and Setters for Starter Deck Unlock Level.
+- Added Extensions for setting the IconTexture of a Starter Deck.
+- Added 2 Alternate Constructors for making a StarterDeck with a Display Name different from its Internal Name.
+- Added Getters and Setters for Starter Deck Unlock Level.
# 2.24.0
- Fixed Part2CardCostRender.UpdatePlayableCardCost not being invoked
@@ -792,4 +794,4 @@
- Custom cards are added via the **CustomCard** constructor rather than through the **AddCard** method.
# v1.1
-- Hooked into a much more sensible method to load the cards into the card pool.
\ No newline at end of file
+- Hooked into a much more sensible method to load the cards into the card pool.
diff --git a/InscryptionAPI/Card/DefaultBoneGainOnDeath.cs b/InscryptionAPI/Card/DefaultBoneGainOnDeath.cs
new file mode 100644
index 00000000..fc40bb0b
--- /dev/null
+++ b/InscryptionAPI/Card/DefaultBoneGainOnDeath.cs
@@ -0,0 +1,135 @@
+using DiskCardGame;
+using HarmonyLib;
+using System.Collections;
+using System.Reflection;
+using System.Reflection.Emit;
+
+namespace InscryptionAPI.Card;
+
+///
+/// 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.
+///
+[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 InsertBoneMethodHook(IEnumerable instructions)
+ {
+ // === We want to turn this
+
+ // if (!HasAbility(Ability.QuadrupleBones) && slotBeforeDeath.IsPlayerSlot) {
+ // yield return Singleton.Instance.AddBones(1, slotBeforeDeath);
+ // }
+
+ // === Into this
+
+ // if (ShouldDoDefaultBoneGain(base.Card, slotBeforeDeath) {
+ // yield return DoDefaultBoneGain(base.Card, slotBeforeDeath, 1);
+ // }
+
+ // ===
+ List 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) && 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/'d__98'::'5__2'
+ * callvirt instance bool DiskCardGame.CardSlot::get_IsPlayerSlot()
+ * brfalse.s IL_022f
+ *
+ * =
+ *
+ * // if (ShouldDoDefaultBoneGain(playableCard, 5__2)
+ * ldloc.1
+ * ldarg.0
+ * ldfld class DiskCardGame.CardSlot DiskCardGame.PlayableCard/'d__98'::'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.Instance.AddBones(1, 5__2);
+ * ldarg.0
+ * call !0 class Singleton`1::get_Instance()
+ * ldc.i4.1
+ * ldarg.0
+ * ldfld class DiskCardGame.CardSlot DiskCardGame.PlayableCard/'d__98'::'5__2'
+ * callvirt instance class [netstandard]System.Collections.IEnumerator DiskCardGame.ResourcesManager::AddBones(int32, class DiskCardGame.CardSlot)
+ * stfld object DiskCardGame.PlayableCard/'d__98'::'<>2__current'
+ *
+ * =
+ *
+ * // <>2__current = DoDefaultBoneGain(playableCard, slotBeforeDeath, 1);
+ * ldarg.0
+ * ldloc.1
+ * ldarg.0
+ * ldfld class DiskCardGame.CardSlot DiskCardGame.PlayableCard/'d__98'::'5__2'
+ * ldc.i4.1
+ * callvirt DoDefaultBoneGain
+ * stfld object DiskCardGame.PlayableCard/'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;
+ }
+
+ ///
+ /// Simple boolean check that by default replicates the vanilla check for whether a card should award a Bone on death.
+ ///
+ /// The PlayableCard that has died.
+ /// The CardSlot of card.
+ /// True if card should give a Bone (calls DoDefaultBoneGain).
+ public static bool ShouldDoDefaultBoneGain(PlayableCard card, CardSlot slotBeforeDeath) {
+ return slotBeforeDeath.IsPlayerSlot && !card.HasAbility(Ability.QuadrupleBones);
+ }
+ ///
+ /// A simple call to ResourcesManager.AddBones, intended to give modders some more flexibility over the default death behaviour of player cards giving 1 Bone.
+ ///
+ /// The PlayableCard that has died.
+ /// The CardSlot of card.
+ /// How many Bones to drop whenever a player's card dies (default is 1).
+ public static IEnumerator DoDefaultBoneGain(PlayableCard card, CardSlot slotBeforeDeath, int amount) {
+ yield return Singleton.Instance.AddBones(amount, slotBeforeDeath);
+ }
+}
diff --git a/InscryptionAPI/InscryptionAPI.csproj b/InscryptionAPI/InscryptionAPI.csproj
index 84e11198..268c4a87 100644
--- a/InscryptionAPI/InscryptionAPI.csproj
+++ b/InscryptionAPI/InscryptionAPI.csproj
@@ -58,7 +58,7 @@
-
+
diff --git a/InscryptionCommunityPatch/InscryptionCommunityPatch.csproj b/InscryptionCommunityPatch/InscryptionCommunityPatch.csproj
index 64344fb5..ba313073 100644
--- a/InscryptionCommunityPatch/InscryptionCommunityPatch.csproj
+++ b/InscryptionCommunityPatch/InscryptionCommunityPatch.csproj
@@ -21,24 +21,24 @@
false
true
-
+
-
+
-
+
-
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
-
-
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+