Skip to content

Commit 908b1a8

Browse files
Add way to easily patch and modify the default bone gain when a player's card dies (#341)
Adds a new class `DefaultBoneGainOnDeath` and methods `DefaultBoneGainOnDeath.ShouldDoDefaultBoneGain` and `DefaultBoneGainOnDeeath.DoDefaultBoneGain` to the API that basically expose specific parts of the PlayableCard.Die method's code. These allow modders to patch and modify the default bone gain within the PlayableCard.Die method without needing to patch ResourcesManager.AddBone directly. --------- Co-authored-by: Chaosyr <Thincreator3483@hotmail.com>
1 parent cbe00db commit 908b1a8

4 files changed

Lines changed: 153 additions & 16 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@
99
- This comes with 5 new Dictionaries `BaseGameCustomAppearances` (Internal), `BaseGameCustomAppearancesPublic`, `ModdedCustomAppearancesDictionary` (Internal), `ModdedCustomAppearancesDictionaryPublic`, `CombinedCustomAppearancesDictionaryPublic`.
1010
- This system is stored under the `TextureHelper` class.
1111
* Improved In-Code Documentation via XML Comments.
12+
* Added a way to easily patch and modify the default bone gain when a player's card dies.
13+
* Added the following class: `DefaultBoneGainOnDeath` and the following methods within that class: `DefaultBoneGainOnDeath.ShouldDoDefaultBoneGain` and `DefaultBoneGainOnDeeath.DoDefaultBoneGain`
1214

1315
# 2.24.1
14-
* Added Extensions for setting the IconTexture of a Starter Deck.
15-
* Added 2 Alternate Constructors for making a StarterDeck with a Display Name different from its Internal Name.
16-
* Added Getters and Setters for Starter Deck Unlock Level.
16+
- Added Extensions for setting the IconTexture of a Starter Deck.
17+
- Added 2 Alternate Constructors for making a StarterDeck with a Display Name different from its Internal Name.
18+
- Added Getters and Setters for Starter Deck Unlock Level.
1719

1820
# 2.24.0
1921
- Fixed Part2CardCostRender.UpdatePlayableCardCost not being invoked
@@ -792,4 +794,4 @@
792794
- Custom cards are added via the **CustomCard** constructor rather than through the **AddCard** method.
793795

