NOTE: This is only for mod developers who want to add custom unlocks/add custom monster hunts/add new items to breach shops
Github repository, where you can look at SaveAPI's code and download it: https://github.com/SpecialAPI/SaveAPI
An API that allows easily saving data, adding custom unlocks to items, adding custom monster hunt quests and adding new items to breach shops.
To use this API, just
- Add it's files except files from Examples folder, SaveAPI.csproj and SaveAPI.sln, README.md, .gitignore and .gitattributes and everything from the Properties folder to your project.
- Call
SaveAPIManager.Setup("yourModPrefix")
in yourETGModule.Init()
method.
SaveAPI Guide
Various SaveAPI classes and enums
Spoiler!
CustomDungeonFlagsComparer
,CustomTrackedMaximumsComparer
andCustomTrackedStatsComparer
- they just exist.CustomCharacterSpecificGungeonFlags
- add new values to this enum to add new custom character-specific flags. Custom character-specific flags can be set usingSaveAPIManager.SetCharacterSpecificFlag(character, characterSpecificFlag, value)
and get usingSaveAPIManager.GetCharacterSpecificFlag(character, flag)
. Custom character-specific flags can have different values for different characters.CustomDungeonFlags
- add new values to this enum to add new custom flags. Custom flags can be set usingSaveAPIManager.SetFlag(flag, value)
and get usingSaveAPIManager.GetFlag(flag)
CustomTrackedMaximums
- add new values to this enum to add new custom tracked maximums. Tracked maximums can be set usingSaveAPIManager.UpdateMaximum(maximum, value)
(maximum will not be set if the value is less than maximum's current value) and get usingSaveAPIManager.GetPlayerMaximum(maximum)
.CustomTrackedStats
- add new values to this enum to add new custom tracked stats. Tracked stats can be set usingSaveAPIManager.SetStat(stat, value)
, get usingSaveAPIManager.GetPlayerStatValue(stat)
and incremented usingSaveAPIManager.RegisterStatChange(stat, value)
(if the value is negative it will decrement the stat).AdvancedGameStats
- stores session data like tracked maximums, stats and character-specific flags.AdvancedGameStatsManager
- stores data like flags and total session data.AdvancedMidGameSaveData
- stores custom midgame save data.BreachShopTool
- has methods that allow adding new items to breach shops. Also prevents breach shops from breaking when they have new items added to them.CustomDungeonPrerequisite
-DungeonPrerequisite
, but overridable. Also has some built-in custom prerequisite types.CustomHuntQuest
- stores custom hunt quest data.CustomHuntQuests
- has methods that allow adding new monster hunt quests. Also handles other stuff related to custom hunt quests.JammedEnemyState
- enum with 3 states of jammed enemies. Used mainly for custom hunt quests.SaveAPIManager
- core class of SaveAPI. Used to setup and unload SaveAPI and statically accessAdvancedGameStatsManager
's methods.SaveTools
- has tools and extensions that are used in SaveAPI code or that are just helpful methods when using SaveAPI.SpecialAIActor
- stores custom AIActor data like flag to set on death or flag to set on activation.SpecialPickupObject
- stores custom PickupObject data - flag to set on acquisition;
Adding custom unlocks to items
Spoiler!
SaveTools
has a lot of methods that can build and add unlocks to items:
item.SetupUnlockOnFlag(flag, requiredFlagValue)
- the item will be locked whenflag
's value isn'trequiredFlagValue
item.SetupUnlockOnStat(stat, comparisonValue, comparisonOperation)
- ifcomparisonOperation
isDungeonPrerequisite.PrerequisiteOperation.LESS_THAN
: the item is locked whenstat
's value is greater or equal tocomparisonValue
. IfcomparisonOperation
isDungeonPrerequisite.PrerequisiteOperation.EQUAL_TO
: the item is locked whenstat
's value isn't equal tocomparisonValue
. IfcomparisonOperation
isDungeonPrerequisite.PrerequisiteOperation.GREATER_THAN
: the item is locked whenstat
's value is less or equal tocomparisonValue
.item.SetupUnlockOnMaximum(maximum, comparisonValue, comparisonOperation)
- ifcomparisonOperation
isDungeonPrerequisite.PrerequisiteOperation.LESS_THAN
: the item is locked whenmaximum
's value is greater or equal tocomparisonValue
. IfcomparisonOperation
isDungeonPrerequisite.PrerequisiteOperation.EQUAL_TO
: the item is locked whenmaximum
's value isn't equal tocomparisonValue
. IfcomparisonOperation
isDungeonPrerequisite.PrerequisiteOperation.GREATER_THAN
: the item is locked whenmaximum
's value is less or equal tocomparisonValue
.item.SetupUnlockOnEncounter(encounterObjectGuid, requiredNumberOfEncounters, comparisonOperation)
- ifcomparisonOperation
isDungeonPrerequisite.PrerequisiteOperation.LESS_THAN
: the item is locked when EncounterTrackable with guid ofencounterObjectGuid
's number of encounters is greater or equal torequiredNumberOfEncounters
. IfcomparisonOperation
isDungeonPrerequisite.PrerequisiteOperation.EQUAL_TO
: the item is locked when EncounterTrackable with guid ofencounterObjectGuid
's number of encounters isn't equal torequiredNumberOfEncounters
. IfcomparisonOperation
isDungeonPrerequisite.PrerequisiteOperation.GREATER_THAN
: the item is locked when EncounterTrackable with guid ofencounterObjectGuid
's number of encounters is less or equal torequiredNumberOfEncounters
.item.SetupUnlockOnEncounter(encounterRoom, requiredNumberOfEncounters, comparisonOperation)
- ifcomparisonOperation
isDungeonPrerequisite.PrerequisiteOperation.LESS_THAN
: the item is locked whenencounterRoom
's number of encounters is greater or equal torequiredNumberOfEncounters
. IfcomparisonOperation
isDungeonPrerequisite.PrerequisiteOperation.EQUAL_TO
: the item is locked whenencounterRoom
's number of encounters isn't equal torequiredNumberOfEncounters
. IfcomparisonOperation
isDungeonPrerequisite.PrerequisiteOperation.GREATER_THAN
: the item is locked whenencounterRoom
's number of encounters is less or equal torequiredNumberOfEncounters
.item.SetupUnlockOnEncounterOrFlag(flag, requiredFlagValue, encounterObjectGuid, requiredNumberOfEncounters, comparisonOperation)
- ifcomparisonOperation
isDungeonPrerequisite.PrerequisiteOperation.LESS_THAN
: the item is locked when EncounterTrackable with guid ofencounterObjectGuid
's number of encounters is greater or equal torequiredNumberOfEncounters
andflag
's value isn'trequiredFlagValue
. IfcomparisonOperation
isDungeonPrerequisite.PrerequisiteOperation.EQUAL_TO
: the item is locked when EncounterTrackable with guid ofencounterObjectGuid
's number of encounters isn't equal torequiredNumberOfEncounters
andflag
's value isn'trequiredFlagValue
. IfcomparisonOperation
isDungeonPrerequisite.PrerequisiteOperation.GREATER_THAN
: the item is locked when EncounterTrackable with guid ofencounterObjectGuid
's number of encounters is less or equal torequiredNumberOfEncounters
andflag
's value isn'trequiredFlagValue
.item.SetupUnlockOnEncounterOrFlag(flag, requiredFlagValue, encounterRoom, requiredNumberOfEncounters, comparisonOperation)
- ifcomparisonOperation
isDungeonPrerequisite.PrerequisiteOperation.LESS_THAN
: the item is locked whenencounterRoom
's number of encounters is greater or equal torequiredNumberOfEncounters
andflag
's value isn'trequiredFlagValue
. IfcomparisonOperation
isDungeonPrerequisite.PrerequisiteOperation.EQUAL_TO
: the item is locked whenencounterRoom
's number of encounters isn't equal torequiredNumberOfEncounters
andflag
's value isn'trequiredFlagValue
. IfcomparisonOperation
isDungeonPrerequisite.PrerequisiteOperation.GREATER_THAN
: the item is locked whenencounterRoom
's number of encounters is less or equal torequiredNumberOfEncounters
andflag
's value isn'trequiredFlagValue
.item.SetupUnlockOnTileset(requiredTileset, requiredTilesetValue)
- ifrequiredTilesetValue
istrue
: the item will be locked when the current floor's tileset isn'trequiredTileset
. IfrequiredTilesetValue
isfalse
: the item will be locked when the current floor's tileset isrequiredTileset
.item.SetupUnlockOnCharacter(requiredCharacter, requiredCharacterValue)
- ifrequiredCharacterValue
istrue
: the item will be locked when the current character's identity isn'trequiredCharacter
. IfrequiredCharacterValue
isfalse
: the item will be locked when the current character's identity isrequiredCharacter
.item.SetupUnlockOnEncounterOrCustomFlag(flag, requiredFlagValue, encounterObjectGuid, requiredNumberOfEncounters, comparisonOperation)
- ifcomparisonOperation
isDungeonPrerequisite.PrerequisiteOperation.LESS_THAN
: the item is locked when EncounterTrackable with guid ofencounterObjectGuid
's number of encounters is greater or equal torequiredNumberOfEncounters
andflag
's value isn'trequiredFlagValue
. IfcomparisonOperation
isDungeonPrerequisite.PrerequisiteOperation.EQUAL_TO
: the item is locked when EncounterTrackable with guid ofencounterObjectGuid
's number of encounters isn't equal torequiredNumberOfEncounters
andflag
's value isn'trequiredFlagValue
. IfcomparisonOperation
isDungeonPrerequisite.PrerequisiteOperation.GREATER_THAN
: the item is locked when EncounterTrackable with guid ofencounterObjectGuid
's number of encounters is less or equal torequiredNumberOfEncounters
andflag
's value isn'trequiredFlagValue
.item.SetupUnlockOnEncounterOrCustomFlag(flag, requiredFlagValue, encounterRoom, requiredNumberOfEncounters, comparisonOperation)
- ifcomparisonOperation
isDungeonPrerequisite.PrerequisiteOperation.LESS_THAN
: the item is locked whenencounterRoom
's number of encounters is greater or equal torequiredNumberOfEncounters
andflag
's value isn'trequiredFlagValue
. IfcomparisonOperation
isDungeonPrerequisite.PrerequisiteOperation.EQUAL_TO
: the item is locked whenencounterRoom
's number of encounters isn't equal torequiredNumberOfEncounters
andflag
's value isn'trequiredFlagValue
. IfcomparisonOperation
isDungeonPrerequisite.PrerequisiteOperation.GREATER_THAN
: the item is locked whenencounterRoom
's number of encounters is less or equal torequiredNumberOfEncounters
andflag
's value isn'trequiredFlagValue
.item.SetupUnlockOnCustomFlag(flag, requiredFlagValue)
- the item will be locked whenflag
's value isn'trequiredFlagValue
item.SetupUnlockOnCustomStat(stat, comparisonValue, comparisonOperation)
- ifcomparisonOperation
isDungeonPrerequisite.PrerequisiteOperation.LESS_THAN
: the item is locked whenstat
's value is greater or equal tocomparisonValue
. IfcomparisonOperation
isDungeonPrerequisite.PrerequisiteOperation.EQUAL_TO
: the item is locked whenstat
's value isn't equal tocomparisonValue
. IfcomparisonOperation
isDungeonPrerequisite.PrerequisiteOperation.GREATER_THAN
: the item is locked whenstat
's value is less or equal tocomparisonValue
.item.SetupUnlockOnCustomMaximum(maximum, comparisonValue, comparisonOperation)
- ifcomparisonOperation
isDungeonPrerequisite.PrerequisiteOperation.LESS_THAN
: the item is locked whenmaximum
's value is greater or equal tocomparisonValue
. IfcomparisonOperation
isDungeonPrerequisite.PrerequisiteOperation.EQUAL_TO
: the item is locked whenmaximum
's value isn't equal tocomparisonValue
. IfcomparisonOperation
isDungeonPrerequisite.PrerequisiteOperation.GREATER_THAN
: the item is locked whenmaximum
's value is less or equal tocomparisonValue
.item.SetupUnlockOnCustomMaximum(comparisonValue, comparisonOperation)
- ifcomparisonOperation
isDungeonPrerequisite.PrerequisiteOperation.LESS_THAN
: the item is locked when the total amount of pasts beaten is greater or equal tocomparisonValue
. IfcomparisonOperation
isDungeonPrerequisite.PrerequisiteOperation.EQUAL_TO
: the item is locked when the total amount of pasts beaten isn't equal tocomparisonValue
. IfcomparisonOperation
isDungeonPrerequisite.PrerequisiteOperation.GREATER_THAN
: the item is locked when the total amount of pasts beaten is less or equal tocomparisonValue
.
If there's no SetupUnlock method for a type of prerequisite you want to add, you can manually add it with item.AddPrerequisite(yourPrerequisite)
You can add multiple prerequisites to an item by calling SetupUnlock or AddPrerequisite method multiple times. If an item has more than one prerequisite, it will be unlocked when all prerequisites are fulfilled.
Adding new items to breach shops
Spoiler!
To add an item to Trorc's, Goopton's or Doug's you need to call item.AddItemToTrorcMetaShop(hegemonyCreditCost, itemAppearIndex)
, item.AddItemToGooptonMetaShop(hegemonyCreditCost, itemAppearIndex)
and item.AddItemToDougMetaShop(hegemonyCreditCost, itemAppearIndex)
respectively.
You can't add singular items to Ox and Cadence's shops, you need to add tiers (3 items) to it. You can do it by calling BreachShopTool.AddBaseMetaShopTier(Gungeon.Game.Items["left_item_console_id"].PickupObjectId, leftItemPrice, Gungeon.Game.Items["middle_item_console_id"].PickupObjectId, middleItemPrice, Gungeon.Game.Items["right_item_console_id"].PickupObjectId, rightItemPrice, appearIndex)
. You don't need to include the arguments for the middle and/or right items and if you don't include them the middle and/or the right items will appear as "Sold Out" signs. Additionally you can add a double tier (2 tiers or 6 items) using BreachShopTool.AddBaseMetaShopTier(Gungeon.Game.Items["upper_left_item_console_id"].PickupObjectId, upperLeftItemPrice, Gungeon.Game.Items["upper_middle_item_console_id"].PickupObjectId, upperMiddleItemPrice, Gungeon.Game.Items["upper_right_item_console_id"].PickupObjectId, upperRightItemPrice, Gungeon.Game.Items["bottom_left_item_console_id"].PickupObjectId, bottomLeftItemPrice, Gungeon.Game.Items["bottom_middle_item_console_id"].PickupObjectId, bottomMiddleItemPrice, Gungeon.Game.Items["bottom_right_item_console_id"].PickupObjectId, upperRightItemPrice, appearIndex)
. Just like with the first method, you don't need to include the bottom right and/or bottom middle item arguments, and if you don't include them the bottom right and/or bottom middle items will appear as "Sold Out Sign".
Note that none of the methods automatically lock the items, so you will need to manually lock them using item.SetupUnlockOnCustomFlag(customFlag, true)
.
Adding custom monster hunt quests
Spoiler!
To add a new monster hunt quest, you need to call CustomHuntQuests.AddQuest(questFlag, questIntroConversation, targetEnemyName, targetEnemies OR targetEnemyGuids, numberKillsRequired, rewardFlags, customRewardFlags, requiredState, validTargetCheck, index)
What do the arguments mean:
questFlag
- flag the value of which is get to check if the quest is complete and is set to true after the last valid quest enemy is killed.questIntroConversation
- the dialogue that Frifle will say when giving the quest to the player.targetEnemyName
- text that Frifle or the Grey Mauser will say when saying how many enemy kills are remaining.targetEnemies
- list of enemies that need to be killed to progress the quest ORtargetEnemyGuids
- guids of enemies that need to be killed to progress the quest.numberKillsRequired
- amount of times the player needs to kill valid quest enemies for the quest to be completed.rewardFlags
- flags that will be set when the player talks to Frifle or the Grey Mauser after completing the quest. If null, defaults to an empty list (no reward flags).customRewardFlags
- custom flags that will be set when the player talks to Frifle or the Grey Mauser after completing the quest. If null, defaults to an empty list (no custom reward flags).requiredState
- enemy state required for an enemy to progress the quest. IfJammedEnemyState.Jammed
, the enemy will need to be jammed, ifJammedEnemyState.Unjammed
, the enemy will need to not be jammed and ifJammedEnemyState.NoCheck
, it won't check for any enemy states.validTargetCheck
- delegate that will be called when an enemy is killed to check if it's valid. It must return true for the enemy to be valid. It'sAIActor
argument is the killed enemy and it'sMonsterHuntProgress
argument is the current hunt progress.index
- the index at which the quest will appear. If null, defaults to the last index in the monster hunt quest list.
You can also add quests to the list of random quests that Frifle will give after the player completes all the ordered quests by calling CustomHuntQuests.AddProceduralQuest(questIntroConversation, targetEnemyName, targetEnemies OR targetEnemyGuids, numberKillsRequired, requiredState, validTargetCheck, rewardFlags, customRewardFlags)
What do the arguments mean:
questIntroConversation
- the dialogue that Frifle will say when giving the quest to the player.targetEnemyName
- text that Frifle or the Grey Mauser will say when saying how many enemy kills are remaining.targetEnemies
- list of enemies that need to be killed to progress the quest ORtargetEnemyGuids
- guids of enemies that need to be killed to progress the quest.numberKillsRequired
- amount of times the player needs to kill valid quest enemies for the quest to be completed.requiredState
- enemy state required for an enemy to progress the quest. IfJammedEnemyState.Jammed
, the enemy will need to be jammed, ifJammedEnemyState.Unjammed
, the enemy will need to not be jammed and ifJammedEnemyState.NoCheck
, it won't check for any enemy states.validTargetCheck
- delegate that will be called when an enemy is killed to check if it's valid. It must return true for the enemy to be valid. It'sAIActor
argument is the killed enemy and it'sMonsterHuntProgress
argument is the current hunt progress.rewardFlags
- flags that will be set when the player talks to Frifle or the Grey Mauser after completing the quest. If null, defaults to an empty list (no reward flags). NOTE: All base game quests don't have any reward flags, but if you for some reason want your procedural quest to have reward flags you can add them.customRewardFlags
- custom flags that will be set when the player talks to Frifle or the Grey Mauser after completing the quest. If null, defaults to an empty list (no custom reward flags). NOTE: All base game quests don't have any reward flags, but if you for some reason want your procedural quest to have reward flags you can add them.
ExampleModule.cs
Spoiler!
There's a file in the Examples folder called ExampleModule.cs
. It shows how to use most of SaveAPI's methods and has comments that exaplain what they do. You shouldn't add it to your project, but you can look at it when you need an example of a method's usage.