diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml
index c4287704..5c234615 100644
--- a/.github/workflows/documentation.yml
+++ b/.github/workflows/documentation.yml
@@ -5,40 +5,51 @@ on:
branches:
- main
+permissions:
+ contents: write
+
jobs:
build:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Setup .NET
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v6
with:
- dotnet-version: 6.0.x
+ dotnet-version: '10.0.x'
- name: Restore Project
run: dotnet restore
- - name: Add Mono Repository
- run: |
- sudo apt install gnupg ca-certificates
- sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
- echo "deb https://download.mono-project.com/repo/ubuntu stable-focal main" | sudo tee /etc/apt/sources.list.d/mono-official-stable.list
- sudo apt update
-
- - name: Install Mono
- run: sudo apt install mono-runtime mono-devel msbuild
-
- name: Install DocFX
run: |
- curl -LJ https://github.com/dotnet/docfx/releases/download/v2.59.0/docfx.zip -o docfx.zip
+ curl -LJ https://github.com/dotnet/docfx/releases/download/v2.81.0/docfx-linux-x64-v2.81.0.zip -o docfx.zip
unzip -d docfx/ docfx.zip
+ chmod +x docfx/docfx
- name: Generate documentation
- run: mono docfx/docfx.exe docs/docfx.json
+ env:
+ REPOSITORY_OWNER: ${{ github.repository_owner }}
+ REPOSITORY_NAME: ${{ github.event.repository.name }}
+ run: |
+ if [ "$REPOSITORY_NAME" = "$REPOSITORY_OWNER.github.io" ]; then
+ DOCFX_BASE_URL="https://${REPOSITORY_OWNER}.github.io/"
+ else
+ DOCFX_BASE_URL="https://${REPOSITORY_OWNER}.github.io/${REPOSITORY_NAME}/"
+ fi
+
+ jq --arg base "$DOCFX_BASE_URL" \
+ '.build.globalMetadata._appBaseUrl = $base' \
+ docs/docfx.json > docs/docfx.generated.json
+
+ ./docfx/docfx docs/docfx.generated.json
+
+ rm docs/docfx.generated.json
- - uses: actions/checkout@v3
+ - name: Checkout gh-pages
+ uses: actions/checkout@v4
with:
ref: gh-pages
path: gh-pages
@@ -50,11 +61,10 @@ jobs:
cp -R ../docs/_site/* .
- name: Push update
- continue-on-error: true
run: |
cd gh-pages
git config user.name github-actions
git config user.email github-actions@github.com
git add .
- git commit -a -m "Generated from ${{ github.event.head_commit.id }}"
+ git commit -a -m "Generated from ${{ github.event.head_commit.id }}" || echo "No changes needed"
git push
diff --git a/.github/workflows/ts-build.yml b/.github/workflows/ts-build.yml
new file mode 100644
index 00000000..5f368da3
--- /dev/null
+++ b/.github/workflows/ts-build.yml
@@ -0,0 +1,34 @@
+
+name: TS-Build
+
+on:
+ workflow_dispatch:
+
+permissions:
+ contents: read
+
+jobs:
+ build:
+ name: Run TS-Build
+ runs-on: windows-latest
+
+ steps:
+ - name: Checkout Repository
+ uses: actions/checkout@v4
+
+ - name: Setup .NET SDK
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 10.0.x
+
+ - name: Run TS-Build Script
+ shell: cmd
+ run: call InscryptionAPI\TS-Build.bat
+
+ - name: Send Artifacts to GitHub Workflow for Later Use.
+ uses: actions/upload-artifact@v4
+ with:
+ name: InscryptionAPI-Thunderstore-${{ github.run_number }}
+ path: InscryptionAPI/GITHUB RELEASE/NET/*.zip
+ if-no-files-found: error
+ retention-days: 30
diff --git a/.gitignore b/.gitignore
index dbfec368..5bac3001 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,4 +6,8 @@ bin/
.vscode/
*.user
build/
-
+InscryptionAPI/GITHUB RELEASE/
+InscryptionAPI/GITHUB PRERELEASE/
+InscryptionAPI/Thunderstore-Package-Elements/monomod/Assembly-CSharp.APIPatcher.mm.dll
+InscryptionAPI/Thunderstore-Package-Elements/monomod/Assembly-CSharp.APIPatcher.mm.pdb
+InscryptionAPI/Thunderstore-Package-Elements/monomod/Assembly-CSharp.APIPatcher.mm.xml
\ No newline at end of file
diff --git a/.run/TS-Build InscryptionAPI.run.xml b/.run/TS-Build InscryptionAPI.run.xml
new file mode 100644
index 00000000..ab052550
--- /dev/null
+++ b/.run/TS-Build InscryptionAPI.run.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/APIPatcher/APIPatcher.csproj b/APIPatcher/APIPatcher.csproj
index 296ee20b..bd589d91 100644
--- a/APIPatcher/APIPatcher.csproj
+++ b/APIPatcher/APIPatcher.csproj
@@ -1,16 +1,27 @@
- netframework4.7.2
+ netframework4.7.2
+ win-x64;win-x86;win-arm64;linux-x64;linux-arm;linux-arm64;linux-musl-x64;linux-musl-arm64;osx-x64;osx-arm64
+ Assembly-CSharp.APIPatcher.mm
+ The MonoMod Patcher for the Inscryption API.
+ 2.24.2
+ Cyantist, IngoH, WhistleWind, Chaosyr and Contibutors
+ true
+ Latest
+ APIPatcher
+ full
+ $(NoWarn);AD0001;CS0612;CS8604;CS0252;CS0618;Harmony003;Publicizer001enabledisable
- latest
+ false
+ true
+ false
+ false
+ truefalse
- Assembly-CSharp.APIPatcher.mm
-
-
-
- $(NoWarn);AD0001;CS0612;CS8604;CS0252;CS0618;Harmony003;Publicizer001
+ true
+ ..\InscryptionAPI\Thunderstore-Package-Elements\monomod\
@@ -22,4 +33,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/APIPatcher/ScriptableObjectLoader.cs b/APIPatcher/ScriptableObjectLoader.cs
index 3c67a6dc..66c6beab 100644
--- a/APIPatcher/ScriptableObjectLoader.cs
+++ b/APIPatcher/ScriptableObjectLoader.cs
@@ -3,9 +3,16 @@
namespace APIPatcher;
+///
+/// Uses MonoMod to patch Unity's ScriptableObjectLoader to also use our version of the ScriptableObjectLoader seen in the Inscryption API itself.
+///
+///
[MonoModPatch("global::ScriptableObjectLoader`1")]
internal class patch_ScriptableObjectLoader : ScriptableObjectLoader where T : UnityObject
{
+ ///
+ /// A List of AllData used within the overarching system, e.g. a List of .
+ ///
new public static List AllData
{
get
diff --git a/APIPatcher/Singleton.cs b/APIPatcher/Singleton.cs
index ce178f8a..1291c79f 100644
--- a/APIPatcher/Singleton.cs
+++ b/APIPatcher/Singleton.cs
@@ -4,9 +4,16 @@
namespace APIPatcher;
+///
+/// Uses MonoMod to patch the Singleton for later usability by the Inscryption API.
+///
+/// A ManagedBehaviour associated with the Singleton System.
[MonoModPatch("global::Singleton`1")]
internal class patch_Singleton : Singleton where T : ManagedBehaviour
{
+ ///
+ /// A simple function used to Find a Specified UnityObject of the specified Type within the Active Scene, if it fails it tosses a Warning.
+ ///
new protected static void FindInstance()
{
if (m_Instance == null)
@@ -21,7 +28,13 @@ internal class patch_Singleton : Singleton where T : ManagedBehaviour
}
}
+///
+/// A simple class object for singletons in correlation with the API.
+///
internal static class Singleton
{
+ ///
+ /// A ManualLogSource specifically for logging issues related to Singletons.
+ ///
internal static readonly ManualLogSource SingletonLogSource = Logger.CreateLogSource("Singleton");
}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d4bddb22..4994339a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,783 +1,825 @@
+# 2.24.2
+* Updated Installation Guides to Include Pulsar Mod Manager.
+* Added more null checks into the following patches `GainGemsForOpponents`, `LoseGemsForOpponents`, `GainTripleGemsForOpponents`, `LoseTripleGemsForOpponents`.
+* Removed `_specialSequencer` from `SpecialSequenceManager` as it was unused.
+* Removed `FontReplacementDataInitialized` from `LocalizationManager` as it was unused.
+* Added new Support for Custom Appearances.
+ * Image Handling is to be handled by the mods using the API.
+ * We now provide a storage of Base Game Decals that mods can reference without needing to instantiate their own.
+ * 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`
+* Privatized several Internal Functions.
+* Rename and Reorder configs internally for clarity as to what they are for.
+* Clean up Code formatting.
+* Fix casing of some variables.
+* Implement new Material Overrides to `MaterialOverride` related to changing `Metallic`, `Smoothness` and `Height` for consistency.
+* Add `OverrideQueuedBackground` to the `PixelCardBehaviours`.
+ * This is used for overriding the Queued Background of a card.
+* Upgraded the API's `.csproj`'s, and TCLI Build system.
+* Publicized the `_originalColor`, `_enterColor`, and `_selectedColor` used within `ActivatedAbilityIconInteractable` of the Community Patch.
+* Update the API to use Latest BepInEx.
+
# 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.
# 2.24.0
-- Fixed Part2CardCostRender.UpdatePlayableCardCost not being invoked
-- Fixed Part2CardCostRender.UpdateVanillaPlayableCardCost not being invoked
-- Fixed SetEmissiveSacrificablePortrait functions which used to refer to SteelTrapPortrait instead of SacrificablePortrait
-- Updated API and community patch target frameworks to `netframework4.7.2` (closer to the Runtime netframework.)
-- Updated community patch plugin's mod version to match the API's
-- Updated list of API contributors
-- Added ability to set custom card given by Steel Trap sigil (cr. Snowi and SpecialAPI)
-- Added `GetSteelTrapPelt` and `SetSteelTrapPelt` card extensions
-- Added debug mode cards for testing custom Steel Trap pelts
-- Added functions to set 'TailLostPortrait' emission sprites
-- Added functions for setting 'TailLostPortrait' from a Sprite object
-- Added NoWarn property to API and community patch projects for AD0001, CS0612, CS0618, Publicizer001
+* Fixed Part2CardCostRender.UpdatePlayableCardCost not being invoked
+* Fixed Part2CardCostRender.UpdateVanillaPlayableCardCost not being invoked
+* Fixed SetEmissiveSacrificablePortrait functions which used to refer to SteelTrapPortrait instead of SacrificablePortrait
+* Updated API and community patch target frameworks to `netframework4.7.2` (closer to the Runtime netframework.)
+* Updated community patch plugin's mod version to match the API's
+* Updated list of API contributors
+* Added ability to set custom card given by Steel Trap sigil (cr. Snowi and SpecialAPI)
+* Added `GetSteelTrapPelt` and `SetSteelTrapPelt` card extensions
+* Added debug mode cards for testing custom Steel Trap pelts
+* Added functions to set 'TailLostPortrait' emission sprites
+* Added functions for setting 'TailLostPortrait' from a Sprite object
+* Added NoWarn property to API and community patch projects for AD0001, CS0612, CS0618, Publicizer001
# 2.23.7
-- Fixed log spam due to inverted condition in CardExtensions.GemsCost
+* Fixed log spam due to inverted condition in CardExtensions.GemsCost
# 2.23.6
-- Fixed card modifications added to a card's base ice cube card via CardInfo.SetIceCube being ignored
-- Fixed PlayableCard.CanPlay not consistently accounting for temporary mod cost adjustments
-- Fixed dynamic play costs not consistently updating
-- Added additional methods for adding specific types of resources to the ResourceBank
-- Added CardSlot.ClearSlotModification extension method
-- Added additional FullAbility helper extension methods for setting act-specific rulebook categories
+* Fixed card modifications added to a card's base ice cube card via CardInfo.SetIceCube being ignored
+* Fixed PlayableCard.CanPlay not consistently accounting for temporary mod cost adjustments
+* Fixed dynamic play costs not consistently updating
+* Added additional methods for adding specific types of resources to the ResourceBank
+* Added CardSlot.ClearSlotModification extension method
+* Added additional FullAbility helper extension methods for setting act-specific rulebook categories
# 2.23.5
-- Fixed cards appearing as blank outside Act 1
-- Added extension methods for FullAbility that mirror AbilityInfo extension methods
+* Fixed cards appearing as blank outside Act 1
+* Added extension methods for FullAbility that mirror AbilityInfo extension methods
# 2.23.4
-- Fixed GemsDraw only considering the player's slots when determining how many cards to draw
-- Fixed Act 2 Tutor sequence softlocking when there are no cards to display
-- Fixed Act 2 Tutor sequence not displaying cards when you have less than 7 cards remaining in your deck
-- Fixed Gemify reducing multiple card costs at once for multicost cards - now only affects 1 as intended
-- Fixed emission textures appearing stretched on Giant cards
-- Added Gems Cost support for ExtendedActivatedAbilityBehaviour class
-- Added extension AbilityManager.FullAbility.FlipYIfOpponent
-- Added config option to prevent Act 1 card emissions from rendering above the play costs
+* Fixed GemsDraw only considering the player's slots when determining how many cards to draw
+* Fixed Act 2 Tutor sequence softlocking when there are no cards to display
+* Fixed Act 2 Tutor sequence not displaying cards when you have less than 7 cards remaining in your deck
+* Fixed Gemify reducing multiple card costs at once for multicost cards
+ * Now only affects 1 as intended
+* Fixed emission textures appearing stretched on Giant cards
+* Added Gems Cost support for ExtendedActivatedAbilityBehaviour class
+* Added extension AbilityManager.FullAbility.FlipYIfOpponent
+* Added config option to prevent Act 1 card emissions from rendering above the play costs
# 2.23.3
-- Fixed custom deck exhaust sequence not performing the requisite checks
-- Added 'CanAppearRandomly' bool and associated extension method for custom regions
-- All custom regions added through the API are now included in AllRegionsCopy and NewRegions (if addToPool was false then it won't be encounterable in-game like normal)
+* Fixed custom deck exhaust sequence not performing the requisite checks
+* Added 'CanAppearRandomly' bool and associated extension method for custom regions
+* All custom regions added through the API are now included in AllRegionsCopy and NewRegions (if addToPool was false then it won't be encounterable in-game like normal)
# 2.23.2
-- Fixed error when trying to create cards that evolve/transform in 4 or more turns
-- Fixed Fledgling and Transformer sigil appearing as black boxes when a card evolves/transform in 4 or more turns
-- Fixed Part2VanillaCardCost event not being invoked
-- Added 'UpdatePlayableCardCosts' event to community patch's Part1CardCostRender and Part2CardCostRender classes
-- Added extension methods for PlayableCard and CardInfo: ProvidesBlueGem, ProvidesGreenGem, ProvidesOrangeGem
-- Evolve and Transformer icons now support cards that evolve in 4 or more turns
-- Wiki: added articles 'Other Features' and 'Triggers and the Order of Operations'
-- Wiki: modified starting section of 'Custom Triggers' article
-- Documentation: fixed description for IPostCardGettingAttacked stating it triggers before CardGettingAttacked
+* Fixed error when trying to create cards that evolve/transform in 4 or more turns
+* Fixed Fledgling and Transformer sigil appearing as black boxes when a card evolves/transform in 4 or more turns
+* Fixed Part2VanillaCardCost event not being invoked
+* Added 'UpdatePlayableCardCosts' event to community patch's Part1CardCostRender and Part2CardCostRender classes
+* Added extension methods for PlayableCard and CardInfo: ProvidesBlueGem, ProvidesGreenGem, ProvidesOrangeGem
+* Evolve and Transformer icons now support cards that evolve in 4 or more turns
+* Wiki: added articles 'Other Features' and 'Triggers and the Order of Operations'
+* Wiki: modified starting section of 'Custom Triggers' article
+* Documentation: fixed description for IPostCardGettingAttacked stating it triggers before CardGettingAttacked
# 2.23.1
-- Fixed non-CardModificationInfo shields not breaking
-- Fixed ShieldGeneratorItem not correclty updating visuals
-- Fixed DamageShieldBehaviours not initialising before being called
-- Added CardInfo.GetAbilityStacks()
-- Changed how DamageShieldBehaviour.ResetShield works to be more inline with how vanilla shields work
-- Removed some shield-reset-related patches
+* Fixed non-CardModificationInfo shields not breaking
+* Fixed ShieldGeneratorItem not correclty updating visuals
+* Fixed DamageShieldBehaviours not initialising before being called
+* Added CardInfo.GetAbilityStacks()
+* Changed how DamageShieldBehaviour.ResetShield works to be more inline with how vanilla shields work
+* Removed some shield-reset-related patches
# 2.23.0
-- Added 'GBC Vanilla Render' config to community patches (false by default) - makes GBC cards render with vanilla cost sprites
-- Added 'Vanilla Stacking' config to community patches (false by default) - renders cards with only two (stacking) sigils as they appear in vanilla, eg Spore Mice and Sporedigger
-- Added PostCardGettingAttacked custom trigger
-- Added BoardManager.GetCards and BoardManager.GetOpenSlots overloads that retrieve from the entire board
-- Fixed incorrect rulebook icon scaling in Act 3
-- Fixed rulebook-related null errors when playing during Magnificus' Act
-- Fixed slot modification rulebook pages not appearing correctly during Magnificus' Act
-- Fixed cards shield sigils not rendering correctly
-- DamageShieldBehaviour class now has 'initialised' boolean field
-- Highest displayable bone cost value in Act 1 raised from 13+ to 15+
-- Minor tweaks to blood and bone cost icons
-- Rewrote SlotAttackSlotPatches transpilers to be cleaner
+* Added 'GBC Vanilla Render' config to community patches (false by default)
+ * Makes GBC cards render with vanilla cost sprites
+* Added 'Vanilla Stacking' config to community patches (false by default)
+ * Renders cards with only two (stacking) sigils as they appear in vanilla, eg Spore Mice and Sporedigger
+* Added PostCardGettingAttacked custom trigger
+* Added BoardManager.GetCards and BoardManager.GetOpenSlots overloads that retrieve from the entire board
+* Fixed incorrect rulebook icon scaling in Act 3
+* Fixed rulebook-related null errors when playing during Magnificus' Act
+* Fixed slot modification rulebook pages not appearing correctly during Magnificus' Act
+* Fixed cards shield sigils not rendering correctly
+* DamageShieldBehaviour class now has 'initialised' boolean field
+* Highest displayable bone cost value in Act 1 raised from 13+ to 15+
+* Minor tweaks to blood and bone cost icons
+* Rewrote SlotAttackSlotPatches transpilers to be cleaner
# 2.22.3
-- Fixed pelt names when a user goes to the trader with modded cards, Examples shown below.
+* Fixed pelt names when a user goes to the trader with modded cards, Examples shown below.
-- Fixed index error when loading custom challenges
-- Publicised ConsumableItemData.SetPrefabModelType
+* Fixed index error when loading custom challenges
+* Publicised ConsumableItemData.SetPrefabModelType
# 2.22.2
-- Added GetEnergyConfig method to community patch's EnergyDrone class - retrieves the current Act's EnergyConfigInfo
-- CommunityPatches: Added community config to move pelt price tags to the right of the card
-- Experimental: Changed gemified to only reduce a single cost on a card, with priority of Energy > Bones > Gems > Blood
-- Fixed positioning errors caused by having multiple custom boss challenge icons
-- EnergyConfigInfo's fields can now be modified when initialising a new instance
-- Updated installation guide on the ReadMe to match the wiki, added link to wiki.
+* Added GetEnergyConfig method to community patch's EnergyDrone class
+ * Retrieves the current Act's EnergyConfigInfo
+* CommunityPatches: Added community config to move pelt price tags to the right of the card
+* Experimental: Changed gemified to only reduce a single cost on a card, with priority of Energy > Bones > Gems > Blood
+* Fixed positioning errors caused by having multiple custom boss challenge icons
+* EnergyConfigInfo's fields can now be modified when initialising a new instance
+* Updated installation guide on the ReadMe to match the wiki, added link to wiki.
# 2.22.1
-- Added IShieldPreventedDamage and IShieldPreventedDamageInHand ability triggers and interfaces
-- Added TriggerBreakShield, wraps BreakShield in an IEnumerator for additional customisation by modders
-- Added ICustomExhaustSequence trigger interface for modifying the draw pile exhaustion effect - use with Opponents
-- Fixed board slots being uninteractable if a slot effect with a rulebook interactable was reset
-- Removed debug logging related to rulebook redirect coordinates
+* Added IShieldPreventedDamage and IShieldPreventedDamageInHand ability triggers and interfaces
+* Added TriggerBreakShield, wraps BreakShield in an IEnumerator for additional customisation by modders
+* Added ICustomExhaustSequence trigger interface for modifying the draw pile exhaustion effect
+ * Use with Opponents
+* Fixed board slots being uninteractable if a slot effect with a rulebook interactable was reset
+* Removed debug logging related to rulebook redirect coordinates
# 2.22.0
-- Added FullBoon objects for each vanilla Boon
-- Added 'AllFullBoons' list to BoonManager
-- Added support for boons and items appearing in multiple acts' rulebooks
-- Added RuleBookRedirectManager and support for rulebook text redirects/page links
-- Added additional methods to RuleBookManager: ItemShouldBeAdded, BoonShouldBeAdded, SlotModShouldBeAdded, GetUnformattedPageId
-- Added GetFullBoon and GetFullConsumableItemData extension methods
-- Added extension methods for adding text redirects to abilities, stat icons, items, boons, slot modifications, and rulebook pages
-- Added ModificationType.SetSharedRulebook - used for slot modifications that should share their rulebook entry with other slot modifications
-- Added support for multiple rulebook sprites for slot modifications (SetRulebookP03Sprite, SetRulebookGrimoraSprite, SetRulebookMagnificusSprite)
-- Added RuleBookController.Instance.OpenToCustomPage
-- Added CustomDiskTalkingCard abstract class
-- Added TalkingCardManager.NewDisk and TalkingCardManager.CreateDisk
-- Fixed RuleBook construction patches having lower patch priority than intended
-- Fixed slot modification interactable being enabled when no rulebook entry exists
-- Fixed slot modification rulebook pages not working in Act 3
-- Fixed rulebook sprites being smaller than normal after flipping to a slot modification rulebook page
-- Fixed DiskTalkingCards created through the API not correctly working under certain conditions
-- Moved ConsumableItemManager patches to a separate ConsumableItemPatches class
-- Modified implementation of rulebook fill page logic to let modders patch the API logic
- - Patch 'RuleBookManagerPatches.FillPage' to do this
-- Tweaked how custom rulebook pages are added and detected
-- Wiki: Tweaked page for adding custom rulebook sections
-- Wiki: Added section on adding text redirects
+* Added FullBoon objects for each vanilla Boon
+* Added 'AllFullBoons' list to BoonManager
+* Added support for boons and items appearing in multiple acts' rulebooks
+* Added RuleBookRedirectManager and support for rulebook text redirects/page links
+* Added additional methods to RuleBookManager: ItemShouldBeAdded, BoonShouldBeAdded, SlotModShouldBeAdded, GetUnformattedPageId
+* Added GetFullBoon and GetFullConsumableItemData extension methods
+* Added extension methods for adding text redirects to abilities, stat icons, items, boons, slot modifications, and rulebook pages
+* Added ModificationType.SetSharedRulebook
+ * Used for slot modifications that should share their rulebook entry with other slot modifications
+* Added support for multiple rulebook sprites for slot modifications (SetRulebookP03Sprite, SetRulebookGrimoraSprite, SetRulebookMagnificusSprite)
+* Added RuleBookController.Instance.OpenToCustomPage
+* Added CustomDiskTalkingCard abstract class
+* Added TalkingCardManager.NewDisk and TalkingCardManager.CreateDisk
+* Fixed RuleBook construction patches having lower patch priority than intended
+* Fixed slot modification interactable being enabled when no rulebook entry exists
+* Fixed slot modification rulebook pages not working in Act 3
+* Fixed rulebook sprites being smaller than normal after flipping to a slot modification rulebook page
+* Fixed DiskTalkingCards created through the API not correctly working under certain conditions
+* Moved ConsumableItemManager patches to a separate ConsumableItemPatches class
+* Modified implementation of rulebook fill page logic to let modders patch the API logic
+ * Patch 'RuleBookManagerPatches.FillPage' to do this
+* Tweaked how custom rulebook pages are added and detected
+* Wiki: Tweaked page for adding custom rulebook sections
+* Wiki: Added section on adding text redirects
# 2.21.1
-- Fixed RuleBookManager not syncing when playing with no custom rulebook sections
+* Fixed RuleBookManager not syncing when playing with no custom rulebook sections
# 2.21.0
-- Fixed ability stacks not rendering
-- Fixed rendering error when displaying a card with tribes outside of Act 1
-- Fixed ResetShields not re-setting lostShield to false under certain conditions
-- Fixed RemoveMaxEnergy not working as intended
-- Fixed custom AudioClips not loading correctly on Mac OSX
-- Added RuleBookManager for adding custom rulebook sections (see wiki for more info)
-- Added AllModificationInfos, AllModificationTypes, and modification syncing to SlotModificationManager
-- Added additional functionality to SlotModificationManager - Infos now store name and GUID
-- Added rulebook entry support for slot modifications - use extension method .SetRulebook() when adding your slot modification
-- Added more shield-related extensions
-- Added some AbilityInfo-related extensions
-- Added ShieldManager.AllShieldAbilities and ShieldManager.AllShieldInfos for easier tracking of custom shield abilities
-- Added config to the community patches to add a forced red emission to Undead Cat
-- Modified Obsolete warning for Helpers.CustomLine to point to Dialogue.CustomLine
+* Fixed ability stacks not rendering
+* Fixed rendering error when displaying a card with tribes outside of Act 1
+* Fixed ResetShields not re-setting lostShield to false under certain conditions
+* Fixed RemoveMaxEnergy not working as intended
+* Fixed custom AudioClips not loading correctly on Mac OSX
+* Added RuleBookManager for adding custom rulebook sections (see wiki for more info)
+* Added AllModificationInfos, AllModificationTypes, and modification syncing to SlotModificationManager
+* Added additional functionality to SlotModificationManager
+ * Infos now store name and GUID
+* Added rulebook entry support for slot modifications
+ * Use extension method .SetRulebook() when adding your slot modification
+* Added more shield-related extensions
+* Added some AbilityInfo-related extensions
+* Added ShieldManager.AllShieldAbilities and ShieldManager.AllShieldInfos for easier tracking of custom shield abilities
+* Added config to the community patches to add a forced red emission to Undead Cat
+* Modified Obsolete warning for Helpers.CustomLine to point to Dialogue.CustomLine
# 2.20.0
-- Updated wiki sections for Adding Map Nodes, and Conditional Map Nodes; moved Special Sequencers section to Opponents
-- Fixed issues related to challlenge icon sorting when a boss icon is present
-- Fixed TalkingCardManager not properly configuring talking cards in Part 3on the page
-- Fixed extension properties for CardModificationInfos saved to the save file not consistently loading
-- Fixed cards not shaking when losing a shield
-- Fixed ShieldManager.BreakShield not being called when a shielded card takes damage
-- Added SlotModificationManager for adding behaviour to card slots; see wiki for more info
-- Added SaveFileExtensions class
-- Added support for cards costing multiple of the same colour Mox
-- Added debugging to GetCustomCardCosts method; please let the API folks know if you receive any warnings/errors marked by '[GetCustomCardCosts]'
-- Added StatIconInfo.SetRulebookInfo and StatIconInfo.SetAppliesToStats
-- Added NodeData.SelectionCondition's ChallengeIsActive and NumChallengesOfTypeActive
-- Added PlayableCard.GetShieldCount<\T>() for getting a specific shield ability's NumShield value
-- Added new config to the community patches to reduce the size of the price tags during the Buy Pelts sequence
-- Added CardModificationInfo.AddNegateAbilities extension method
-- Removed leftover debugging related to boss challenge icons and custom costs
-- P03 Face Card Displayer can now show card costs other than energy
-- Publiciser warnings from the API and Community Patches no longer appear in the console
-- SaveFile.CurrentDeck now returns gbcData.deck in Act 2
-- DeathShieldLatch can longer target cards with an active shield
-- Cards with a broken shield return to their default portrait when regaining their shield
-- Shield abilities now use NumShields to determine visual sigil stacking
-- CardModificationInfo.SetNameReplacement now accepts null value for the name replacement
+* Updated wiki sections for Adding Map Nodes, and Conditional Map Nodes; moved Special Sequencers section to Opponents
+* Fixed issues related to challlenge icon sorting when a boss icon is present
+* Fixed TalkingCardManager not properly configuring talking cards in Part 3on the page
+* Fixed extension properties for CardModificationInfos saved to the save file not consistently loading
+* Fixed cards not shaking when losing a shield
+* Fixed ShieldManager.BreakShield not being called when a shielded card takes damage
+* Added SlotModificationManager for adding behaviour to card slots; see wiki for more info
+* Added SaveFileExtensions class
+* Added support for cards costing multiple of the same colour Mox
+* Added debugging to GetCustomCardCosts method; please let the API folks know if you receive any warnings/errors marked by '[GetCustomCardCosts]'
+* Added StatIconInfo.SetRulebookInfo and StatIconInfo.SetAppliesToStats
+* Added NodeData.SelectionCondition's ChallengeIsActive and NumChallengesOfTypeActive
+* Added PlayableCard.GetShieldCount<\T>() for getting a specific shield ability's NumShield value
+* Added new config to the community patches to reduce the size of the price tags during the Buy Pelts sequence
+* Added CardModificationInfo.AddNegateAbilities extension method
+* Removed leftover debugging related to boss challenge icons and custom costs
+* P03 Face Card Displayer can now show card costs other than energy
+* Publiciser warnings from the API and Community Patches no longer appear in the console
+* SaveFile.CurrentDeck now returns gbcData.deck in Act 2
+* DeathShieldLatch can longer target cards with an active shield
+* Cards with a broken shield return to their default portrait when regaining their shield
+* Shield abilities now use NumShields to determine visual sigil stacking
+* CardModificationInfo.SetNameReplacement now accepts null value for the name replacement
# 2.19.5
-- Fixed pixel Bones cost icons not appearing when the cost is greater than vanilla amounts
-- Fixed interaction where a Gemified card that gives a blue gem doesn't spend the correct resource amount when played
-- Fixed active challenges desyncing from the icons when returning to the select challenges screen from a custom screen
-- Added pixel icon to Aquasquirrel (courtesy of Zepht)
-- Added GetCustomCostAmount extension methods for automatically accounting for whether a custom cost can be negative
-- Added support for making custom challenges that use the Final Boss challenge's icon format (occupying the whole column)
-- AscensionChallengePaginator's leftArrow and rightArrow fields are now AscensionMenuInteractables
-- Changed method name of GenBaseGameChallengs to GenBaseGameChallenges
-- Changed Act 1 energy cost choice cardback to match the cost's icon colour
-- Changed TestCost.OnPlayed to no longer trigger on negative values
-- CustomCardCost.OnPlayed no longer triggers for custom costs with a value of 0 (negative values can still occur)
-- Challenges no longer show dependencies/incompatibilies when viewed in the pause menu and end screen
+* Fixed pixel Bones cost icons not appearing when the cost is greater than vanilla amounts
+* Fixed interaction where a Gemified card that gives a blue gem doesn't spend the correct resource amount when played
+* Fixed active challenges desyncing from the icons when returning to the select challenges screen from a custom screen
+* Added pixel icon to Aquasquirrel (courtesy of Zepht)
+* Added GetCustomCostAmount extension methods for automatically accounting for whether a custom cost can be negative
+* Added support for making custom challenges that use the Final Boss challenge's icon format (occupying the whole column)
+* AscensionChallengePaginator's leftArrow and rightArrow fields are now AscensionMenuInteractables
+* Changed method name of GenBaseGameChallengs to GenBaseGameChallenges
+* Changed Act 1 energy cost choice cardback to match the cost's icon colour
+* Changed TestCost.OnPlayed to no longer trigger on negative values
+* CustomCardCost.OnPlayed no longer triggers for custom costs with a value of 0 (negative values can still occur)
+* Challenges no longer show dependencies/incompatibilies when viewed in the pause menu and end screen
# 2.19.4
-- Fixed error when retrieving custom card costs from a card with no custom card costs
-- Fixed cards with custom card costs using the pixel cost icons in some circumstances
-- Fixed modifications to base Pelt choice amounts not being reflected in-game
-- Fixed latched sigils not appearing in Act 3
-- Added config to randomise cost choice order
-- Added additional functionality to FullCardCost - see wiki and documentation for more info
-- Added TestCost class to community patches - can be added to the game by enabling "Test Mode" in the configs
-- Added extension methods for setting and getting a custom card cost using the CustomCardCost class instance
-- Custom costs now support cost tiers and checking CanBePlayedByTurn2WithHand
-- Custom costs' textures now differentiate whether they're from Acts 1, 2, or 3 when storing them post-assemblage
-- Card choices when trading Pelts are now positioned correctly for amounts non-divisible by 4
-- Modified Act 1 latch patch logic
-- Publicised a number of TradePeltSequence patch methods
-- Refactored some TradePeltSequence patches
-- Reverted undocumented changes to some SniperFix parameter names in previous version
+* Fixed error when retrieving custom card costs from a card with no custom card costs
+* Fixed cards with custom card costs using the pixel cost icons in some circumstances
+* Fixed modifications to base Pelt choice amounts not being reflected in-game
+* Fixed latched sigils not appearing in Act 3
+* Added config to randomise cost choice order
+* Added additional functionality to FullCardCost
+ * See wiki and documentation for more info
+* Added TestCost class to community patches
+ * Can be added to the game by enabling "Test Mode" in the configs
+* Added extension methods for setting and getting a custom card cost using the CustomCardCost class instance
+* Custom costs now support cost tiers and checking CanBePlayedByTurn2WithHand
+* Custom costs' textures now differentiate whether they're from Acts 1, 2, or 3 when storing them post-assemblage
+* Card choices when trading Pelts are now positioned correctly for amounts non-divisible by 4
+* Modified Act 1 latch patch logic
+* Publicised a number of TradePeltSequence patch methods
+* Refactored some TradePeltSequence patches
+* Reverted undocumented changes to some SniperFix parameter names in previous version
# 2.19.3
-- Fixed index error related to Totem sigils
-- Fixed index error related to opponent sniper targeting
-- Fixed Shield Latch sigil not displaying the first latched sigil
-- Added config to community patches to reset Leshy's eye colour after triggering the grizzly bear sequence during boss fights
+* Fixed index error related to Totem sigils
+* Fixed index error related to opponent sniper targeting
+* Fixed Shield Latch sigil not displaying the first latched sigil
+* Added config to community patches to reset Leshy's eye colour after triggering the grizzly bear sequence during boss fights
# 2.19.2
-- Fixed activated abilities not being interactable in Act 3
-- Fixed cards with costs above vanilla defaults not displaying
-- Added debug logs to AddCustomTribesToList (used to add custom Tribes to the list of obtainable Totem tops)
+* Fixed activated abilities not being interactable in Act 3
+* Fixed cards with costs above vanilla defaults not displaying
+* Added debug logs to AddCustomTribesToList (used to add custom Tribes to the list of obtainable Totem tops)
# 2.19.1
-- Fixed API not retrieving pixel card costs above 5
+* Fixed API not retrieving pixel card costs above 5
# 2.19.0
-- Fixed decals added via temporary mods not being cleared from the base card
-- Fixed merged and totem sigils being uninteractable if the icon has been flipped vertically
-- Fixed pixel Shapeshifter patch not correctly patching DisguiseOutOfBattle
-- Fixed temporary decal mods not being removed in Act 1
-- Fixed softlock in Part 1 during the boon-gaining sequence
-- Fixed all copies of a custom challenge becoming activated/deactivated when the page is reloaded
-- Fixed Sentry ability softlocking when the base card dies before all Sentry stacks are triggered
-- Fixed softlock when talking card dialogue cannot be parsed in certain conditions
-- Added public method GetIjiraqDisguises to pixel Shapeshifter patch for easier modification of Shapeshifter for modders
-- Added variant of PeltManager.New
-- Added variant of PlayableCard.AllAbilities that accounts for negated abilities in TemporaryMods
-- Added support for creating custom card costs using new class CustomCardCost; see wiki for more information
-- Added ability to remove gems costs from a card using CardModificationInfos
-- Added a number of extension methods for CardModificationInfos (RemoveGemsCost, SetCustomCostId, etc)
-- Added helpers for getting TextBox.Style from CardInfo.temple or the chosen ambition
-- Rewrote CardModificationInfoManager's id system for setting persistent extended properties in a CardModificationInfo's singletonId
-- Rewrote pixel Shapeshifter patch to RevealInBattle to hopefully prevent errors in Act 1
-- PeltManager.New now throws an error when getCardChoices is null
-- Changed LogLevel of dialogue event insertion message from Info to Debug
-- API death cards now use the clean singleton id when creating the death card info mod
-- Temporary decal mods are now removed from Act 2 cards instead of being cleared
-- Opponent snipers will now target a random slot if there are no opposing cards (previously only targeted the opposing slot)
+* Fixed decals added via temporary mods not being cleared from the base card
+* Fixed merged and totem sigils being uninteractable if the icon has been flipped vertically
+* Fixed pixel Shapeshifter patch not correctly patching DisguiseOutOfBattle
+* Fixed temporary decal mods not being removed in Act 1
+* Fixed softlock in Part 1 during the boon-gaining sequence
+* Fixed all copies of a custom challenge becoming activated/deactivated when the page is reloaded
+* Fixed Sentry ability softlocking when the base card dies before all Sentry stacks are triggered
+* Fixed softlock when talking card dialogue cannot be parsed in certain conditions
+* Added public method GetIjiraqDisguises to pixel Shapeshifter patch for easier modification of Shapeshifter for modders
+* Added variant of PeltManager.New
+* Added variant of PlayableCard.AllAbilities that accounts for negated abilities in TemporaryMods
+* Added support for creating custom card costs using new class CustomCardCost; see wiki for more information
+* Added ability to remove gems costs from a card using CardModificationInfos
+* Added a number of extension methods for CardModificationInfos (RemoveGemsCost, SetCustomCostId, etc)
+* Added helpers for getting TextBox.Style from CardInfo.temple or the chosen ambition
+* Rewrote CardModificationInfoManager's id system for setting persistent extended properties in a CardModificationInfo's singletonId
+* Rewrote pixel Shapeshifter patch to RevealInBattle to hopefully prevent errors in Act 1
+* PeltManager.New now throws an error when getCardChoices is null
+* Changed LogLevel of dialogue event insertion message from Info to Debug
+* API death cards now use the clean singleton id when creating the death card info mod
+* Temporary decal mods are now removed from Act 2 cards instead of being cleared
+* Opponent snipers will now target a random slot if there are no opposing cards (previously only targeted the opposing slot)
# 2.18.7
-- Fixed softlock during Act 1's final boss cabin/boons sequence
-- Fixed startup errors relating to ShieldManager transpilers
-- Fixed resource drone not showing up outside of Act 3
-- Fixed latched sigils not visually disappearing when using RemoveTemporaryMod to remove a latch CardModInfo
-- Fixed stack sigil icons not correctly replacing the '1' in stackable sigil icons with the appropriate stack number
-- Fixed Act 2 Tutor sequence displaying the wrong number of cards above the max of 42
-- Fixed temporary mods not correctly updating a card's shield count above 1
-- Added extension methods PlayableCard.AllCardModificationInfos(), PlayableCard.RemoveCardModificationInfo()
-- Added SpriteType 'PixelStandardButton'
-- CustomTriggerFinder now caches the list of non-card triggers before iteration
-- ActivatedDamageShieldBehaviour now inherits from DamageShieldBehaviour instead of ActivateAbilityBehaviour
-- ActivatedDamageShieldBehaviour now implements the logic from ExtendedActivatedAbilityBehaviour
-- Mud Turtle now has a broken shield portrait (identical to its alternate portrait, which is unchanged)
-- CardTriggerHandler.RemoveAbility now only destroys the AbilityBehaviour if triggeredAbilities no longer contains the corresponding Ability
-- Act 2 Tutor now supports multiple pages of cards
+* Fixed softlock during Act 1's final boss cabin/boons sequence
+* Fixed startup errors relating to ShieldManager transpilers
+* Fixed resource drone not showing up outside of Act 3
+* Fixed latched sigils not visually disappearing when using RemoveTemporaryMod to remove a latch CardModInfo
+* Fixed stack sigil icons not correctly replacing the '1' in stackable sigil icons with the appropriate stack number
+* Fixed Act 2 Tutor sequence displaying the wrong number of cards above the max of 42
+* Fixed temporary mods not correctly updating a card's shield count above 1
+* Added extension methods PlayableCard.AllCardModificationInfos(), PlayableCard.RemoveCardModificationInfo()
+* Added SpriteType 'PixelStandardButton'
+* CustomTriggerFinder now caches the list of non-card triggers before iteration
+* ActivatedDamageShieldBehaviour now inherits from DamageShieldBehaviour instead of ActivateAbilityBehaviour
+* ActivatedDamageShieldBehaviour now implements the logic from ExtendedActivatedAbilityBehaviour
+* Mud Turtle now has a broken shield portrait (identical to its alternate portrait, which is unchanged)
+* CardTriggerHandler.RemoveAbility now only destroys the AbilityBehaviour if triggeredAbilities no longer contains the corresponding Ability
+* Act 2 Tutor now supports multiple pages of cards
# 2.18.6
-- 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
-- Added missing null checks to ResourceDrone patches
-- Added pixel icon to Transformer
-- 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
+* 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
+* Added missing null checks to ResourceDrone patches
+* Added pixel icon to Transformer
+* 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
-- Fixed DrawCopyOnDeath creating warnings in the console
-- Fixed talking cards locking the camera view when obtained during the Trapper boss's final phase
-- Fixed ResourceDrone softlocking during Leshy's goodbye sequence if ConfigDefaultDrone is false
-- Added missing null checks
-- Added PlayableCard.GetStatIconHealthBuffs()
-- Added PlayableCard.TransformIntoCardAboveHand() - variant of TransformIntoCardInHand that incorporates MoveCardAboveHand
-- Added FullAbility.SetExtendedProperty for setting an AbilityInfo's custom property during ability creation
-- Reverted change to resource drone preventing it from being parented to the scale outside of Act 1
-- Improved visual fix for the full pack Pack Rat sequence
+* Fixed DrawCopyOnDeath creating warnings in the console
+* Fixed talking cards locking the camera view when obtained during the Trapper boss's final phase
+* Fixed ResourceDrone softlocking during Leshy's goodbye sequence if ConfigDefaultDrone is false
+* Added missing null checks
+* Added PlayableCard.GetStatIconHealthBuffs()
+* Added PlayableCard.TransformIntoCardAboveHand()
+ * Variant of TransformIntoCardInHand that incorporates MoveCardAboveHand
+* Added FullAbility.SetExtendedProperty for setting an AbilityInfo's custom property during ability creation
+* Reverted change to resource drone preventing it from being parented to the scale outside of Act 1
+* Improved visual fix for the full pack Pack Rat sequence
# 2.18.4
-- Fixed Sniper sigil targeting the wrong side of the board
-- Fixed placeholder tribe choice icons being placed incorrectly
-- Auto-gen tribe choice texture is now only created if the tribe can be found in tribe choices
+* Fixed Sniper sigil targeting the wrong side of the board
+* Fixed placeholder tribe choice icons being placed incorrectly
+* Auto-gen tribe choice texture is now only created if the tribe can be found in tribe choices
# 2.18.3
-- Fixed resource drone behaving incorrectly outside of Act 1
-- Added null checks to various custom triggers
-- Added more extension methods for CardInfo and AbilityInfo
-- Added PlayableCard extension methods: AddShieldCount(Ability), AddShieldCount\() and AddShieldCount(Ability), RemoveShieldCount\()
- - These affect the internal numShields field, and do NOT add or remove ability stacks
-- Added alternate portrait 'SacrificablePortrait' for when a card can be sacrificed in Act 1 or Act 2 (part of the SetShaking method)
-- Added methods for getting the emissive portraits for extra alt portraits (EmissiveSteelTrapPortrait(), EmissiveBrokenShieldPortrait(), etc.)
-- Expanded SniperFix sniper logic with additional methods for easier patching and modification:
- - DoSniperLogic() - controls whether to use player or opponent sniper logic
- - DoAttackTargetSlotsLogic() - controls attack logic for each target slot
- - GetValidTargets() - returns the list of card slot the player and opponent can target
- - PlayerTargetSelectedCallback() - called when the player selects a valid target
- - PlayerSlotCursorEnterCallback() - called when the player's cursor enters a slot
- - OpponentSelectTarget() - returns a card slot for the opponent to target and attack
-- Revamped the wiki to (hopefully) make it easier to navigate and read through
+* Fixed resource drone behaving incorrectly outside of Act 1
+* Added null checks to various custom triggers
+* Added more extension methods for CardInfo and AbilityInfo
+* Added PlayableCard extension methods: AddShieldCount(Ability), AddShieldCount\() and AddShieldCount(Ability), RemoveShieldCount\()
+ * These affect the internal numShields field, and do NOT add or remove ability stacks
+* Added alternate portrait 'SacrificablePortrait' for when a card can be sacrificed in Act 1 or Act 2 (part of the SetShaking method)
+* Added methods for getting the emissive portraits for extra alt portraits (EmissiveSteelTrapPortrait(), EmissiveBrokenShieldPortrait(), etc.)
+* Expanded SniperFix sniper logic with additional methods for easier patching and modification:
+ * DoSniperLogic()
+ * Controls whether to use player or opponent sniper logic
+ * DoAttackTargetSlotsLogic()
+ * Controls attack logic for each target slot
+ * GetValidTargets()
+ * Returns the list of card slot the player and opponent can target
+ * PlayerTargetSelectedCallback()
+ * Called when the player selects a valid target
+ * PlayerSlotCursorEnterCallback()
+ * Called when the player's cursor enters a slot
+ * OpponentSelectTarget()
+ * Returns a card slot for the opponent to target and attack
+* Revamped the wiki to (hopefully) make it easier to navigate and read through
# 2.18.2
-- Fixed abilities marked TriggersOncePerStack not actually triggering once per stack on evolution
-- Fixed CardManager.Remove not actually removing cards
-- Fixed mods on card clones being lost during card sync
-- Added extension methods for setting the emissions for SteelTrap and BrokenShield alt portraits
-- Added Config to disable boss scenery for optimization purposes
-- Exposed EncounterManager.NewEncounters so JSONLoader may replace existing Encounters
-- Refactored Act 1 energy drone movement logic, added support for 'immediate' bool (Default Drone must be true)
-- Act 1 energy drone game object is now named 'Part1ResourceDrone'
-- Act 1 energy drone is now correctly synced with the scale when Default Drone config is false
+* Fixed abilities marked TriggersOncePerStack not actually triggering once per stack on evolution
+* Fixed CardManager.Remove not actually removing cards
+* Fixed mods on card clones being lost during card sync
+* Added extension methods for setting the emissions for SteelTrap and BrokenShield alt portraits
+* Added Config to disable boss scenery for optimization purposes
+* Exposed EncounterManager.NewEncounters so JSONLoader may replace existing Encounters
+* Refactored Act 1 energy drone movement logic, added support for 'immediate' bool (Default Drone must be true)
+* Act 1 energy drone game object is now named 'Part1ResourceDrone'
+* Act 1 energy drone is now correctly synced with the scale when Default Drone config is false
# 2.18.1
-- Fixed BoxCollider null reference during Act 3 Build-A-Card-Sequencer
-- Fixed Act 3 bone displayer screen changing to static whenever P03 changes their face
-- Added TryGetGuidAndKeyEnumValue for getting the mod GUID and key from enum value
-- Custom regions now store their mod GUID
+* Fixed BoxCollider null reference during Act 3 Build-A-Card-Sequencer
+* Fixed Act 3 bone displayer screen changing to static whenever P03 changes their face
+* Added TryGetGuidAndKeyEnumValue for getting the mod GUID and key from enum value
+* Custom regions now store their mod GUID
# 2.18.0
-- Fixed SetPixelAbilityIcon() not accepting 22x10 textures for activated abilities
-- Fixed IModifyDamageTaken priority sorting being reversed
-- Fixed null errors in TakeDamage and custom trigger calls
-- Added extension methods for getting emission portraits, setting animated portrait
-- Added CustomFields helper for associating data with objects or classes
-- Added IModifyDirectDamage, IOnTurnEndInQueue custom triggers
-- Custom Tribes now store their name and GUID
+* Fixed SetPixelAbilityIcon() not accepting 22x10 textures for activated abilities
+* Fixed IModifyDamageTaken priority sorting being reversed
+* Fixed null errors in TakeDamage and custom trigger calls
+* Added extension methods for getting emission portraits, setting animated portrait
+* Added CustomFields helper for associating data with objects or classes
+* Added IModifyDirectDamage, IOnTurnEndInQueue custom triggers
+* Custom Tribes now store their name and GUID
# 2.17.0
-- Fixed card extension GetAbilityStacks() being able to return a negative value; minimum value is now capped at 0
-- Added ability interfaces IModifyDamageTaken, IPreTakeDamage, which trigger at the start of PlayableCard.TakeDamage
-- Added PlayableCard extension method ResetShield(Ability) for only resetting shields belonging to a certain ability
-- Added ShieldManager class and changed how shields are managed in the game's logic
-- Added abstract classes DamageShieldBehaviour and ActivatedDamageShieldBehaviour
-- Added support for adding alternate portraits for SteelTrap activation and broken shields
-- Added portrait setters SetSteelTrapPortrait(), SetBrokenShieldPortrait(), SetPixelSteelTrapPortrait(), SetPixelBrokenShieldPortrait()
-- Added support for adding new language translations
-- Added AbilityInfo extension method SetHideSingleStacks(), affecting how stacking sigils are affected by being hidden (see wiki)
-- DeathShield ability now has a custom AbilityBehaviour attached to it
-- DeathShield ability is no longer passive, and can stack
-- TakeDamage trigger now requires damage to be above 0 to activate
-- Cards can no longer lose shields from attacks that deal 0 damage
-- Damage dealt to cards can no longer go below 0
-- Updated the wiki with sections on the additions
-- Zombie Parrot is now part of the Avian tribe
+* Fixed card extension GetAbilityStacks() being able to return a negative value; minimum value is now capped at 0
+* Added ability interfaces IModifyDamageTaken, IPreTakeDamage, which trigger at the start of PlayableCard.TakeDamage
+* Added PlayableCard extension method ResetShield(Ability) for only resetting shields belonging to a certain ability
+* Added ShieldManager class and changed how shields are managed in the game's logic
+* Added abstract classes DamageShieldBehaviour and ActivatedDamageShieldBehaviour
+* Added support for adding alternate portraits for SteelTrap activation and broken shields
+* Added portrait setters SetSteelTrapPortrait(), SetBrokenShieldPortrait(), SetPixelSteelTrapPortrait(), SetPixelBrokenShieldPortrait()
+* Added support for adding new language translations
+* Added AbilityInfo extension method SetHideSingleStacks(), affecting how stacking sigils are affected by being hidden (see wiki)
+* DeathShield ability now has a custom AbilityBehaviour attached to it
+* DeathShield ability is no longer passive, and can stack
+* TakeDamage trigger now requires damage to be above 0 to activate
+* Cards can no longer lose shields from attacks that deal 0 damage
+* Damage dealt to cards can no longer go below 0
+* Updated the wiki with sections on the additions
+* Zombie Parrot is now part of the Avian tribe
# 2.16.1
-- Gem Shield sigil now visually applies the Armoured sigil to cards in Act 1
+* Gem Shield sigil now visually applies the Armoured sigil to cards in Act 1
# 2.16.0
-- Added interface IGetAttackingSlots for altering the order cards attack in, see the wiki for more information
-- Added out-of-turn (cards attacking outside of their owner's turn) damage support
-- Added PlayableCard extension method GetAbilityStacks()
-- Added PlayableCard extension method TransformIntoCardInHand()
-- Moved SlotAttackSlotFixes and SelfAttackDamagePatch from community patches to the API, renamed to SlotAttackSlotPatches and DoCombatPhasePatches respectively
-- Made community patch method RandomAbilityPatches.GetRandomAbility public
+* Added interface IGetAttackingSlots for altering the order cards attack in, see the wiki for more information
+* Added out-of-turn (cards attacking outside of their owner's turn) damage support
+* Added PlayableCard extension method GetAbilityStacks()
+* Added PlayableCard extension method TransformIntoCardInHand()
+* Moved SlotAttackSlotFixes and SelfAttackDamagePatch from community patches to the API, renamed to SlotAttackSlotPatches and DoCombatPhasePatches respectively
+* Made community patch method RandomAbilityPatches.GetRandomAbility public
# 2.15.2
-- Fixed cards not evolving correctly if the Fledgling sigil was obtained via card mods (card merge, totem, etc.)
-- Moved the Squirrel Orbit community patch into the main API
-- Added SetTransformCardId(), GetTransformerCardId() for controlling the Transformer evolution separate of the standard evolution
-- Transformer sigil will now also check for a card's API-set TransformerCardId if no card mod is found
-- Transformer sigil now also adjusts Blood and Bone costs when transforming
-- Transformer sigil now correctly works for cards without a defined evolution/transformation
+* Fixed cards not evolving correctly if the Fledgling sigil was obtained via card mods (card merge, totem, etc.)
+* Moved the Squirrel Orbit community patch into the main API
+* Added SetTransformCardId(), GetTransformerCardId() for controlling the Transformer evolution separate of the standard evolution
+* Transformer sigil will now also check for a card's API-set TransformerCardId if no card mod is found
+* Transformer sigil now also adjusts Blood and Bone costs when transforming
+* Transformer sigil now correctly works for cards without a defined evolution/transformation
# 2.15.1
-- Fixed Transformer sigil disappearing upon transformation in certain scenarios
-- Fixed Act 3 Bone Display checking the wrong card cost, resulting in the display always appearing
-- Fixed Act 3 Bone Display null error in certain Acts
+* Fixed Transformer sigil disappearing upon transformation in certain scenarios
+* Fixed Act 3 Bone Display checking the wrong card cost, resulting in the display always appearing
+* Fixed Act 3 Bone Display null error in certain Acts
# 2.15.0
-- Fixed friend cards created by G0LLY not having any mods
-- Reverted previous change to cloned CardInfos
-- Tweaked RandomAbilityPatches to hopefully prevent obtaining sigils already possessed by the card
-- Added cost display support for Act 3
-- Added bone counter for Act 3
+* Fixed friend cards created by G0LLY not having any mods
+* Reverted previous change to cloned CardInfos
+* Tweaked RandomAbilityPatches to hopefully prevent obtaining sigils already possessed by the card
+* Added cost display support for Act 3
+* Added bone counter for Act 3
# 2.14.5
-- Cloned CardInfos now only copy over Gemify mods, unless they possess BountyHunterInfo/DeathCardInfo/BuildACardInfo
-- Fixed certain card mods duplicating when the card evolve
-- Added ResourcesManager.RemoveMaxEnergy, ResourcesManager.ShowRemoveMaxEnergy extension methods
+* Cloned CardInfos now only copy over Gemify mods, unless they possess BountyHunterInfo/DeathCardInfo/BuildACardInfo
+* Fixed certain card mods duplicating when the card evolve
+* Added ResourcesManager.RemoveMaxEnergy, ResourcesManager.ShowRemoveMaxEnergy extension methods
# 2.14.4
-- Fixed the first energy cell remaining closed in Act 1 when battle starts
-- Added new field to PeltManager.PeltData 'peltTierName' used when trading pelts
-- Added extension method PeltData.SetTierName
-- The Trader will now speak the correct name of custom pelts when trading with them
-- Added DialogueManager.GenerateTraderPeltsEvent for creating custom dialogue events spoken by the Trader when trading a custom pelt
-- Added DialogueManager.GenerateRegionIntroEvent for creating the dialogue event played upon entering a custom region
+* Fixed the first energy cell remaining closed in Act 1 when battle starts
+* Added new field to PeltManager.PeltData 'peltTierName' used when trading pelts
+* Added extension method PeltData.SetTierName
+* The Trader will now speak the correct name of custom pelts when trading with them
+* Added DialogueManager.GenerateTraderPeltsEvent for creating custom dialogue events spoken by the Trader when trading a custom pelt
+* Added DialogueManager.GenerateRegionIntroEvent for creating the dialogue event played upon entering a custom region
# 2.14.3
-- Fixed Act 2 bug relating to stackable sigils and activated sigils in the deck display menu
-- Fixed dynamic costs still not working in Act 2
-- Fixed dynamic gem costs checking ResourcesManager instead of OpponentGemsManager for opponent cards
-- Fixed dynamic costs not checking for owned blue gems
-- Fixed dynamic costs not updating energy display correctly
-- Changed dynamic costs to patch SetInfo instead of Awake
-- Re-added dynamic cost error messages for when the card or card info is null
-- Added ResourcesManager.Instance.GemsOfType(GemType) to check for owned gems of the specified type
+* Fixed Act 2 bug relating to stackable sigils and activated sigils in the deck display menu
+* Fixed dynamic costs still not working in Act 2
+* Fixed dynamic gem costs checking ResourcesManager instead of OpponentGemsManager for opponent cards
+* Fixed dynamic costs not checking for owned blue gems
+* Fixed dynamic costs not updating energy display correctly
+* Changed dynamic costs to patch SetInfo instead of Awake
+* Re-added dynamic cost error messages for when the card or card info is null
+* Added ResourcesManager.Instance.GemsOfType(GemType) to check for owned gems of the specified type
# 2.14.2
-- Fixed Overclock patch not checking for the correct Acts
-- Fixed appearance behaviour's Card field always returning null in Act 2
-- Added OverridePixelPortrait virtual method to PixelAppearanceBehaviour to allow for changing card portraits in Act 2
-- Added CardInfo.SetPixelAlternatePortrait() and Cardinfo.GetPixelAlternatePortrait() for storing alternate pixel portraits
-- Re-added SetTerrain method without optional bool parameter
-- SwitchToAlternatePortrait and SwitchToDefaultPortrait now work in Act 2 using the above system
-- Removed cost-related error spam in Act 2
+* Fixed Overclock patch not checking for the correct Acts
+* Fixed appearance behaviour's Card field always returning null in Act 2
+* Added OverridePixelPortrait virtual method to PixelAppearanceBehaviour to allow for changing card portraits in Act 2
+* Added CardInfo.SetPixelAlternatePortrait() and Cardinfo.GetPixelAlternatePortrait() for storing alternate pixel portraits
+* Re-added SetTerrain method without optional bool parameter
+* SwitchToAlternatePortrait and SwitchToDefaultPortrait now work in Act 2 using the above system
+* Removed cost-related error spam in Act 2
# 2.14.1
-- Custom tribes are now given a placeholder reward cardback if one isn't provided
-- Fixed visual error when flipping a custom tribe choice for a tribe without a custom cardback
-- Fixed pixel stat icons not hiding the underlying stat number
-- Fixed ChooseTarget null exception
-- Fixed opponent cards with mods not being created properly (eg Bounty Hunters)
-- Fixed being able to ring the bell in Part 2 during the Tutor sequence
-- Fixed GBC packs not checking for onePerDeck when selecting possible cards
-- Fixed decals added via temporary mods not clearing from cards in Act 2
-- Changed what vanilla abilities are marked as Act2Modular (see the Part2ModularAbilities file for the full list)
-- Removed leftover debug info during start-up
-- Added CardInfo.SetCardTemple()
-- Added CardModInfo extension methods SetTemporaryDecal and IsTemporaryDecal (primarily for internal use, maybe you'll find a use for it)
-- Added GBCPackManager.ModifyGBCPacks function for altering what cards can be found in GBC card packs
+* Custom tribes are now given a placeholder reward cardback if one isn't provided
+* Fixed visual error when flipping a custom tribe choice for a tribe without a custom cardback
+* Fixed pixel stat icons not hiding the underlying stat number
+* Fixed ChooseTarget null exception
+* Fixed opponent cards with mods not being created properly (eg Bounty Hunters)
+* Fixed being able to ring the bell in Part 2 during the Tutor sequence
+* Fixed GBC packs not checking for onePerDeck when selecting possible cards
+* Fixed decals added via temporary mods not clearing from cards in Act 2
+* Changed what vanilla abilities are marked as Act2Modular (see the Part2ModularAbilities file for the full list)
+* Removed leftover debug info during start-up
+* Added CardInfo.SetCardTemple()
+* Added CardModInfo extension methods SetTemporaryDecal and IsTemporaryDecal (primarily for internal use, maybe you'll find a use for it)
+* Added GBCPackManager.ModifyGBCPacks function for altering what cards can be found in GBC card packs
# 2.14.0
-- Fixed Sniper duplicating attacks from sigils like Double Strike
-- Fixed interaction between Waterborne and Fledgling in Act 2
-- Fixed Cuckoo sigil softlocking in Act 2 when making a Raven Egg
-- Fixed sigils added via temporary mods not displaying in Act 2
-- Fixed hiddenAbilities not affecting sigil display in Act 2
-- Fixed Handy sigil visual bug outside of Act 2
-- Fixed Shapeshifter special ability in Act 2
-- Added pixel sprites for Raven Egg and Cuckoo/Broken Egg
-- Added ResourceBankManager.AddDecal(), PlayableCard.AddTemporaryMods(), CardModificationInfo.AddDecalIds
-- Added AbilityInfo.SetPixelIcon(string pathToArt), CardInfo.RemoveAppearances(), CardInfo.SetDefaultEvolutionName()
-- Added DialogueManager.PlayDialogueEventSafe - combines TextDisplayer.PlayDialogueEvent and DialogueHandler.PlayDialogueHandler for multi-act support
-- Added support for directly loading AudioClips via the GramophoneManager
-- Added support for adding decals to pixel cards via DecalIds
-- Added pixel portrait for Ijiraq
-- Added support for changing costs midbattle using CardModificationInfos or a HarmonyPatch
-- Changed TranspilerHelpers.LogCodeInscryptions to also function as an extension method for List
-- FullSpecialTriggeredAbility now stores the ability name and mod GUID
-- Temporary mods can now be used to add decals to a card
-- CardRenderInfo.OverrideAbilityIcon now works for Act 2 sigils
-- CardInfo.SetTerrain() now has optional parameter 'useTerrainLayout', defaulting to true
-- Made method used to add stacks to pixel sigils public
-- Updated the wiki
+* Fixed Sniper duplicating attacks from sigils like Double Strike
+* Fixed interaction between Waterborne and Fledgling in Act 2
+* Fixed Cuckoo sigil softlocking in Act 2 when making a Raven Egg
+* Fixed sigils added via temporary mods not displaying in Act 2
+* Fixed hiddenAbilities not affecting sigil display in Act 2
+* Fixed Handy sigil visual bug outside of Act 2
+* Fixed Shapeshifter special ability in Act 2
+* Added pixel sprites for Raven Egg and Cuckoo/Broken Egg
+* Added ResourceBankManager.AddDecal(), PlayableCard.AddTemporaryMods(), CardModificationInfo.AddDecalIds
+* Added AbilityInfo.SetPixelIcon(string pathToArt), CardInfo.RemoveAppearances(), CardInfo.SetDefaultEvolutionName()
+* Added DialogueManager.PlayDialogueEventSafe
+ * Combines TextDisplayer.PlayDialogueEvent and DialogueHandler.PlayDialogueHandler for multi-act support
+* Added support for directly loading AudioClips via the GramophoneManager
+* Added support for adding decals to pixel cards via DecalIds
+* Added pixel portrait for Ijiraq
+* Added support for changing costs midbattle using CardModificationInfos or a HarmonyPatch
+* Changed TranspilerHelpers.LogCodeInscryptions to also function as an extension method for List
+* FullSpecialTriggeredAbility now stores the ability name and mod GUID
+* Temporary mods can now be used to add decals to a card
+* CardRenderInfo.OverrideAbilityIcon now works for Act 2 sigils
+* CardInfo.SetTerrain() now has optional parameter 'useTerrainLayout', defaulting to true
+* Made method used to add stacks to pixel sigils public
+* Updated the wiki
# 2.13.3
-- Fixed null error when opening card packs in Act 2
-- Fixed pixel cards with activated sigils showing the activated sigil icon twice (does not fix the button obscuring sigils)
-- Added new helper class GemsManagerHelpers with helper methods: OpponentHasGems, PlayerHasGems
-- Changed how Act 2 descriptions are altered to prevent conflicts
-- True Scholar now correctly requires a Blue Gem to be owned prior to use
+* Fixed null error when opening card packs in Act 2
+* Fixed pixel cards with activated sigils showing the activated sigil icon twice (does not fix the button obscuring sigils)
+* Added new helper class GemsManagerHelpers with helper methods: OpponentHasGems, PlayerHasGems
+* Changed how Act 2 descriptions are altered to prevent conflicts
+* True Scholar now correctly requires a Blue Gem to be owned prior to use
# 2.13.2
-- Fixed Hoarder sigil breaking when used by opponents in Act 2
-- Fixed Hodag special ability not working in Act 2
-- Fixed cards marked as AffectedByTidalLock not being killed by Tidal Lock when it's on a giant card
-- Added card extension methods SetAffectedByTidalLock and HasAlternatePortrait
-- Added ability extension method SetPart2Ability
-- Added AbilityCardMetaCategory AbilityManager.Part2Modular
-- Added pixel portraits for Empty Vessel and its Gemified variants, Ant, Bee, Dam, Chime, and the Tail cards
-- Amorphous sigil now works in Act 2
-- Vessel Printer sigil now works in Act 2
-- Trinket Bearer sigil is now disabled in Act 2
-- Hidden abilities are now properly hidden in Act 2
-- Fledgling sigil now properly shows the required (up to the number 3) in Act 2
-- Fledgling sigil's rulebook description now updates to show the selected card's actual number of required turns
-- Squirrel, Aqua Squirrel, and Rabbit are now marked as AffectedByTidalLock
-- SteelTrap sigil no longer changes a card's portrait to the closed trap; will now switch to an alternate portrait if it exists
+* Fixed Hoarder sigil breaking when used by opponents in Act 2
+* Fixed Hodag special ability not working in Act 2
+* Fixed cards marked as AffectedByTidalLock not being killed by Tidal Lock when it's on a giant card
+* Added card extension methods SetAffectedByTidalLock and HasAlternatePortrait
+* Added ability extension method SetPart2Ability
+* Added AbilityCardMetaCategory AbilityManager.Part2Modular
+* Added pixel portraits for Empty Vessel and its Gemified variants, Ant, Bee, Dam, Chime, and the Tail cards
+* Amorphous sigil now works in Act 2
+* Vessel Printer sigil now works in Act 2
+* Trinket Bearer sigil is now disabled in Act 2
+* Hidden abilities are now properly hidden in Act 2
+* Fledgling sigil now properly shows the required (up to the number 3) in Act 2
+* Fledgling sigil's rulebook description now updates to show the selected card's actual number of required turns
+* Squirrel, Aqua Squirrel, and Rabbit are now marked as AffectedByTidalLock
+* SteelTrap sigil no longer changes a card's portrait to the closed trap; will now switch to an alternate portrait if it exists
# 2.13.1
-- Fixed custom items falling through reality
-- Added card extension method IsAffectedByTidalLock
-- Mental Gemnastics sigil now works in Act 1
-- Tidal Lock sigil now works for non-Moon cards
+* Fixed custom items falling through reality
+* Added card extension method IsAffectedByTidalLock
+* Mental Gemnastics sigil now works in Act 1
+* Tidal Lock sigil now works for non-Moon cards
# 2.13.0
-- Fixed DontDestroyOnLoad warnings when using custom items
-- Fixed weird spacing for Mox cost textures in Act 1
-- Fixed player death cards not inheriting Energy, Mox, or custom costs
-- Fixed the hint dialogue for insufficient Energy in Act 1 being the wrong colour
-- Fixed ExtendedActivatedAbilityBehaviour discarding negative activation cost modifiers
-- Fixed Sniper not accounting for custom sigils that modify attack slots
-- Fixed Tutor not working in Act 2
-- Added more extension methods to BoardManager
-- Added new card extensions SetGemify and SetGemsCost(params GemType[])
-- Added catch-all cost textures for when Blood or Bones go above 13
-- Added CardModificationInfoManager and DeathCardManager
-- Added extended property support and extensions for CardModificationInfo
-- Added Blood activation cost support to ExtendedActivatedAbilityBehaviour
-- ExtendedActivatedAbilityBehaviour now calls PostActivate() if a card dies from paying the Health cost
-- Leshy now recognises death cards with multiple costs in his dialogue
-- Leshy will now let you create death cards with up to 8 sigils
-- Minor adjustments to some cost textures
-- Rearranged order of Mox cost textures to align with order of Mox on the Gem Module
-- Removed empty cost textures for Blood, Bones, Energy, Mox from the community patches
-- Sniper patch's methods are now public
+* Fixed DontDestroyOnLoad warnings when using custom items
+* Fixed weird spacing for Mox cost textures in Act 1
+* Fixed player death cards not inheriting Energy, Mox, or custom costs
+* Fixed the hint dialogue for insufficient Energy in Act 1 being the wrong colour
+* Fixed ExtendedActivatedAbilityBehaviour discarding negative activation cost modifiers
+* Fixed Sniper not accounting for custom sigils that modify attack slots
+* Fixed Tutor not working in Act 2
+* Added more extension methods to BoardManager
+* Added new card extensions SetGemify and SetGemsCost(params GemType[])
+* Added catch-all cost textures for when Blood or Bones go above 13
+* Added CardModificationInfoManager and DeathCardManager
+* Added extended property support and extensions for CardModificationInfo
+* Added Blood activation cost support to ExtendedActivatedAbilityBehaviour
+* ExtendedActivatedAbilityBehaviour now calls PostActivate() if a card dies from paying the Health cost
+* Leshy now recognises death cards with multiple costs in his dialogue
+* Leshy will now let you create death cards with up to 8 sigils
+* Minor adjustments to some cost textures
+* Rearranged order of Mox cost textures to align with order of Mox on the Gem Module
+* Removed empty cost textures for Blood, Bones, Energy, Mox from the community patches
+* Sniper patch's methods are now public
# 2.12.0
-- Fixed ExtendedActivatedAbilityBehaviour's Health cost not subtracting Health correctly
-- Fixed softlock in Act 1 during death card creation
-- Fixed custom cards that start Gemified not working as intended when obtained in-game
-- Potentially fixed softlock when making terrain for a region
-- Added further checks to challenge icon-related patch to prevent softlocks
-- Added decal, appearance behaviour, and Gemified card support for Act 2 cards
-- Added Singleton for keeping track of opponent gems
-- Added new helper method for creating Sprites from resource files in an assembly
-- Added new SpriteType for creating pixel card decals
-- Gemified visuals now work correctly for Act 3 opponents
-- Cost choice node now offers each Mox colour individually
-- Added new config "Default Drone" to change the model and position of the Energy Drone
-- Amorphous sigil now activates when used by opponents or obtained via evolution/temp mod
-- Owned Mox in Act 1 now updates when a card is hooked by the Angler or via the Hook item
+* Fixed ExtendedActivatedAbilityBehaviour's Health cost not subtracting Health correctly
+* Fixed softlock in Act 1 during death card creation
+* Fixed custom cards that start Gemified not working as intended when obtained in-game
+* Potentially fixed softlock when making terrain for a region
+* Added further checks to challenge icon-related patch to prevent softlocks
+* Added decal, appearance behaviour, and Gemified card support for Act 2 cards
+* Added Singleton for keeping track of opponent gems
+* Added new helper method for creating Sprites from resource files in an assembly
+* Added new SpriteType for creating pixel card decals
+* Gemified visuals now work correctly for Act 3 opponents
+* Cost choice node now offers each Mox colour individually
+* Added new config "Default Drone" to change the model and position of the Energy Drone
+* Amorphous sigil now activates when used by opponents or obtained via evolution/temp mod
+* Owned Mox in Act 1 now updates when a card is hooked by the Angler or via the Hook item
# 2.11.2
-- Fixed starter deck custom unlocks not working
-- Fixed card icons not being properly centred for starter decks with 4+ cards
-- Cards in Acts 2 and 3 can now display up to 8 sigils
-- Blood tokens in Act 3 now appear to the side of the board instead of on it
-- Blood tokens now stack on each other when there are more than 4
+* Fixed starter deck custom unlocks not working
+* Fixed card icons not being properly centred for starter decks with 4+ cards
+* Cards in Acts 2 and 3 can now display up to 8 sigils
+* Blood tokens in Act 3 now appear to the side of the board instead of on it
+* Blood tokens now stack on each other when there are more than 4
# 2.11.1
-- Fixed regions in Act 1 being out of order
-- Fixed the console message concerning custom dialogue events not giving the right amount
+* Fixed regions in Act 1 being out of order
+* Fixed the console message concerning custom dialogue events not giving the right amount
# 2.11.0
-- Refactored how regions are handled by the API to prevent duplicate bosses
-- Refactored how bosses are selected to prevent duplicates being encountered
-- Changed when modded Ascension data is cleared to allow for editing it post-clear
-- Added more descriptive error logs for some commonly encountered errors
-- Added config option to reduce the amount of debug info shown in the console
-- Added methods to aid in creating encounter turn plans
-- Added more methods for interacting with lists, new debug method to aid in making transpilers
-- Added ExtendedActivatedAbilityBehaviour class; allows for dynamic costs and Health costs
-- Fixed SetOnePerDeck() and SetHideStats() being inaccessible
-- Fixed AddCardBlueprint() not setting the replacement card correctly
+* Refactored how regions are handled by the API to prevent duplicate bosses
+* Refactored how bosses are selected to prevent duplicates being encountered
+* Changed when modded Ascension data is cleared to allow for editing it post-clear
+* Added more descriptive error logs for some commonly encountered errors
+* Added config option to reduce the amount of debug info shown in the console
+* Added methods to aid in creating encounter turn plans
+* Added more methods for interacting with lists, new debug method to aid in making transpilers
+* Added ExtendedActivatedAbilityBehaviour class; allows for dynamic costs and Health costs
+* Fixed SetOnePerDeck() and SetHideStats() being inaccessible
+* Fixed AddCardBlueprint() not setting the replacement card correctly
# 2.10.0
-- Completely revamped PeltManager to be more user friendly (Mod breaking)
-- Added LocalizationManager for more language support with mods
-- Added helper method for custom pelts to change cards trader
-- Pelts offered by Trapper capped at 8.
-- Pelts offered by Trapper are now randomized if more than 8
-- Fixed soft lock at trader when having more pelts than cards to offer
-- Fixed the campfire fix breaking the normal sequence
-- Fixed HasCardMetaCategory returning the inverse of its intended value
-- Fixed stackable sigils not showing numbers above 9
+* Completely revamped PeltManager to be more user friendly (Mod breaking)
+* Added LocalizationManager for more language support with mods
+* Added helper method for custom pelts to change cards trader
+* Pelts offered by Trapper capped at 8.
+* Pelts offered by Trapper are now randomized if more than 8
+* Fixed soft lock at trader when having more pelts than cards to offer
+* Fixed the campfire fix breaking the normal sequence
+* Fixed HasCardMetaCategory returning the inverse of its intended value
+* Fixed stackable sigils not showing numbers above 9
# 2.9.1
-- Fixed the campfire fix breaking the normal sequence
+* Fixed the campfire fix breaking the normal sequence
# 2.9.0
-- Added talking card support!
-- Moved the "CustomLine" struct outside of the Dialogue.Helpers class.
-- Fixed tribe choice node being able to offer vanilla tribes with no cards
-- Fixed totem choice node being able to offer tops for vanilla tribes with no cards
-- Added fallbacks for tribal choice node if there are less than 3 chooseable tribes
-- Added fallback to campfire node if you don't have any cards that can be buffed
-- Fixed 'outdated plugins' warning showing up when it shouldn't, tweaked message slightly
+* Added talking card support!
+* Moved the "CustomLine" struct outside of the Dialogue.Helpers class.
+* Fixed tribe choice node being able to offer vanilla tribes with no cards
+* Fixed totem choice node being able to offer tops for vanilla tribes with no cards
+* Added fallbacks for tribal choice node if there are less than 3 chooseable tribes
+* Added fallback to campfire node if you don't have any cards that can be buffed
+* Fixed 'outdated plugins' warning showing up when it shouldn't, tweaked message slightly
# 2.8.1
-- Added CardInfo extensions for checking CardMetaCategories, cause why not
-- Added DialogueManager for custom dialogue for regions and Custom Color support
-- Added ResourceBankManager for custom resources. Avoids doing this for every mod
-- Deprecated DialogueEventGenerator (Moved to Dialogue Manager)
-- Fixed repeating bosses on regions that have multiple boss possibilities
-- Fixed custom props not having a renderer on the top parent and breaking loading regions
-- Fixed arrows on the challenges select screen being offscreen at certain resolutions
-- Fixed tribe choice node being able to offer custom tribes with no cards
-- Fixed being able to get custom totem tops for tribes with no cards
+* Added CardInfo extensions for checking CardMetaCategories, cause why not
+* Added DialogueManager for custom dialogue for regions and Custom Color support
+* Added ResourceBankManager for custom resources. Avoids doing this for every mod
+* Deprecated DialogueEventGenerator (Moved to Dialogue Manager)
+* Fixed repeating bosses on regions that have multiple boss possibilities
+* Fixed custom props not having a renderer on the top parent and breaking loading regions
+* Fixed arrows on the challenges select screen being offscreen at certain resolutions
+* Fixed tribe choice node being able to offer custom tribes with no cards
+* Fixed being able to get custom totem tops for tribes with no cards
# 2.8.0
-- Added support for custom masks
-- Fixed sometimes items use the wrong behaviour
-- Added more resource and asset bundle helpers
+* Added support for custom masks
+* Fixed sometimes items use the wrong behaviour
+* Added more resource and asset bundle helpers
# 2.7.4
-- Fixed latch fix modifying the base info
-- Fixed stackable abilities activating twice when they shouldn't
+* Fixed latch fix modifying the base info
+* Fixed stackable abilities activating twice when they shouldn't
# 2.7.3
-- Fixed sniper fix not accounting for cards with Repulsive ability
-- Fixed latch abilities not working in Act 2
-- Added ExtendedProperties for abilities
-- Added new ability setter SetTriggersOncePerStack for controlling the behaviour of stackable abilities after a card evolves
-- Added new helper methods for creating cards: SetOnePerDeck, SetHideStats
-- Added new helper methods for abilities: SetCanStack, SetTriggersOncePerStack, SetActivated, SetPassive, SetConduit, SetConduitCell
-- Added new remover methods for cards: RemoveAbilities, RemoveAbilitiesSingle, RemoveTraits, RemoveTribes
+* Fixed sniper fix not accounting for cards with Repulsive ability
+* Fixed latch abilities not working in Act 2
+* Added ExtendedProperties for abilities
+* Added new ability setter SetTriggersOncePerStack for controlling the behaviour of stackable abilities after a card evolves
+* Added new helper methods for creating cards: SetOnePerDeck, SetHideStats
+* Added new helper methods for abilities: SetCanStack, SetTriggersOncePerStack, SetActivated, SetPassive, SetConduit, SetConduitCell
+* Added new remover methods for cards: RemoveAbilities, RemoveAbilitiesSingle, RemoveTraits, RemoveTribes
# v2.7.2
-- Added `CanActivateOutsideBattles` extension method to ConsumableItemData so they can be used outside of battles.
-- Added Missing Tribe Icon fallback texture for totem tops when a tribe has no icon
-- Changed TotemManager to accept a `CompositeTotemPiece` type for custom behaviour other than always a custom icon
-- Fixed lag when entering gain consumable item map node
-- Fixed crash when using custom consumable items
-- Fixed hard lock when getting totem top that doesn't have an icon
-- Fixed Pack Rat card object not having the correct background during the item node sequence
-- Fixed Latch abilities removing stat boosts when latching a card
-- Fixed latched abilities not properly rendering in some acts
+* Added `CanActivateOutsideBattles` extension method to ConsumableItemData so they can be used outside of battles.
+* Added Missing Tribe Icon fallback texture for totem tops when a tribe has no icon
+* Changed TotemManager to accept a `CompositeTotemPiece` type for custom behaviour other than always a custom icon
+* Fixed lag when entering gain consumable item map node
+* Fixed crash when using custom consumable items
+* Fixed hard lock when getting totem top that doesn't have an icon
+* Fixed Pack Rat card object not having the correct background during the item node sequence
+* Fixed Latch abilities removing stat boosts when latching a card
+* Fixed latched abilities not properly rendering in some acts
# v2.7.1
-- Changed Pelt Manager to no longer have an interface for future safety! (NOTE This will break all mods with custom pelts!)
-- Added Squirrel tribe art (Thanks Drift!)
-- Fixed Green Gem stat icon showing as a black square in act 1
-- Fixed Green Gem stat icon not appearing in rulebook
-- Fixed Squirrel totem top causing NMA when using custom totem tops
-- Fixed being unable to play cards with a Blood cost above 4 via sacrifices
+* Changed Pelt Manager to no longer have an interface for future safety! (NOTE This will break all mods with custom pelts!)
+* Added Squirrel tribe art (Thanks Drift!)
+* Fixed Green Gem stat icon showing as a black square in act 1
+* Fixed Green Gem stat icon not appearing in rulebook
+* Fixed Squirrel totem top causing NMA when using custom totem tops
+* Fixed being unable to play cards with a Blood cost above 4 via sacrifices
# v2.7.0
-- Added support for custom pelts
-- Added support for converting audio files to AudioClip objects
-- Added support for adding custom tracks to the Gramophone
-- Added support for adding custom audio files
-- Warning message for outdated plugins now lists the outdated plugins
-- Energy Drone now tweens with the scales, kinda
-- Fixed visual bug where energy cells didn't start closed in successive battles
+* Added support for custom pelts
+* Added support for converting audio files to AudioClip objects
+* Added support for adding custom tracks to the Gramophone
+* Added support for adding custom audio files
+* Warning message for outdated plugins now lists the outdated plugins
+* Energy Drone now tweens with the scales, kinda
+* Fixed visual bug where energy cells didn't start closed in successive battles
# v2.6.0
-- Added support for custom consumable items using a choice of a few models
-- Added support for custom consumable card in a bottle items
-- Added support for custom consumable items with a custom model
-- Added more helper extensions for checking abilities, traits, special abilities
-- Fixed null instances in Act 2 spamming the console with warnings
+* Added support for custom consumable items using a choice of a few models
+* Added support for custom consumable card in a bottle items
+* Added support for custom consumable items with a custom model
+* Added more helper extensions for checking abilities, traits, special abilities
+* Fixed null instances in Act 2 spamming the console with warnings
# v2.5.3
-- Added support for custom card unlock requirements
-- Fixed non-giant cards with Omni Strike not directly attacking their opposing slot when there are no opposing cards
-- Fixed cards attacking their own side of the board during combat not adding damage to the correct side of the scale
-- Fixed an issue where a challenge would go missing if you had more than 14 installed
+* Added support for custom card unlock requirements
+* Fixed non-giant cards with Omni Strike not directly attacking their opposing slot when there are no opposing cards
+* Fixed cards attacking their own side of the board during combat not adding damage to the correct side of the scale
+* Fixed an issue where a challenge would go missing if you had more than 14 installed
# v2.5.2
-- Fixed the sentry fix overriding patches to SlotAttackSlot
+* Fixed the sentry fix overriding patches to SlotAttackSlot
# v2.5.1
-- Reverted part of the sentry fix that was causing problems
-- Made it easier to override the default totem head
+* Reverted part of the sentry fix that was causing problems
+* Made it easier to override the default totem head
# v2.5.0
-- Added support for custom totem heads
-- Custom Tribes now appear as a totem in the Wood Carver nodes
-- Fixes for Sentry ability in Act 1 relating to PackMule, Loose Tail, and enemy totems
-- Fixed stacked ability icons causing issues when trying to render numbers on some sigil icons
-- Fixed Latches not working in Act 1
+* Added support for custom totem heads
+* Custom Tribes now appear as a totem in the Wood Carver nodes
+* Fixes for Sentry ability in Act 1 relating to PackMule, Loose Tail, and enemy totems
+* Fixed stacked ability icons causing issues when trying to render numbers on some sigil icons
+* Fixed Latches not working in Act 1
# v2.4.2
-- Switched to debug version
+* Switched to debug version
# v2.4.1
-- Fixed Sentry ability not working properly in Act for players or opponents
+* Fixed Sentry ability not working properly in Act for players or opponents
# v2.4.0
-- Reworked challenges
-- Fixed gemified opponent cards not working properly
-- Fixed stat icons in Act 3
+* Reworked challenges
+* Fixed gemified opponent cards not working properly
+* Fixed stat icons in Act 3
# v2.3.0
-- Fixed orange gem not counting towards passive attack
-- Fixed PackMule special ability not working on the player's side
-- Fixed Mox cost choice node not working
-- Fixed boon rulebook and removal
-- Fixed tribe choice nodes
-- Fixed error caused by passing null when assigning a custom tail portrait
-- Improved activated ability fix
-- Improved some extensions and attack buffs
-- Fixes for starter decks
-- Fixes for custom regions, more customisation when creating one
-- Added more extensions
-- Fixed stat icon rendering for Act 3
+* Fixed orange gem not counting towards passive attack
+* Fixed PackMule special ability not working on the player's side
+* Fixed Mox cost choice node not working
+* Fixed boon rulebook and removal
+* Fixed tribe choice nodes
+* Fixed error caused by passing null when assigning a custom tail portrait
+* Improved activated ability fix
+* Improved some extensions and attack buffs
+* Fixes for starter decks
+* Fixes for custom regions, more customisation when creating one
+* Added more extensions
+* Fixed stat icon rendering for Act 3
# v2.2.0
-- Added an interface that triggers when cards are facedown
-- Updated custom artwork for GBC numbers
-- Fixed flipped icons spamming the log with warnings
-- Fixed Tribe API breaking mods that use CardbackTexture
-- Added custom combat triggers
-- Added more custom extensions
-- Fixed Latch abilities in Act 1
-- Fixed extension methods for setting custom flipped portrait affecting the wrong card
-- Fixed optimisation issues caused by passive attack bufs
-- Fixed activated sigils
-- Added node manager for custom nodes
-- Fixed cards getting buffs after the game ends
+* Added an interface that triggers when cards are facedown
+* Updated custom artwork for GBC numbers
+* Fixed flipped icons spamming the log with warnings
+* Fixed Tribe API breaking mods that use CardbackTexture
+* Added custom combat triggers
+* Added more custom extensions
+* Fixed Latch abilities in Act 1
+* Fixed extension methods for setting custom flipped portrait affecting the wrong card
+* Fixed optimisation issues caused by passive attack bufs
+* Fixed activated sigils
+* Added node manager for custom nodes
+* Fixed cards getting buffs after the game ends
# v2.1.0
-- Fixed blurry portraits when playing on low graphics settings
+* Fixed blurry portraits when playing on low graphics settings
# v2.0.3
-- Added support for custom tribes and boons
-- Added config option to opt of custom cost renders for Act 2 cards
-- Refactored and added documentation for CardExtensions
+* Added support for custom tribes and boons
+* Added config option to opt of custom cost renders for Act 2 cards
+* Refactored and added documentation for CardExtensions
# v2.0.2
-- Improved the process of creating stat icons to automatically register and add the corresponding special ability
-- Added log warnings for improperly registered cards
+* Improved the process of creating stat icons to automatically register and add the corresponding special ability
+* Added log warnings for improperly registered cards
# v2.0.1
-- Bugfix for SaveData
+* Bugfix for SaveData
# v2.0
-- Rewritten to use base game objects
+* Rewritten to use base game objects
# v1.13.0
-- Added support for custom card backgrounds, dialogs, encounters and talking cards
-- Fixes to abilities loading and stackable custom abilities
+* Added support for custom card backgrounds, dialogs, encounters and talking cards
+* Fixes to abilities loading and stackable custom abilities
# v1.12.1
-- Bugfix so CustomCard doesn't wipe ability information.
+* Bugfix so CustomCard doesn't wipe ability information.
# v1.12
-- Fixes params.
-- Adds feature for special abilities and special stat icons.
-- Added support for emissions.
+* Fixes params.
+* Adds feature for special abilities and special stat icons.
+* Added support for emissions.
# v1.11
-- Added support for more identifiers
+* Added support for more identifiers
# v1.10.1
-- Fix for abilities which do not have identifier.
+* Fix for abilities which do not have identifier.
# v1.10
-- Added ability identifiers.
+* Added ability identifiers.
# v1.9.1
-- Added support for mox.
-- Forced ability texture to point filter.
+* Added support for mox.
+* Forced ability texture to point filter.
# v1.9
-- Added config options for energy.
+* Added config options for energy.
# v1.8.2
-- Fixed appearanceBehaviour (again).
+* Fixed appearanceBehaviour (again).
# v1.8.1
-- Fix pixelTex dimensions.
+* Fix pixelTex dimensions.
# v1.8
## Not compatible with v1.7.2
-- Changes to using TypeMapper.
+* Changes to using TypeMapper.
# v1.7.2
-- Fixed error when not adding any abilities.
+* Fixed error when not adding any abilities.
# v1.7.1
-- Fixed appearance behaviours not loading properly.
+* Fixed appearance behaviours not loading properly.
# v1.7
-- Added support for custom abilities!
+* Added support for custom abilities!
# v1.6
-- Changed textures to point filter to reduce blur.
+* Changed textures to point filter to reduce blur.
# v1.5.2
-- Enabled fix for evolveParams and some other disabled options.
+* Enabled fix for evolveParams and some other disabled options.
# v1.5.1
-- Fix to accessing private instance for regions.
+* Fix to accessing private instance for regions.
# v1.5
## Not compatible with v1.4
-- Changed all references to API including guid.
+* Changed all references to API including guid.
# v1.4
-- Set up support for customising and adding regions.
+* Set up support for customising and adding regions.
# v1.3
-- Set up project to work as a library for other plugins to use.
+* Set up project to work as a library for other plugins to use.
# v1.2.1.1
-- Fixed previous patch.
+* Fixed previous patch.
# v1.2.1
-- Fixed cards not being inserted into the card pool on chapter select.
+* Fixed cards not being inserted into the card pool on chapter select.
# v1.2
## Not compatible with v1.1
-- Added customising default cards through CustomCard.
-- Custom cards are added via the **CustomCard** constructor rather than through the **AddCard** method.
+* Added customising default cards through CustomCard.
+* 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/Assets/BaseGameDecals/decal_blood_1.png b/InscryptionAPI/Assets/BaseGameDecals/decal_blood_1.png
new file mode 100644
index 00000000..8ecf3a09
Binary files /dev/null and b/InscryptionAPI/Assets/BaseGameDecals/decal_blood_1.png differ
diff --git a/InscryptionAPI/Assets/BaseGameDecals/decal_blood_2.png b/InscryptionAPI/Assets/BaseGameDecals/decal_blood_2.png
new file mode 100644
index 00000000..d0e83980
Binary files /dev/null and b/InscryptionAPI/Assets/BaseGameDecals/decal_blood_2.png differ
diff --git a/InscryptionAPI/Assets/BaseGameDecals/decal_blood_3.png b/InscryptionAPI/Assets/BaseGameDecals/decal_blood_3.png
new file mode 100644
index 00000000..e172d394
Binary files /dev/null and b/InscryptionAPI/Assets/BaseGameDecals/decal_blood_3.png differ
diff --git a/InscryptionAPI/Assets/BaseGameDecals/decal_blood_4.png b/InscryptionAPI/Assets/BaseGameDecals/decal_blood_4.png
new file mode 100644
index 00000000..16c4c2e5
Binary files /dev/null and b/InscryptionAPI/Assets/BaseGameDecals/decal_blood_4.png differ
diff --git a/InscryptionAPI/Assets/BaseGameDecals/decal_child.png b/InscryptionAPI/Assets/BaseGameDecals/decal_child.png
new file mode 100644
index 00000000..1e5492ec
Binary files /dev/null and b/InscryptionAPI/Assets/BaseGameDecals/decal_child.png differ
diff --git a/InscryptionAPI/Assets/BaseGameDecals/decal_fungus.png b/InscryptionAPI/Assets/BaseGameDecals/decal_fungus.png
new file mode 100644
index 00000000..257e6747
Binary files /dev/null and b/InscryptionAPI/Assets/BaseGameDecals/decal_fungus.png differ
diff --git a/InscryptionAPI/Assets/BaseGameDecals/decal_smoke.png b/InscryptionAPI/Assets/BaseGameDecals/decal_smoke.png
new file mode 100644
index 00000000..6bd48df8
Binary files /dev/null and b/InscryptionAPI/Assets/BaseGameDecals/decal_smoke.png differ
diff --git a/InscryptionAPI/Assets/BaseGameDecals/decal_smoke_abilityhole.png b/InscryptionAPI/Assets/BaseGameDecals/decal_smoke_abilityhole.png
new file mode 100644
index 00000000..79c96158
Binary files /dev/null and b/InscryptionAPI/Assets/BaseGameDecals/decal_smoke_abilityhole.png differ
diff --git a/InscryptionAPI/Assets/BaseGameDecals/decal_snelk_1.png b/InscryptionAPI/Assets/BaseGameDecals/decal_snelk_1.png
new file mode 100644
index 00000000..6d5a76a0
Binary files /dev/null and b/InscryptionAPI/Assets/BaseGameDecals/decal_snelk_1.png differ
diff --git a/InscryptionAPI/Assets/BaseGameDecals/decal_snelk_2.png b/InscryptionAPI/Assets/BaseGameDecals/decal_snelk_2.png
new file mode 100644
index 00000000..ff65c2cf
Binary files /dev/null and b/InscryptionAPI/Assets/BaseGameDecals/decal_snelk_2.png differ
diff --git a/InscryptionAPI/Assets/BaseGameDecals/decal_snelk_3.png b/InscryptionAPI/Assets/BaseGameDecals/decal_snelk_3.png
new file mode 100644
index 00000000..86b02813
Binary files /dev/null and b/InscryptionAPI/Assets/BaseGameDecals/decal_snelk_3.png differ
diff --git a/InscryptionAPI/Assets/BaseGameDecals/decal_snelk_4.png b/InscryptionAPI/Assets/BaseGameDecals/decal_snelk_4.png
new file mode 100644
index 00000000..f424a824
Binary files /dev/null and b/InscryptionAPI/Assets/BaseGameDecals/decal_snelk_4.png differ
diff --git a/InscryptionAPI/Assets/BaseGameDecals/decal_snelk_5.png b/InscryptionAPI/Assets/BaseGameDecals/decal_snelk_5.png
new file mode 100644
index 00000000..93c2b621
Binary files /dev/null and b/InscryptionAPI/Assets/BaseGameDecals/decal_snelk_5.png differ
diff --git a/InscryptionAPI/Assets/BaseGameDecals/decal_snelk_6.png b/InscryptionAPI/Assets/BaseGameDecals/decal_snelk_6.png
new file mode 100644
index 00000000..6a04dede
Binary files /dev/null and b/InscryptionAPI/Assets/BaseGameDecals/decal_snelk_6.png differ
diff --git a/InscryptionAPI/Assets/BaseGameDecals/decal_snelk_main.png b/InscryptionAPI/Assets/BaseGameDecals/decal_snelk_main.png
new file mode 100644
index 00000000..eceba729
Binary files /dev/null and b/InscryptionAPI/Assets/BaseGameDecals/decal_snelk_main.png differ
diff --git a/InscryptionAPI/Assets/BaseGameDecals/decal_stitches.png b/InscryptionAPI/Assets/BaseGameDecals/decal_stitches.png
new file mode 100644
index 00000000..4127675d
Binary files /dev/null and b/InscryptionAPI/Assets/BaseGameDecals/decal_stitches.png differ
diff --git a/InscryptionAPI/Card/CardExtensions.cs b/InscryptionAPI/Card/CardExtensions.cs
index bdbcf3f5..dd8dcebf 100644
--- a/InscryptionAPI/Card/CardExtensions.cs
+++ b/InscryptionAPI/Card/CardExtensions.cs
@@ -412,4 +412,5 @@ public static CardInfo RemoveCardMetaCategories(this CardInfo info, params CardM
public static bool ModPrefixIs(this CardInfo info, string prefixToMatch) => info.GetExtendedProperty("ModPrefix") == prefixToMatch;
#endregion
+
}
diff --git a/InscryptionAPI/Card/CardExtensionsCosts.cs b/InscryptionAPI/Card/CardExtensionsCosts.cs
index 3e452018..36ea9330 100644
--- a/InscryptionAPI/Card/CardExtensionsCosts.cs
+++ b/InscryptionAPI/Card/CardExtensionsCosts.cs
@@ -31,7 +31,7 @@ public static PlayableCard GetPlayableCard(this CardInfo cardInfo)
///
public static int BloodCost(this PlayableCard card)
{
- //Debug.Log($"{card != null} {card?.Info != null} [{card?.GetType()}] {(card as DiskCardGame.Card)?.Info != null}");
+ //InscryptionAPIPlugin.Logger.LogInfo($"{card != null} {card?.Info != null} [{card?.GetType()}] {(card as DiskCardGame.Card)?.Info != null}");
if (card != null && card.Info != null)
{
int originalBloodCost = CostProperties.CostProperties.OriginalBloodCost(card.Info);
@@ -42,6 +42,7 @@ public static int BloodCost(this PlayableCard card)
foreach (CardModificationInfo mod in card.TemporaryMods)
originalBloodCost += mod.bloodCostAdjustment;
+ //InscryptionAPIPlugin.Logger.LogInfo(originalBloodCost);
return originalBloodCost;
}
@@ -105,11 +106,21 @@ public static List GemsCost(this PlayableCard card)
return gemsCost;
}
+ ///
+ /// Checks if the given PlayableCard is gemified in either its CardInfo or TemporaryMods.
+ ///
+ /// True if the PlayableCard is gemified.
public static bool IsGemified(this PlayableCard card) => card.Info.Gemified || card.TemporaryMods.Exists((CardModificationInfo x) => x.gemify);
+ ///
+ /// Determines if the given PlayableCard's owner possesses a blue gem. Works for the opponent and player.
+ ///
public static bool OwnerHasBlueGem(this PlayableCard card)
{
return card.OpponentCard ? OpponentGemsManager.Instance.HasGem(GemType.Blue) : ResourcesManager.Instance.HasGem(GemType.Blue);
}
+ ///
+ /// Whether or not the given PlayableCard is affected by a blue gem and should have its cost reduced.
+ ///
public static bool IsUsingBlueGem(this PlayableCard card) => card.IsGemified() && card.OwnerHasBlueGem();
///
diff --git a/InscryptionAPI/Card/CardManager.cs b/InscryptionAPI/Card/CardManager.cs
index b4de2a81..cad99a63 100644
--- a/InscryptionAPI/Card/CardManager.cs
+++ b/InscryptionAPI/Card/CardManager.cs
@@ -13,6 +13,9 @@
namespace InscryptionAPI.Card;
+///
+/// Class for managing adding, retrieving, tracking custom cards added via the API.
+///
[HarmonyPatch]
public static class CardManager
{
@@ -21,14 +24,50 @@ private class CardExt // Needs to be defined first so the implicit static constr
public readonly Dictionary TypeMap = new();
public readonly Dictionary StringMap = new();
}
+ ///
+ /// Class for storing the data for custom portrait Sprites added via the API.
+ ///
+ ///
+ /// Only tracks custom API portraits like sacrificable steel trap, etc.
+ ///
public class CardAltPortraits
{
+ ///
+ /// Portrait sprite used when calling GetAlternatePortrait in Act 2.
+ ///
public Sprite PixelAlternatePortrait = null;
+ ///
+ /// Portrait sprite used when the Steel Trap sigil is triggered.
+ ///
+ ///
+ /// Example: Leaping Trap
+ ///
public Sprite SteelTrapPortrait = null;
+ ///
+ /// Portrait sprite used when the Steel Trap sigil is triggered in Act 2.
+ ///
public Sprite PixelSteelTrapPortrait = null;
+ ///
+ /// Portrait sprite used when a card's shield breaks.
+ ///
+ ///
+ /// Example: Mud Turtle
+ ///
public Sprite BrokenShieldPortrait = null;
+ ///
+ /// Portrait sprite used when a card's shield breaks in Act 2.
+ ///
public Sprite PixelBrokenShieldPortrait = null;
+ ///
+ /// Portrait sprite used when a card on the board can be chosen as a sacrifice.
+ ///
+ ///
+ /// Example: Squirrel
+ ///
public Sprite SacrificablePortrait = null;
+ ///
+ /// Portrait sprite used when a card on the board can be chosen as a sacrifice in Act 2.
+ ///
public Sprite PixelSacrificablePortrait = null;
}
private static readonly ConditionalWeakTable CardExtensionProperties = new();
@@ -55,14 +94,16 @@ private static IEnumerable GetBaseGameCards()
foreach (CardInfo card in Resources.LoadAll("Data/Cards"))
{
card.SetBaseGameCard(true);
- if (card.name == "Squirrel" || card.name == "AquaSquirrel" || card.name == "Rabbit")
+ if (card.name == "Squirrel" || card.name == "AquaSquirrel" || card.name == "Rabbit") {
card.SetAffectedByTidalLock();
- else if (card.name == "SkeletonParrot")
+ }
+ else if (card.name == "SkeletonParrot") {
card.AddTribes(Tribe.Bird);
- else if (card.name == "MudTurtle")
+ }
+ else if (card.name == "MudTurtle") {
card.SetBrokenShieldPortrait(card.alternatePortrait);
-
- yield return card;
+ }
+ yield return card;
}
}
@@ -200,7 +241,6 @@ static CardManager()
///
/// A copy of all cards in the card pool.
///
- /// .
public static List AllCardsCopy { get; private set; } = BaseGameCards.ToList();
///
@@ -292,47 +332,130 @@ public static CardInfo New(string modPrefix, string name, string displayName, in
}
}
+ ///
+ /// Retrieves the dictionary of card extended properties associated with the given CardInfo.
+ ///
+ /// The CardInfo whose extended properties we wish to retrieve.
+ /// The extension property dictionary for the given CardInfo. Creates and returns an empty dictionary if none exists.
public static Dictionary GetCardExtensionTable(this CardInfo card) => CardExtensionProperties.GetOrCreateValue(card).StringMap;
internal static CardAltPortraits GetAltPortraits(this CardInfo card) => CardAlternatePortraits.GetOrCreateValue(card);
+ ///
+ /// Retrieves the Sprite for the CardInfo's alternate portrait in Act 2 if it exists.
+ ///
+ /// The CardInfo whose portrait we're retrieving.
+ /// The Sprite for the pixel alternate portrait or null if it doesn't exist.
+ ///
+ /// Pixel alternate portraits are added through the API; they are not a vanilla feature.
+ ///
public static Sprite PixelAlternatePortrait(this CardInfo card)
{
return card.GetAltPortraits().PixelAlternatePortrait;
}
+ ///
+ /// Retrieves the Sprite for the CardInfo's portrait used when Steel Trap activates if it exists.
+ ///
+ /// The CardInfo whose portrait we're retrieving.
+ /// The Sprite for the Steel Trap portrait or null if it doesn't exist.
+ ///
+ /// Steel Trap portraits are added through the API; they are not a vanilla feature.
+ ///
public static Sprite SteelTrapPortrait(this CardInfo card)
{
return card.GetAltPortraits().SteelTrapPortrait;
}
+ ///
+ /// Retrieves the Sprite for the CardInfo's portrait emission used when Steel Trap activates if it exists.
+ ///
+ /// The CardInfo whose portrait we're retrieving.
+ /// The Sprite for the Steel Trap portrait emission or null if it doesn't exist.
+ ///
+ /// Steel Trap portraits are added through the API; they are not a vanilla feature.
+ ///
public static Sprite EmissiveSteelTrapPortrait(this CardInfo card)
{
return card.GetAltPortraits().SteelTrapPortrait.GetEmissionSprite();
}
+ ///
+ /// Retrieves the Sprite for the CardInfo's Act 2 portrait used when Steel Trap activates if it exists.
+ ///
+ /// The CardInfo whose portrait we're retrieving.
+ /// The Sprite for the pixel Steel Trap portrait or null if it doesn't exist.
+ ///
+ /// Pixel Steel Trap portraits are added through the API; they are not a vanilla feature.
+ ///
public static Sprite PixelSteelTrapPortrait(this CardInfo card)
{
return card.GetAltPortraits().PixelSteelTrapPortrait;
}
-
+ ///
+ /// Retrieves the Sprite for the CardInfo's portrait used when a card's shield breaks if it exists.
+ ///
+ /// The CardInfo whose portrait we're retrieving.
+ /// The Sprite for the broken shield portrait or null if it doesn't exist.
+ ///
+ /// Broken shield portraits are added through the API; they are not a vanilla feature.
+ ///
public static Sprite BrokenShieldPortrait(this CardInfo card)
{
return card.GetAltPortraits().BrokenShieldPortrait;
}
+ ///
+ /// Retrieves the Sprite for the CardInfo's portrait emission used when a card's shield breaks if it exists.
+ ///
+ /// The CardInfo whose portrait we're retrieving.
+ /// The Sprite for the broken shield portrait emission or null if it doesn't exist.
+ ///
+ /// Broken shield portraits are added through the API; they are not a vanilla feature.
+ ///
public static Sprite EmissiveBrokenShieldPortrait(this CardInfo card)
{
return card.GetAltPortraits().BrokenShieldPortrait.GetEmissionSprite();
}
+ ///
+ /// Retrieves the Sprite for the CardInfo's Act 2 portrait used when a card's shield breaks if it exists.
+ ///
+ /// The CardInfo whose portrait we're retrieving.
+ /// The Sprite for the pixel broken shield portrait or null if it doesn't exist.
+ ///
+ /// Pixel broken shield portraits are added through the API; they are not a vanilla feature.
+ ///
public static Sprite PixelBrokenShieldPortrait(this CardInfo card)
{
return card.GetAltPortraits().PixelBrokenShieldPortrait;
}
-
+ ///
+ /// Retrieves the Sprite for the CardInfo's portrait used when a card on the board can be sacrificed if it exists.
+ ///
+ /// The CardInfo whose portrait we're retrieving.
+ /// The Sprite for the sacrificable portrait or null if it doesn't exist.
+ ///
+ /// Sacrificable portraits are added through the API; they are not a vanilla feature.
+ ///
public static Sprite SacrificablePortrait(this CardInfo card)
{
return card.GetAltPortraits().SacrificablePortrait;
}
+ ///
+ /// Retrieves the Sprite for the CardInfo's portrait emission used when a card on the board can be sacrificed if it exists.
+ ///
+ /// The CardInfo whose portrait we're retrieving.
+ /// The Sprite for the sacrificable portrait emission or null if it doesn't exist.
+ ///
+ /// Sacrificable portraits are added through the API; they are not a vanilla feature.
+ ///
public static Sprite EmissiveSacrificablePortrait(this CardInfo card)
{
return card.GetAltPortraits().SacrificablePortrait.GetEmissionSprite();
}
+ ///
+ /// Retrieves the Sprite for the CardInfo's Act 2 portrait used when a card on the board can be sacrificed if it exists.
+ ///
+ /// The CardInfo whose portrait we're retrieving.
+ /// The Sprite for the pixel sacrificable portrait or null if it doesn't exist.
+ ///
+ /// Pixel sacrificable portraits are added through the API; they are not a vanilla feature.
+ ///
public static Sprite PixelSacrificablePortrait(this CardInfo card)
{
return card.GetAltPortraits().PixelSacrificablePortrait;
diff --git a/InscryptionAPI/Card/CardModificationInfoManager.cs b/InscryptionAPI/Card/CardModificationInfoManager.cs
index 765adb38..abcf0641 100644
--- a/InscryptionAPI/Card/CardModificationInfoManager.cs
+++ b/InscryptionAPI/Card/CardModificationInfoManager.cs
@@ -6,6 +6,10 @@
namespace InscryptionAPI.Card;
+///
+/// Class for managing special CardModificationInfos.
+/// These include persistent extended properties and custom costs.
+///
[HarmonyPatch]
public static class CardModificationInfoManager
{
@@ -69,6 +73,9 @@ internal static Dictionary GetCardModExtensionTable(this CardMod
return exp.StringMap;
}
+ ///
+ /// Re-executes events and rebuilds the special CardModificationInfo pool.
+ ///
public static void SyncCardMods()
{
// Re-add persistent properties
diff --git a/InscryptionAPI/Card/CostProperties.cs b/InscryptionAPI/Card/CostProperties.cs
index d6f2d662..877d85e4 100644
--- a/InscryptionAPI/Card/CostProperties.cs
+++ b/InscryptionAPI/Card/CostProperties.cs
@@ -131,18 +131,58 @@ public static List ImprovedGemsCost(CardInfo instance)
[HarmonyReversePatch, HarmonyPatch(typeof(CardInfo), nameof(CardInfo.EnergyCost), MethodType.Getter), MethodImpl(MethodImplOptions.NoInlining)]
public static int OriginalEnergyCost(CardInfo __instance) { return 0; }
+ ///
+ /// Determines whether or not Gemified should reduce the blood cost on a multicost card.
+ ///
+ /// The gemified PlayableCard we're checking.
+ /// The PlayableCard's blood cost. Defaults to using the CardInfo's blood cost if null.
+ /// True if Gemified should reduce the blood cost by 1.
+ ///
+ /// Used for multicost cards to determine which cost Gemified should affect.
+ /// Priority from first choice to last: Energy, Bones, Mox, Blood
+ ///
public static bool ReduceGemifiedBlood(PlayableCard card, int? bloodCost = null)
{
return (bloodCost ?? OriginalBloodCost(card.Info)) > 0 && !ReduceGemifiedEnergy(card) && !ReduceGemifiedBones(card) && !ReduceGemifiedMox(card);
}
+ ///
+ /// Determines whether or not Gemified should reduce the gems cost on a multicost card.
+ ///
+ /// The gemified PlayableCard we're checking.
+ /// The PlayableCard's gems cost. Defaults to using the CardInfo's gems cost if null.
+ /// True if Gemified should reduce the gems cost by 1.
+ ///
+ /// Used for multicost cards to determine which cost Gemified should affect.
+ /// Priority from first choice to last: Energy, Bones, Mox, Blood
+ ///
public static bool ReduceGemifiedMox(PlayableCard card, List gemsCost = null)
{
return (gemsCost?.Count ?? ImprovedGemsCost(card.Info).Count) > 0 && !ReduceGemifiedBones(card) && !ReduceGemifiedEnergy(card);
}
+ ///
+ /// Determines whether or not Gemified should reduce the bone cost on a multicost card.
+ ///
+ /// The gemified PlayableCard we're checking.
+ /// The PlayableCard's bone cost. Defaults to using the CardInfo's bone cost if null.
+ /// True if Gemified should reduce the bone cost by 1.
+ ///
+ /// Used for multicost cards to determine which cost Gemified should affect.
+ /// Priority from first choice to last: Energy, Bones, Mox, Blood
+ ///
public static bool ReduceGemifiedBones(PlayableCard card, int? bonesCost = null)
{
return (bonesCost ?? OriginalBonesCost(card.Info)) > 0 && !ReduceGemifiedEnergy(card);
}
+ ///
+ /// Determines whether or not Gemified should reduce the energy cost on a multicost card.
+ ///
+ /// The gemified PlayableCard we're checking.
+ /// The PlayableCard's energy cost. Defaults to using the CardInfo's energy cost if null.
+ /// True if Gemified should reduce the energy cost by 1.
+ ///
+ /// Used for multicost cards to determine which cost Gemified should affect.
+ /// Priority from first choice to last: Energy, Bones, Mox, Blood
+ ///
public static bool ReduceGemifiedEnergy(PlayableCard card, int? energyCost = null)
{
return (energyCost ?? OriginalEnergyCost(card.Info)) > 0;
@@ -153,7 +193,7 @@ public static bool ReduceGemifiedEnergy(PlayableCard card, int? energyCost = nul
internal static class ChangeCardCostGetter
{
[HarmonyPatch(typeof(CardInfo), nameof(CardInfo.BloodCost), MethodType.Getter), HarmonyPrefix]
- public static bool BloodCost(CardInfo __instance, ref int __result)
+ private static bool BloodCost(CardInfo __instance, ref int __result)
{
PlayableCard card = __instance.GetPlayableCard();
//Debug.Log($"{card != null}");
@@ -162,7 +202,7 @@ public static bool BloodCost(CardInfo __instance, ref int __result)
}
[HarmonyPatch(typeof(CardInfo), nameof(CardInfo.BonesCost), MethodType.Getter), HarmonyPrefix]
- public static bool BoneCost(CardInfo __instance, ref int __result)
+ private static bool BoneCost(CardInfo __instance, ref int __result)
{
PlayableCard card = __instance.GetPlayableCard();
if (card == null)
@@ -173,7 +213,7 @@ public static bool BoneCost(CardInfo __instance, ref int __result)
}
[HarmonyPatch(typeof(CardInfo), nameof(CardInfo.GemsCost), MethodType.Getter), HarmonyPrefix]
- public static bool GemsCost(CardInfo __instance, ref List __result)
+ private static bool GemsCost(CardInfo __instance, ref List __result)
{
PlayableCard card = __instance.GetPlayableCard();
__result = card?.GemsCost() ?? CostProperties.ImprovedGemsCost(__instance);
@@ -181,7 +221,7 @@ public static bool GemsCost(CardInfo __instance, ref List __result)
}
[HarmonyPatch(typeof(CardInfo), nameof(CardInfo.EnergyCost), MethodType.Getter), HarmonyPrefix]
- public static bool EnergyCost(CardInfo __instance, ref int __result)
+ private static bool EnergyCost(CardInfo __instance, ref int __result)
{
PlayableCard card = __instance.GetPlayableCard();
__result = card?.EnergyCost ?? CostProperties.OriginalEnergyCost(__instance);
@@ -189,7 +229,7 @@ public static bool EnergyCost(CardInfo __instance, ref int __result)
}
[HarmonyPatch(typeof(PlayableCard), nameof(PlayableCard.EnergyCost), MethodType.Getter), HarmonyPrefix]
- public static bool DisableVanillaEnergyCost(PlayableCard __instance, ref int __result)
+ private static bool DisableVanillaEnergyCost(PlayableCard __instance, ref int __result)
{
// patch this to follow the same pattern as the other cost methods
int energyCost = CostProperties.OriginalEnergyCost(__instance.Info);
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/Card/OpponentGemsPatches.cs b/InscryptionAPI/Card/OpponentGemsPatches.cs
index c20af144..a65a3117 100644
--- a/InscryptionAPI/Card/OpponentGemsPatches.cs
+++ b/InscryptionAPI/Card/OpponentGemsPatches.cs
@@ -39,30 +39,34 @@ private static IEnumerator UpdateGemsOnHookGrab(IEnumerator enumerator)
private static IEnumerator GainGemsForOpponents(IEnumerator enumerator, GainGem __instance)
{
yield return enumerator;
- if (__instance.Card.OpponentCard && Singleton.Instance != null)
- Singleton.Instance.AddGem(__instance.Gem);
+ if (__instance != null && __instance.Card != null)
+ if (__instance.Card.OpponentCard && Singleton.Instance != null)
+ Singleton.Instance.AddGem(__instance.Gem);
}
[HarmonyPostfix, HarmonyPatch(typeof(GainGem), nameof(GainGem.OnDie))]
private static IEnumerator LoseGemsForOpponents(IEnumerator enumerator, GainGem __instance)
{
yield return enumerator;
- if (__instance.Card.OpponentCard && Singleton.Instance != null)
- Singleton.Instance.LoseGem(__instance.Gem);
+ if (__instance != null && __instance.Card != null)
+ if (__instance.Card.OpponentCard && Singleton.Instance != null)
+ Singleton.Instance.LoseGem(__instance.Gem);
}
[HarmonyPostfix, HarmonyPatch(typeof(GainGemTriple), nameof(GainGemTriple.OnResolveOnBoard))]
private static IEnumerator GainTripleGemsForOpponents(IEnumerator enumerator, GainGemTriple __instance)
{
yield return enumerator;
- if (__instance.Card.OpponentCard && Singleton.Instance)
- Singleton.Instance.AddGems(GemType.Green, GemType.Orange, GemType.Blue);
+ if (__instance != null && __instance.Card != null)
+ if (__instance.Card.OpponentCard && Singleton.Instance)
+ Singleton.Instance.AddGems(GemType.Green, GemType.Orange, GemType.Blue);
}
[HarmonyPostfix, HarmonyPatch(typeof(GainGemTriple), nameof(GainGemTriple.OnDie))]
private static IEnumerator LoseTripleGemsForOpponents(IEnumerator enumerator, GainGemTriple __instance)
{
yield return enumerator;
- if (__instance.Card.OpponentCard && Singleton.Instance != null)
- Singleton.Instance.LoseGems(GemType.Green, GemType.Orange, GemType.Blue);
+ if (__instance != null && __instance.Card != null)
+ if (__instance.Card.OpponentCard && Singleton.Instance != null)
+ Singleton.Instance.LoseGems(GemType.Green, GemType.Orange, GemType.Blue);
}
[HarmonyTranspiler, HarmonyPatch(typeof(DiskRenderStatsLayer), nameof(DiskRenderStatsLayer.RenderCard))]
diff --git a/InscryptionAPI/Card/Patches/PatchGenerateTradeCardsWithCostTierWithOptionalDebugLogging.cs b/InscryptionAPI/Card/Patches/PatchGenerateTradeCardsWithCostTierWithOptionalDebugLogging.cs
new file mode 100644
index 00000000..c26a2734
--- /dev/null
+++ b/InscryptionAPI/Card/Patches/PatchGenerateTradeCardsWithCostTierWithOptionalDebugLogging.cs
@@ -0,0 +1,206 @@
+using DiskCardGame;
+using HarmonyLib;
+using InscryptionAPI.Guid;
+using UnityEngine;
+
+namespace InscryptionAPI.Card.Patches;
+
+///
+/// A Patch in which injects Loggers and Validation Check Logging into 'GenerateTradeCardsWithCostTier' before it runs to try and debug errors related to it.
+///
+[HarmonyPatch(typeof(TradeCardsForPelts), "GenerateTradeCardsWithCostTier")]
+internal static class PatchGenerateTradeCardsWithCostTierWithOptionalDebugLogging
+{
+ ///
+ /// Makes our system Log 'GenerateTradeCardsWithCostTier' related issues.
+ ///
+ /// The Number Of Cards to Generate.
+ /// The Tier of Cards that should be Generated.
+ /// The RandomSeed associated with the Generation.
+ [HarmonyPrefix]
+ private static void Prefix(int numCards, int tier, int randomSeed)
+ {
+ try
+ {
+ LogGenerateTradeCardsWithCostTierState(numCards, tier, randomSeed);
+ }
+ catch (Exception ex)
+ {
+ if (InscryptionAPI.InscryptionAPIPlugin.configEnableTraderCostTierBugDebugLogging.Value)
+ {
+ InscryptionAPI.InscryptionAPIPlugin.Logger.LogError($"[TradeCardsForPelts Debug] Prefix logging failed. " + $"The original GenerateTradeCardsWithCostTier method will still run. " + $"Exception: {ex}");
+ }
+ }
+ }
+
+ ///
+ /// A function use to Log relevant info and checks for 'GenerateTradeCardsWithCostTier'.
+ ///
+ /// The Number Of Cards to Generate.
+ /// The Tier of Cards that should be Generated.
+ /// The RandomSeed associated with the Generation.
+ private static void LogGenerateTradeCardsWithCostTierState(int numCards, int requestedTier, int randomSeed)
+ {
+ bool flag = requestedTier > 0;
+ int effectiveTier = Mathf.Max(1, requestedTier);
+
+ if (InscryptionAPI.InscryptionAPIPlugin.configEnableTraderCostTierBugDebugLogging.Value)
+ {
+ InscryptionAPI.InscryptionAPIPlugin.Logger.LogDebug($"===== GenerateTradeCardsWithCostTier pre-run ===== " + $"numCards={numCards}, " + $"requestedTier={requestedTier}, " + $"effectiveTier={effectiveTier}, " + $"randomSeed={randomSeed}, " + $"flag={flag}");
+ }
+ List learnedCards = CardLoader.LearnedCards;
+
+ if (InscryptionAPI.InscryptionAPIPlugin.configEnableTraderCostTierBugDebugLogging.Value)
+ {
+ InscryptionAPI.InscryptionAPIPlugin.Logger.LogDebug($"[TradeCardsForPelts Debug] LearnedCards count before vanilla filtering: {learnedCards.Count}");
+ }
+ for (int index = 0; index < learnedCards.Count; index++)
+ {
+ CardInfo card = learnedCards[index];
+
+ if (card == null)
+ {
+ if (InscryptionAPI.InscryptionAPIPlugin.configEnableTraderCostTierBugDebugLogging.Value)
+ {
+ InscryptionAPI.InscryptionAPIPlugin.Logger.LogError($"[TradeCardsForPelts Debug] NULL CardInfo in CardLoader.LearnedCards " + $"at index={index}.");
+ }
+ continue;
+ }
+
+ CardTemple temple;
+ int costTier;
+
+ try
+ {
+ temple = card.temple;
+ costTier = card.CostTier;
+ }
+ catch (Exception ex)
+ {
+ if (InscryptionAPI.InscryptionAPIPlugin.configEnableTraderCostTierBugDebugLogging.Value)
+ {
+ InscryptionAPI.InscryptionAPIPlugin.Logger.LogError($"[TradeCardsForPelts Debug] Failed while evaluating vanilla outer predicate | " + $"index={index} | " + $"card={GetCardName(card)} | " + $"exception={ex}");
+ }
+ continue;
+ }
+
+ if (temple != CardTemple.Nature || costTier != effectiveTier)
+ continue;
+
+ if (InscryptionAPI.InscryptionAPIPlugin.configEnableTraderCostTierBugDebugLogging.Value)
+ {
+ InscryptionAPI.InscryptionAPIPlugin.Logger.LogDebug($"[TradeCardsForPelts Debug] Vanilla ability-filter candidate | " + $"index={index} | " + $"card={GetCardName(card)} | " + $"temple={temple} | " + $"costTier={costTier} | " + $"baseAbilities=[{FormatAbilities(card.abilities)}] | " + $"mods={card.mods?.Count ?? 0}");
+ }
+ List effectiveAbilities;
+
+ try
+ {
+ effectiveAbilities = card.Abilities;
+ }
+ catch (Exception ex)
+ {
+ if (InscryptionAPI.InscryptionAPIPlugin.configEnableTraderCostTierBugDebugLogging.Value)
+ {
+ InscryptionAPI.InscryptionAPIPlugin.Logger.LogError($"[TradeCardsForPelts Debug] card.Abilities threw while evaluating the " + $"same property vanilla will use | " + $"index={index} | " + $"card={GetCardName(card)} | " + $"exception={ex}");
+ }
+ continue;
+ }
+
+ if (effectiveAbilities == null)
+ {
+ if (InscryptionAPI.InscryptionAPIPlugin.configEnableTraderCostTierBugDebugLogging.Value)
+ {
+ InscryptionAPI.InscryptionAPIPlugin.Logger.LogError($"[TradeCardsForPelts Debug] NULL effective CardInfo.Abilities list | " + $"index={index} | " + $"card={GetCardName(card)} | " + $"tier={effectiveTier} | " + $"mods={card.mods?.Count ?? 0}");
+ }
+ continue;
+ }
+ if (InscryptionAPI.InscryptionAPIPlugin.configEnableTraderCostTierBugDebugLogging.Value)
+ {
+ InscryptionAPI.InscryptionAPIPlugin.Logger.LogDebug($"[TradeCardsForPelts Debug] Effective abilities | " + $"index={index} | " + $"card={GetCardName(card)} | " + $"abilities=[{FormatAbilities(effectiveAbilities)}]");
+ }
+ for (int abilityIndex = 0; abilityIndex < effectiveAbilities.Count; abilityIndex++)
+ {
+ Ability ability = effectiveAbilities[abilityIndex];
+ string abilityName = GetGuidAndKey(ability);
+
+ AbilityInfo abilityInfo;
+
+ try
+ {
+ abilityInfo = AbilitiesUtil.GetInfo(ability);
+ }
+ catch (Exception ex)
+ {
+ if (InscryptionAPI.InscryptionAPIPlugin.configEnableTraderCostTierBugDebugLogging.Value)
+ {
+ InscryptionAPI.InscryptionAPIPlugin.Logger.LogError($"[TradeCardsForPelts Debug] AbilitiesUtil.GetInfo threw | " + $"card={GetCardName(card)} | " + $"tier={effectiveTier} | " + $"abilityIndex={abilityIndex} | " + $"ability={abilityName} | " + $"rawValue={(int)ability} | " + $"exception={ex}");
+ }
+ continue;
+ }
+
+ if (abilityInfo == null)
+ {
+ if (InscryptionAPI.InscryptionAPIPlugin.configEnableTraderCostTierBugDebugLogging.Value)
+ {
+ InscryptionAPI.InscryptionAPIPlugin.Logger.LogError($"[TradeCardsForPelts Debug] VANILLA NRE CANDIDATE: " + $"AbilitiesUtil.GetInfo returned null | " + $"card={GetCardName(card)} | " + $"tier={effectiveTier} | " + $"abilityIndex={abilityIndex} | " + $"ability={abilityName} | " + $"rawValue={(int)ability} | " + $"baseAbilities=[{FormatAbilities(card.abilities)}] | " + $"effectiveAbilities=[{FormatAbilities(effectiveAbilities)}] | " + $"mods={card.mods?.Count ?? 0} | " + $"vanillaExpression=!AbilitiesUtil.GetInfo(a).opponentUsable");
+ }
+ continue;
+ }
+
+ if (InscryptionAPI.InscryptionAPIPlugin.configEnableTraderCostTierBugDebugLogging.Value)
+ {
+ InscryptionAPI.InscryptionAPIPlugin.Logger.LogDebug($"[TradeCardsForPelts Debug] Ability lookup OK | " + $"card={GetCardName(card)} | " + $"tier={effectiveTier} | " +
+ $"abilityIndex={abilityIndex} | " + $"ability={abilityName} | " + $"rawValue={(int)ability} | " + $"opponentUsable={abilityInfo.opponentUsable}");
+ }
+ }
+ }
+ if (InscryptionAPI.InscryptionAPIPlugin.configEnableTraderCostTierBugDebugLogging.Value)
+ {
+ InscryptionAPI.InscryptionAPIPlugin.Logger.LogDebug("===== End GenerateTradeCardsWithCostTier pre-run =====");
+ }
+ }
+
+ ///
+ /// Formats the Passed Abilities as a String.
+ ///
+ /// The Abilities to cast into the String.
+ /// A Formatted Abilities String.
+ private static string FormatAbilities(IEnumerable abilities)
+ {
+ if (abilities == null)
+ return "null";
+
+ return string.Join(", ", abilities.Select(GetGuidAndKey));
+ }
+
+ ///
+ /// Gets a GUID and Key associated with a Ability from the passed in Ability Value.
+ ///
+ /// The Ability we want to get the String Name of.
+ /// A String representing the Ability either via the GUID system or the Enum System.
+ private static string GetGuidAndKey(Ability ability)
+ {
+ if (GuidManager.TryGetGuidAndKeyEnumValue(ability, out string guid, out string key))
+ return $"{guid}_{key}";
+
+ return ability.ToString();
+ }
+
+ ///
+ /// Gets the Card Name and DisplayName of the passed in Card.
+ ///
+ /// The Card to get the Name of.
+ /// A string of the Card's Name and DisplayName.
+ private static string GetCardName(CardInfo card)
+ {
+ if (card == null)
+ return "null";
+
+ string internalName = string.IsNullOrEmpty(card.name) ? "null" : card.name;
+ string displayedName = string.IsNullOrEmpty(card.DisplayedNameEnglish)
+ ? "null"
+ : card.DisplayedNameEnglish;
+
+ return $"{internalName} ({displayedName})";
+ }
+}
\ No newline at end of file
diff --git a/InscryptionAPI/Card/Patches/SteelTrapDeathPatch.cs b/InscryptionAPI/Card/Patches/SteelTrapDeathPatch.cs
index db541bb5..0bdb1f1f 100644
--- a/InscryptionAPI/Card/Patches/SteelTrapDeathPatch.cs
+++ b/InscryptionAPI/Card/Patches/SteelTrapDeathPatch.cs
@@ -5,7 +5,7 @@
using MonoMod.Cil;
using UnityEngine;
-namespace InscryptionAPI.Card;
+namespace InscryptionAPI.Card.Patches;
///
/// Patches the Steal Trap Death system to drop a differed pelt on the case the opposing card has the "SteelTrapPelt" extended property.
diff --git a/InscryptionAPI/Costs/CardCostManager.cs b/InscryptionAPI/Costs/CardCostManager.cs
index 7af707a3..901ccf4b 100644
--- a/InscryptionAPI/Costs/CardCostManager.cs
+++ b/InscryptionAPI/Costs/CardCostManager.cs
@@ -2,8 +2,10 @@
using GBC;
using HarmonyLib;
using InscryptionAPI.Card;
+using InscryptionAPI.Card.CostProperties;
using InscryptionAPI.Dialogue;
using InscryptionAPI.Guid;
+using InscryptionAPI.Helpers;
using Sirenix.Utilities;
using System.Collections;
using System.Collections.ObjectModel;
@@ -13,6 +15,9 @@
namespace InscryptionAPI.CardCosts;
+///
+/// Class for managing custom card costs.
+///
[HarmonyPatch]
public static class CardCostManager
{
@@ -91,6 +96,11 @@ public class FullCardCost
///
public Func GetRewardBackTexture = null;
+ ///
+ /// Texture used if this card can show up in a card cost choice node.
+ ///
+ ///
+ ///
public Texture RewardBackTexture(int amount)
{
if (GetRewardBackTexture == null)
@@ -183,6 +193,10 @@ public FullCardCost(string modGUID, string costName, Type costBehaviour,
TypeManager.Add(costName, costBehaviour);
}
+ ///
+ /// Creates a deep clone of this FullCardCost.
+ ///
+ /// A new clone of this FullCardCost.
public FullCardCost Clone()
{
FullCardCost retval = new(
@@ -202,18 +216,29 @@ static CardCostManager()
SyncCustomCostList();
};
}
-
+ ///
+ /// A list of all card costs registered with the API.
+ ///
public static List AllCustomCosts { get; private set; } = new();
internal readonly static ObservableCollection NewCosts = new();
+ ///
+ /// This event runs every time the card card list is resynced. By adding listeners to this event, you can modify card costs that have been added to the list after your mod was loaded.
+ ///
public static event Func, List> ModifyCustomCostList;
// you don't have the [colour] gem for that.
// no [colour] gem on the table? then you can't play it.
// you need at least one [colour] gem on the board in order to play that [card]
// play the required [colour] gem... then you can play that.
+ ///
+ /// The Hint used to tell the player when they cannot play a card that costs multiple gems of the same colour.
+ ///
public static HintsHandler.Hint notEnoughSameColourGemsHint = new("Hint_NotEnoughSameColourGemsHint", 2);
+ ///
+ /// The DialogueEvent that is played when a player cannot play a card that costs multiple gems of the same colour.
+ ///
public static DialogueEvent notEnoghSameColourGemsEvent = DialogueManager.GenerateEvent(
InscryptionAPIPlugin.ModGUID, "Hint_NotEnoughSameColourGemsHint",
new() { "You don't have enough [v:1] gems for that." },
@@ -223,16 +248,37 @@ static CardCostManager()
new() { "You need more [v:1] gems on the board in order to play that [v:0]."},
new() { "Play the required [v:1] gems... then you can play that." }
});
+ ///
+ /// Re-executes events and rebuilds the card cost pool.
+ ///
public static void SyncCustomCostList()
{
AllCustomCosts = NewCosts.Select(a => a.Clone()).ToList();
AllCustomCosts = ModifyCustomCostList?.Invoke(AllCustomCosts) ?? AllCustomCosts;
}
+ ///
+ /// Retrieves the FullCardCost object associated with the given CustomCardCost class Type.
+ ///
+ /// Collection of FullCardCost objects to search through.
+ /// Type of the CustomCardCost to find the FUllCardCost object of.
+ /// The FullCardCost associated with the given Type, or null if it cannot be found.
+ ///
+ /// Intended to be used with the AllCustomCosts getter as a way of searching through all card costs added by the API.
+ ///
public static FullCardCost CostByBehaviour(this IEnumerable customCosts, Type costBehaviour)
{
return customCosts.FirstOrDefault(x => x.CostBehaviour == costBehaviour);
}
+ ///
+ /// Registers a new custom card cost with the API.
+ ///
+ /// The GUID of the mod adding this card cost.
+ /// The internal name of this card cost.
+ /// The type of the CustomCardCost class for this card cost.
+ /// The function used to determine what texture to display on cards with this cost.
+ /// The function used to determine what pixel texture to display on cards with this cost.
+ /// The FullCardCost object containing the new custom card cost's data.
public static FullCardCost Register(string modGUID, string costName, Type costBehaviour,
Func getCostTexture, Func getPixelCostTexture)
{
@@ -518,7 +564,19 @@ private static bool MultipleSameColourMoxSupport(PlayableCard card)
private static IEnumerable FixDialogueSoftlock(IEnumerable instructions)
{
List codes = new(instructions);
- //codes.LogCodeInscryptions();
+ //codes.LogCodeInstructions();
+
+ // this part's for fixing blood cost nonsense I encountered when dealing with duplicate CardInfos
+ // it just changes the call from card.Info.BloodCost to card.BloodCost()
+ // and avoiding the janky dynamic cost find playablecard nonsenseseses
+ int bloodCostIdx = codes.FindIndex(x => x.opcode == OpCodes.Callvirt && x.operand.ToString() == "Int32 get_BloodCost()");
+ if (bloodCostIdx > 0) {
+ bloodCostIdx--;
+ codes.RemoveRange(bloodCostIdx, 4);
+ MethodInfo playableCardBloodCost = AccessTools.Method(typeof(CardExtensions), nameof(CardExtensions.BloodCost),
+ new Type[] { typeof(PlayableCard) });
+ codes.Insert(bloodCostIdx, new CodeInstruction(OpCodes.Callvirt, playableCardBloodCost));
+ }
int methodIndex = codes.FindIndex(x => x.opcode == OpCodes.Callvirt && x.operand.ToString() == "System.Collections.IEnumerator PlayCardOnSlot(DiskCardGame.PlayableCard, DiskCardGame.CardSlot)");
if (methodIndex > 0)
@@ -663,7 +721,7 @@ private static void GenerateCustomCostChoices(ref List __result, int
while (list.Count > 3)
list.RemoveAt(SeededRandom.Range(0, list.Count, randomSeed++));
- if (InscryptionAPIPlugin.configRandomChoiceOrder.Value)
+ if (InscryptionAPIPlugin.configRandomCostChoiceOrder.Value)
list = list.Randomize().ToList();
__result = list;
@@ -820,4 +878,4 @@ public virtual IEnumerator OnPlayed(int cardCost, PlayableCard playableCard)
{
yield break;
}
-}
\ No newline at end of file
+}
diff --git a/InscryptionAPI/Encounters/SpecialSequenceManager.cs b/InscryptionAPI/Encounters/SpecialSequenceManager.cs
index e1396663..a42ba506 100644
--- a/InscryptionAPI/Encounters/SpecialSequenceManager.cs
+++ b/InscryptionAPI/Encounters/SpecialSequenceManager.cs
@@ -11,7 +11,6 @@ public class FullSpecialSequencer
{
public readonly string Id;
- private Type _specialSequencer;
public Type SpecialSequencer { get; private set; }
public FullSpecialSequencer(string id, Type specialSequencer)
diff --git a/InscryptionAPI/Guid/CustomTypePatches.cs b/InscryptionAPI/Guid/CustomTypePatches.cs
index 8fb865f3..941bc97f 100644
--- a/InscryptionAPI/Guid/CustomTypePatches.cs
+++ b/InscryptionAPI/Guid/CustomTypePatches.cs
@@ -8,11 +8,22 @@
namespace InscryptionAPI.Guid;
+///
+/// This is the Manager for Custom Type's related to our GUID System.
+///
[HarmonyPatch]
public static class TypeManager
{
+ ///
+ /// This is an Internal Dictionary of Type Related Cache.
+ ///
private static readonly Dictionary TypeCache = new();
+ ///
+ /// Use this to add a custom type to the Cache, if another type is passed with the same key, the old value is overwritten.
+ ///
+ /// The Key associated with the Custom Type.
+ /// The Custom Type the Key should be associated with.
internal static void Add(string key, Type value)
{
if (TypeCache.ContainsKey(key))
@@ -26,6 +37,11 @@ internal static void Add(string key, Type value)
TypeCache.Add(key, value);
}
+ ///
+ /// Use this exclusively for replacing a Custom Type that is in the Cache.
+ ///
+ /// The Key you want to replace the Custom Type of.
+ /// The New Type acting as the Custom Type's replacement.
internal static void Replace(string key, Type value)
{
if (TypeCache.ContainsKey(key))
@@ -34,8 +50,16 @@ internal static void Replace(string key, Type value)
Add(key, value);
}
+ ///
+ /// This is a Internal Dictionary of ModId's passed in by other mods.
+ ///
private static readonly Dictionary ModIds = new();
+ ///
+ /// This is a function that gets the Mod ID of a Passed Assembly.
+ ///
+ /// The Assembly to get the Mod ID of.
+ /// The Mod ID of the requested Assembly.
private static string GetModIdFromAssembly(Assembly assembly)
{
if (ModIds.ContainsKey(assembly.FullName))
@@ -57,6 +81,11 @@ private static string GetModIdFromAssembly(Assembly assembly)
return default;
}
+ ///
+ /// Gets the Mod ID from an Assembly Calling the API.
+ ///
+ /// The Assembly Calling the API.
+ /// The Mod ID of the Assembly Calling the API.
public static string GetModIdFromCallstack(Assembly callingAssembly)
{
string cacheVal = GetModIdFromAssembly(callingAssembly);
@@ -74,11 +103,25 @@ public static string GetModIdFromCallstack(Assembly callingAssembly)
return default;
}
+ ///
+ /// Used to get the Original Type from a Namespace and a known Type Name.
+ ///
+ /// The Namespace associated with the Type.
+ /// The Type's Name.
+ /// The Type that was originally used by the given Namespace with that Type's Name.
+ /// If this is thrown The Patch was unsuccessful.
[HarmonyReversePatch(HarmonyReversePatchType.Original)]
[HarmonyPatch(typeof(CustomType), nameof(CustomType.GetType), new Type[] { typeof(string), typeof(string) })]
[MethodImpl(MethodImplOptions.NoInlining)]
public static Type OriginalGetType(string nameSpace, string typeName) { throw new NotImplementedException(); }
+ ///
+ /// This Patch implements our custom version of , for Getting our Custom Types.
+ ///
+ /// The Namespace associated with the Type.
+ /// The Type's Name.
+ /// The Return Value of the Type.
+ /// The Custom Type associated with the Namespace and given Name for the Type.
[HarmonyPatch(typeof(CustomType), nameof(CustomType.GetType), new Type[] { typeof(string), typeof(string) })]
[HarmonyPrefix]
private static bool GetCustomType(string nameSpace, string typeName, ref Type __result)
diff --git a/InscryptionAPI/Guid/GuidManager.cs b/InscryptionAPI/Guid/GuidManager.cs
index 199857ee..26053b65 100644
--- a/InscryptionAPI/Guid/GuidManager.cs
+++ b/InscryptionAPI/Guid/GuidManager.cs
@@ -2,21 +2,47 @@
namespace InscryptionAPI.Guid;
+///
+/// This class is the GUID Manager used throughout the API.
+///
public static class GuidManager
{
+ ///
+ /// Gets the fully qualified name of GUID_Value.
+ ///
+ /// The GUID or Identifier associated with the given Mod.
+ /// The Value being paired with the GUID.
+ /// The Fully Qualified name in the form of GUID_Value
public static string GetFullyQualifiedName(string guid, string value)
{
return $"{guid}_{value}";
}
+ ///
+ /// A mapper of Int to Type in the form of a Dictionary.
+ ///
private static readonly Dictionary reverseMapper = new();
+ ///
+ /// Serves as a Lock within
+ ///
private static readonly object lockObject = new object();
+ ///
+ /// The Start Index for our GUID's.
+ ///
public const int START_INDEX = 1000;
+ ///
+ /// The Maximum Data Value for the API after all Enum's have been passed.
+ ///
public const string MAX_DATA = "maximumStoredValueForEnum";
+ ///
+ /// Gets the Enum Type associated with a passed Integer.
+ ///
+ /// The Specific Number associated with the Type we are after from the .
+ /// The Type associated with the passed Number.
public static Type GetEnumType(int number)
{
reverseMapper.TryGetValue(number, out var res);
@@ -48,6 +74,11 @@ unsafe public static List GetValues() where T : unmanaged, System.Enum
return itemList;
}
+ ///
+ /// Gets the Enum Value with the passed GUID and Value.
+ ///
+ /// If successful returns the Enum Value
+ /// Thrown when our GUID system does not support the associated Type.
unsafe public static T GetEnumValue(string guid, string value) where T : unmanaged, System.Enum
{
if (sizeof(T) != sizeof(int))
@@ -75,6 +106,14 @@ unsafe public static T GetEnumValue(string guid, string value) where T : unma
return *(T*)&enumValue;
}
+ ///
+ /// Attempts to get the GUID and Key associated with an Enum Value's Name.
+ ///
+ /// The Value we want to get the GUID and Key from.
+ /// The GUID found to be associated with the Value.
+ /// The Key found to be associated with the Passed in Value.
+ /// The Type of the Enum.
+ /// If True the GUID and Key associated with the Value were found successfully and are valid for use.
public static bool TryGetGuidAndKeyEnumValue(T value, out string guid, out string key) where T : System.Enum
{
string prefix = $"{typeof(T).Name}";
diff --git a/InscryptionAPI/Helpers/AssetBundleHelper.cs b/InscryptionAPI/Helpers/AssetBundleHelper.cs
index 481daecd..b91a0ff2 100644
--- a/InscryptionAPI/Helpers/AssetBundleHelper.cs
+++ b/InscryptionAPI/Helpers/AssetBundleHelper.cs
@@ -2,8 +2,19 @@
namespace InscryptionAPI.Helpers;
+///
+/// A Helper Set related to the .
+///
public static class AssetBundleHelper
{
+ ///
+ /// A function that attempts to get a Prefab of Type T from the given .
+ ///
+ /// The we want to get a Prefab out of.
+ /// The Name of the specific Prefab we are after.
+ /// The Fetched Prefab from the , if it fails we return Default(T), e.g. the Null associated with the given Type.
+ /// The Type in which is associated with the Prefab itself.
+ /// False if we fail, true if we successfully returned a Prefab associated with Type T.
public static bool TryGet(AssetBundle bundle, string prefabName, out T prefab) where T : UnityObject
{
if (bundle == null)
@@ -13,11 +24,8 @@ public static bool TryGet(AssetBundle bundle, string prefabName, out T prefab
return false;
}
- // Get object from bundle
prefab = bundle.LoadAsset(prefabName);
-
- // Unload bundle but don't unload the assets
- bundle.Unload(false);
+ bundle.Unload(false); // Does not unload assets, just the Bundle.
if (prefab == null)
{
@@ -28,6 +36,14 @@ public static bool TryGet(AssetBundle bundle, string prefabName, out T prefab
return true;
}
+ ///
+ /// A function that attempts to get a Prefab of Type T from the given path to the .
+ ///
+ /// The path to the
+ /// The Name of the specific Prefab we are after.
+ /// The Fetched Prefab from the , if it fails we return Default(T), e.g. the Null associated with the given Type.
+ /// The Type in which is associated with the Prefab itself.
+ /// False if we fail, true if we successfully returned a Prefab associated with Type T.
public static bool TryGet(string pathToAssetBundle, string prefabName, out T prefab) where T : UnityObject
{
AssetBundle bundle = AssetBundle.LoadFromFile(pathToAssetBundle);
@@ -38,11 +54,8 @@ public static bool TryGet(string pathToAssetBundle, string prefabName, out T
return false;
}
- // Get object from bundle
prefab = bundle.LoadAsset(prefabName);
-
- // Unload bundle but don't unload the assets
- bundle.Unload(false);
+ bundle.Unload(false); // Does not unload assets, just the Bundle.
if (prefab == null)
{
@@ -53,6 +66,14 @@ public static bool TryGet(string pathToAssetBundle, string prefabName, out T
return true;
}
+ ///
+ /// A function that attempts to get a Prefab of Type T from the given Memory associated with the .
+ ///
+ /// A array in the form of byte[] representing the Memory associated with a .
+ /// The Name of the specific Prefab we are after.
+ /// The Fetched Prefab from the , if it fails we return Default(T), e.g. the Null associated with the given Type.
+ /// The Type in which is associated with the Prefab itself.
+ /// False if we fail, true if we successfully returned a Prefab associated with Type T.
public static bool TryGet(byte[] resources, string prefabName, out T prefab) where T : UnityObject
{
AssetBundle bundle = AssetBundle.LoadFromMemory(resources);
@@ -63,11 +84,8 @@ public static bool TryGet(byte[] resources, string prefabName, out T prefab)
return false;
}
- // Get object from bundle
prefab = bundle.LoadAsset(prefabName);
-
- // Unload bundle but don't unload the assets
- bundle.Unload(false);
+ bundle.Unload(false); // Does not unload assets, just the Bundle.
if (prefab == null)
{
diff --git a/InscryptionAPI/Helpers/CustomFields.cs b/InscryptionAPI/Helpers/CustomFields.cs
index 4091247e..71ac90d5 100644
--- a/InscryptionAPI/Helpers/CustomFields.cs
+++ b/InscryptionAPI/Helpers/CustomFields.cs
@@ -3,11 +3,15 @@
namespace InscryptionAPI.Helpers;
///
-/// Allows for an easy way to add custom fields to an object, or to an entire class.
+/// A Helper Object for Custom Fields.
///
+/// Allows for an easy way to add custom fields to an object, or to an entire class.
public static class CustomFields
{
- static ConditionalWeakTable