794796
# v1.1
795-
- Hooked into a much more sensible method to load the cards into the card pool.
797+
- Hooked into a much more sensible method to load the cards into the card pool.
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
using DiskCardGame;
2+
using HarmonyLib;
3+
using System.Collections;
4+
using System.Reflection;
5+
using System.Reflection.Emit;
6+
7+
namespace InscryptionAPI.Card;
8+
9+
/// <summary>
10+
/// Class for handling exposing the bone-on-death behaviour present in the vanilla PlayableCard.Die method.
11+
/// Allows for modifying the default behaviour through Harmony patches.
12+
/// </summary>
13+
[HarmonyPatch]
14+
public class DefaultBoneGainOnDeath {
15+
// this method does not need XML documentation since it's purely internal to make the other two methods work.
16+
// I also don't want to explain how transpilers work.
17+
[HarmonyTranspiler]
18+
[HarmonyPatch(typeof(PlayableCard), nameof(PlayableCard.Die), MethodType.Enumerator)]
19+
private static IEnumerable<CodeInstruction> InsertBoneMethodHook(IEnumerable<CodeInstruction> instructions)
20+
{
21+
// === We want to turn this
22+
23+
// if (!HasAbility(Ability.QuadrupleBones) && slotBeforeDeath.IsPlayerSlot) {
24+
// yield return Singleton<ResourcesManager>.Instance.AddBones(1, slotBeforeDeath);
25+
// }
26+
27+
// === Into this
28+
29+
// if (ShouldDoDefaultBoneGain(base.Card, slotBeforeDeath) {
30+
// yield return DoDefaultBoneGain(base.Card, slotBeforeDeath, 1);
31+
// }
32+
33+
// ===
34+
List<CodeInstruction> codes = new(instructions);
35+
36+
for (int i = 0; i < codes.Count; i++) {
37+
// there are two instances where this is true, but we only care about the first instance
38+
// the second instance will be ignored
39+
if (codes[i].opcode == OpCodes.Ldc_I4_S && codes[i].operand.ToString() == "12") {
40+
/*
41+
* // if (!playableCard.HasAbility(Ability.QuadrupleBones) && <slotBeforeDeath>5__2.IsPlayerSlot)
42+
* ldloc.1
43+
* ldc.i4.s 12
44+
* call instance bool DiskCardGame.PlayableCard::HasAbility(valuetype DiskCardGame.Ability)
45+
* brtrue.s IL_022f
46+
*
47+
* ldarg.0
48+
* ldfld class DiskCardGame.CardSlot DiskCardGame.PlayableCard/'<Die>d__98'::'<slotBeforeDeath>5__2'
49+
* callvirt instance bool DiskCardGame.CardSlot::get_IsPlayerSlot()
50+
* brfalse.s IL_022f
51+
*
52+
* =
53+
*
54+
* // if (ShouldDoDefaultBoneGain(playableCard, <slotBeforeDeath>5__2)
55+
* ldloc.1
56+
* ldarg.0
57+
* ldfld class DiskCardGame.CardSlot DiskCardGame.PlayableCard/'<Die>d__98'::'<slotBeforeDeath>5__2'
58+
* callvirt ShouldDo...
59+
* brfalse.s IL_022f
60+
*/
61+
MethodInfo validationMethod = AccessTools.Method(
62+
typeof(DefaultBoneGainOnDeath), nameof(ShouldDoDefaultBoneGain),
63+
new Type[] { typeof(PlayableCard), typeof(CardSlot) });
64+
65+
codes.RemoveAt(i);
66+
codes.RemoveAt(i);
67+
codes.RemoveAt(i);
68+
i += 2;
69+
codes[i] = new CodeInstruction(OpCodes.Callvirt, validationMethod);
70+
71+
/*
72+
* // <>2__current = Singleton<ResourcesManager>.Instance.AddBones(1, <slotBeforeDeath>5__2);
73+
* ldarg.0
74+
* call !0 class Singleton`1<class DiskCardGame.ResourcesManager>::get_Instance()
75+
* ldc.i4.1
76+
* ldarg.0
77+
* ldfld class DiskCardGame.CardSlot DiskCardGame.PlayableCard/'<Die>d__98'::'<slotBeforeDeath>5__2'
78+
* callvirt instance class [netstandard]System.Collections.IEnumerator DiskCardGame.ResourcesManager::AddBones(int32, class DiskCardGame.CardSlot)
79+
* stfld object DiskCardGame.PlayableCard/'<Die>d__98'::'<>2__current'
80+
*
81+
* =
82+
*
83+
* // <>2__current = DoDefaultBoneGain(playableCard, slotBeforeDeath, 1);
84+
* ldarg.0
85+
* ldloc.1
86+
* ldarg.0
87+
* ldfld class DiskCardGame.CardSlot DiskCardGame.PlayableCard/'<Die>d__98'::'<slotBeforeDeath>5__2'
88+
* ldc.i4.1
89+
* callvirt DoDefaultBoneGain
90+
* stfld object DiskCardGame.PlayableCard/'<Die>d__98'::'<>2__current'
91+
*/
92+
93+
MethodInfo executionMethod = AccessTools.Method(
94+
typeof(DefaultBoneGainOnDeath), nameof(DoDefaultBoneGain),
95+
new Type[] { typeof(PlayableCard), typeof(CardSlot), typeof(int) });
96+
97+
i += 3;
98+
codes[i] = new CodeInstruction(OpCodes.Ldloc_1);
99+
i++;
100+
101+
// since codes are taken from the top of the stack, we need to move the ldc.i4.1 to be AFTER we call slotBeforeDeath
102+
codes.RemoveAt(i);
103+
104+
i += 2;
105+
106+
codes.Insert(i, new CodeInstruction(OpCodes.Ldc_I4_1));
107+
i++;
108+
109+
codes[i] = new CodeInstruction(OpCodes.Callvirt, executionMethod);
110+
break;
111+
}
112+
}
113+
114+
return codes;
115+
}
116+
117+
/// <summary>
118+
/// Simple boolean check that by default replicates the vanilla check for whether a card should award a Bone on death.
119+
/// </summary>
120+
/// <param name="card">The PlayableCard that has died.</param>
121+
/// <param name="slotBeforeDeath">The CardSlot of card.</param>
122+
/// <returns>True if card should give a Bone (calls DoDefaultBoneGain).</returns>
123+
public static bool ShouldDoDefaultBoneGain(PlayableCard card, CardSlot slotBeforeDeath) {
124+
return slotBeforeDeath.IsPlayerSlot && !card.HasAbility(Ability.QuadrupleBones);
125+
}
126+
/// <summary>
127+
/// A simple call to ResourcesManager.AddBones, intended to give modders some more flexibility over the default death behaviour of player cards giving 1 Bone.
128+
/// </summary>
129+
/// <param name="card">The PlayableCard that has died.</param>
130+
/// <param name="slotBeforeDeath">The CardSlot of card.</param>
131+
/// <param name="amount">How many Bones to drop whenever a player's card dies (default is 1).</param>
132+
public static IEnumerator DoDefaultBoneGain(PlayableCard card, CardSlot slotBeforeDeath, int amount) {
133+
yield return Singleton<ResourcesManager>.Instance.AddBones(amount, slotBeforeDeath);
134+
}
135+
}

‎InscryptionAPI/InscryptionAPI.csproj‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
<None Remove="Assets\BaseGameDecals\decal_stitches.png" />
5959
<EmbeddedResource Include="Assets\BaseGameDecals\decal_stitches.png" />
6060
</ItemGroup>
61-
61+
6262
<ItemGroup>
6363
<!-- Talking Card Prefab -->
6464
<None Remove="$(ProjectDir)\TalkingCards\talkingcardgenericprefab" />

‎InscryptionCommunityPatch/InscryptionCommunityPatch.csproj‎

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,24 +21,24 @@
2121
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
2222
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
2323
</PropertyGroup>
24-
24+
2525
<ItemGroup>
26-
<EmbeddedResource Include="$(ProjectDir)\Assets\*.png" />
26+
<EmbeddedResource Include="$(ProjectDir)\Assets\*.png" />
2727
</ItemGroup>
2828

2929
<ItemGroup>
30-
<ProjectReference Private="false" Include="..\InscryptionAPI\InscryptionAPI.csproj" />
30+
<ProjectReference Private="false" Include="..\InscryptionAPI\InscryptionAPI.csproj" />
3131
</ItemGroup>
3232

3333
<ItemGroup>
34-
<PackageReference Include="BepInEx.Analyzers" Version="1.0.8">
35-
<PrivateAssets>all</PrivateAssets>
36-
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
37-
</PackageReference>
38-
<PackageReference Include="BepInEx.Core" Version="5.4.21" />
39-
<PackageReference Include="HarmonyX" Version="2.10.2" />
40-
<PackageReference Include="Inscryption.GameLibs" Version="1.9.0-r.0" />
41-
<PackageReference Include="UnityEngine.Modules" Version="2019.4.24" />
34+
<PackageReference Include="BepInEx.Analyzers" Version="1.0.8">
35+
<PrivateAssets>all</PrivateAssets>
36+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
37+
</PackageReference>
38+
<PackageReference Include="BepInEx.Core" Version="5.4.21" />
39+
<PackageReference Include="HarmonyX" Version="2.10.2" />
40+
<PackageReference Include="Inscryption.GameLibs" Version="1.9.0-r.0" />
41+
<PackageReference Include="UnityEngine.Modules" Version="2019.4.24" />
4242
</ItemGroup>
4343

4444
<!--Net Framework References-->

0 commit comments

Comments
 (0)