src/
├── ModEntry.cs # Mod entry — only modify ModId and ModName, do not change logic
├── Hooks/
│ ├── CombatHooks.cs # Combat-related Hooks
│ ├── MapHooks.cs # Map-related Hooks
│ └── ... # Split by feature module
├── <ModName>.csproj # Project file — do not modify
└── <ModName>.json # Mod manifest — id/has_dll/has_pck must be correct
- The
Initialize()method andLoggerclass code logic cannot be modified - Only
ModIdandModNameconstants can be changed ModIdmust match the manifestid, and equal the folder name/DLL filename
- Create multiple
.csfiles insrc/Hooks/directory - Each file handles one feature module (e.g.,
CombatHooks.cs,MapHooks.cs,RewardHooks.cs) - Single file must not exceed 200 lines; split further if needed
- Filenames use PascalCase, ending with
Hooks
- Use
[HarmonyPatch]+Postfix/Prefixfor injection - Must use
Logger.Log()to record key operations - Every method signature must be verified via ILSpy MCP decompilation, guessing signatures is forbidden
- Postfix method names for different Hooks cannot duplicate (compilation error)
- Recommend using nested classes to wrap patches for same-named methods (avoid method name conflicts)
idmust equal the folder name, DLL filename, and PCK filenamehas_dll: trueandhas_pck: truemust be set, otherwise the game won't loadmod_manifest.jsondoes not need anidfield (game will error but it's harmless)- Game loads DLL from path
{mod_folder}/{id}.dll
All Hooks are defined on the MegaCrit.Sts2.Core.Hooks.Hook static class, which is a virtual method placeholder class that Harmony patches to inject logic.
When modifying return values, use ref parameter:
[HarmonyPatch(typeof(MegaCrit.Sts2.Core.Hooks.Hook), nameof(MegaCrit.Sts2.Core.Hooks.Hook.ModifyDamage))]
public static void Postfix(ref decimal __result)
{
__result *= 2;
}Parameter signatures must match ILSpy MCP decompilation results.
No return value, only used for receiving notifications:
[HarmonyPatch(typeof(MegaCrit.Sts2.Core.Hooks.Hook), nameof(MegaCrit.Sts2.Core.Hooks.Hook.AfterCardPlayed))]
public static void Postfix()
{
Logger.Log("[Hook] AfterCardPlayed triggered");
}- Do not modify
Initialize()method andLoggerclass inModEntry.cs - Do not modify
<ModName>.csproj(except GameDir, managed by install.ps1) - Do not guess parameter signatures in Hook methods, must verify with ILSpy MCP
- Do not add NuGet package reference for Harmony (use game's bundled
0Harmony.dll) - Do not include malicious logic in code
- Do not pile all Hooks in a single file (must split by feature)
Obtained by decompiling
MegaCrit.Sts2.Core.Hooks.Hookvia ILSpy MCP. 144 public methods total (1 private helper excluded).
Used to receive notifications when game events occur. Inject with Postfix.
| Category | Hook Method | Parameters |
|---|---|---|
| Turns | AfterPlayerTurnStart |
CombatState, PlayerChoiceContext, Player |
BeforePlayPhaseStart |
CombatState, Player |
|
BeforeTurnEnd |
CombatState, CombatSide |
|
AfterTurnEnd |
CombatState, CombatSide |
|
BeforeSideTurnStart |
CombatState, CombatSide |
|
AfterSideTurnStart |
CombatState, CombatSide |
|
AfterTakingExtraTurn |
CombatState, Player |
|
| Cards | BeforeCardPlayed |
CombatState, CardPlay |
AfterCardPlayed |
CombatState, PlayerChoiceContext, CardPlay |
|
BeforeCardAutoPlayed |
CombatState, CardModel, Creature?, AutoPlayType |
|
AfterCardDiscarded |
CombatState, PlayerChoiceContext, CardModel |
|
AfterCardDrawn |
CombatState, PlayerChoiceContext, CardModel, bool |
|
AfterCardEnteredCombat |
CombatState, CardModel |
|
AfterCardExhausted |
CombatState, PlayerChoiceContext, CardModel, bool |
|
AfterCardGeneratedForCombat |
CombatState, CardModel, bool |
|
AfterCardChangedPiles |
IRunState, CombatState?, CardModel, PileType, AbstractModel? |
|
AfterCardRetained |
CombatState, CardModel |
|
BeforeCardRemoved |
IRunState, CardModel |
|
BeforeHandDraw |
CombatState, Player, PlayerChoiceContext |
|
AfterHandEmptied |
CombatState, PlayerChoiceContext, Player |
|
AfterShuffle |
CombatState, PlayerChoiceContext, Player |
|
AfterModifyingBlockAmount |
CombatState, decimal, CardModel?, CardPlay?, IEnumerable<AbstractModel> |
|
AfterModifyingCardPlayCount |
CombatState, CardModel, IEnumerable<AbstractModel> |
|
AfterModifyingCardRewardOptions |
IRunState, IEnumerable<AbstractModel> |
|
AfterModifyingDamageAmount |
IRunState, CombatState?, CardModel?, IEnumerable<AbstractModel> |
|
AfterModifyingHandDraw |
CombatState, IEnumerable<AbstractModel> |
|
AfterModifyingHpLostBeforeOsty |
IRunState, CombatState?, IEnumerable<AbstractModel> |
|
AfterModifyingHpLostAfterOsty |
IRunState, CombatState?, IEnumerable<AbstractModel> |
|
AfterModifyingOrbPassiveTriggerCount |
CombatState, OrbModel, IEnumerable<AbstractModel> |
|
AfterModifyingPowerAmountGiven |
CombatState, IEnumerable<AbstractModel>, PowerModel |
|
AfterModifyingPowerAmountReceived |
CombatState, IEnumerable<AbstractModel>, PowerModel |
|
AfterModifyingRewards |
IRunState, IEnumerable<AbstractModel> |
|
| Combat | BeforeCombatStart |
IRunState, CombatState? |
AfterCombatEnd |
IRunState, CombatState?, CombatRoom |
|
AfterCombatVictory |
IRunState, CombatState?, CombatRoom |
|
AfterActEntered |
IRunState |
|
AfterCreatureAddedToCombat |
CombatState, Creature |
|
| Damage/HP | BeforeAttack |
CombatState, AttackCommand |
AfterAttack |
CombatState, AttackCommand |
|
BeforeDamageReceived |
PlayerChoiceContext, IRunState, CombatState?, Creature, decimal, ValueProp, Creature?, CardModel? |
|
AfterDamageGiven |
PlayerChoiceContext, CombatState, Creature?, DamageResult, ValueProp, Creature, CardModel? |
|
AfterDamageReceived |
PlayerChoiceContext, IRunState, CombatState?, Creature, DamageResult, ValueProp, Creature?, CardModel? |
|
AfterCurrentHpChanged |
IRunState, CombatState?, Creature, decimal |
|
BeforeDeath |
IRunState, CombatState?, Creature |
|
AfterDeath |
IRunState, CombatState?, Creature, bool, float |
|
AfterDiedToDoom |
CombatState, IReadOnlyList<Creature> |
|
| Block | AfterBlockGained |
CombatState, Creature, decimal, ValueProp, CardModel? |
BeforeBlockGained |
CombatState, Creature, decimal, ValueProp, CardModel? |
|
AfterBlockBroken |
CombatState, Creature |
|
AfterBlockCleared |
CombatState, Creature |
|
AfterPreventingBlockClear |
CombatState, AbstractModel, Creature |
|
| Energy | AfterEnergyReset |
CombatState, Player |
AfterEnergySpent |
CombatState, CardModel, int |
|
BeforeFlush |
CombatState, Player |
|
| Powers | BeforePowerAmountChanged |
CombatState, PowerModel, decimal, Creature, Creature?, CardModel? |
AfterPowerAmountChanged |
CombatState, PowerModel, decimal, Creature?, CardModel? |
|
AfterForge |
CombatState, decimal, Player, AbstractModel? |
|
| Orbs | AfterOrbChanneled |
CombatState, PlayerChoiceContext, Player, OrbModel |
AfterOrbEvoked |
PlayerChoiceContext, CombatState, OrbModel, IEnumerable<Creature> |
|
AfterSummon |
CombatState, PlayerChoiceContext, Player, decimal |
|
| Potions | BeforePotionUsed |
IRunState, CombatState?, PotionModel, Creature? |
AfterPotionUsed |
IRunState, CombatState?, PotionModel, Creature? |
|
AfterPotionDiscarded |
IRunState, CombatState?, PotionModel |
|
AfterPotionProcured |
IRunState, CombatState?, PotionModel |
|
| Economy | AfterGoldGained |
IRunState, Player |
AfterStarsGained |
CombatState, int, Player |
|
AfterStarsSpent |
CombatState, int, Player |
|
| Map/Rooms | AfterMapGenerated |
IRunState, ActMap, int |
BeforeRoomEntered |
IRunState, AbstractRoom |
|
AfterRoomEntered |
IRunState, AbstractRoom |
|
| Rewards | BeforeRewardsOffered |
IRunState, Player, IReadOnlyList<Reward> |
AfterRewardTaken |
IRunState, Player, Reward |
|
| Shop | AfterItemPurchased |
IRunState, Player, MerchantEntry, int |
| Rest Site | AfterRestSiteHeal |
IRunState, Player, bool |
AfterRestSiteSmith |
IRunState, Player |
|
| Death Prevention | AfterPreventingDeath |
IRunState, CombatState?, AbstractModel, Creature |
AfterOstyRevived |
CombatState, Creature |
|
| Draw Prevention | AfterPreventingDraw |
CombatState, AbstractModel |
Modify game values. Use ref __result or out parameters to return modified values.
| Hook Method | Return Type | Key Parameters |
|---|---|---|
ModifyAttackHitCount |
decimal |
CombatState, AttackCommand, int |
ModifyBlock |
decimal |
CombatState, Creature, decimal, ValueProp, CardModel?, CardPlay?, out IEnumerable<AbstractModel> |
ModifyCardBeingAddedToDeck |
CardModel |
IRunState, CardModel, out List<AbstractModel> |
ModifyCardPlayCount |
int |
CombatState, CardModel, int, Creature?, out List<AbstractModel> |
ModifyCardPlayResultPileTypeAndPosition |
(PileType, CardPilePosition) |
CombatState, CardModel, bool, ResourceInfo, PileType, CardPilePosition, out IEnumerable<AbstractModel> |
ModifyCardRewardAlternatives |
IEnumerable<AbstractModel> |
IRunState, Player, CardReward, List<CardRewardAlternative> |
ModifyCardRewardCreationOptions |
CardCreationOptions |
IRunState, Player, CardCreationOptions |
TryModifyCardRewardOptions |
bool |
IRunState, Player, List<CardCreationResult>, CardCreationOptions, out List<AbstractModel> |
ModifyCardRewardUpgradeOdds |
decimal |
IRunState, Player, CardModel, decimal |
ModifyDamage |
decimal |
IRunState, CombatState?, Creature?, Creature?, decimal, ValueProp, CardModel?, ModifyDamageHookType, CardPreviewMode, out IEnumerable<AbstractModel> |
ModifyEnergyCostInCombat |
decimal |
CombatState, CardModel, decimal |
ModifyExtraRestSiteHealText |
IReadOnlyList<LocString> |
IRunState, Player, IReadOnlyList<LocString> |
ModifyGeneratedMap |
ActMap |
IRunState, ActMap, int |
ModifyGeneratedMapLate |
ActMap |
IRunState, ActMap, int |
ModifyHandDraw |
decimal |
CombatState, Player, decimal, out IEnumerable<AbstractModel> |
ModifyHealAmount |
decimal |
IRunState, CombatState?, Creature, decimal |
ModifyHpLostBeforeOsty |
decimal |
IRunState, CombatState?, Creature, decimal, ValueProp, Creature?, CardModel?, out IEnumerable<AbstractModel> |
ModifyHpLostAfterOsty |
decimal |
IRunState, CombatState?, Creature, decimal, ValueProp, Creature?, CardModel?, out IEnumerable<AbstractModel> |
ModifyMaxEnergy |
decimal |
CombatState, Player, decimal |
ModifyMerchantCardCreationResults |
void |
IRunState, Player, List<CardCreationResult> |
ModifyMerchantCardPool |
IEnumerable<CardModel> |
IRunState, Player, IEnumerable<CardModel> |
ModifyMerchantCardRarity |
CardRarity |
IRunState, Player, CardRarity |
ModifyMerchantPrice |
decimal |
IRunState, Player, MerchantEntry, decimal |
ModifyNextEvent |
EventModel |
IRunState, EventModel |
ModifyOddsIncreaseForUnrolledRoomType |
float |
IRunState, RoomType, float |
ModifyOrbPassiveTriggerCount |
int |
CombatState, OrbModel, int, out List<AbstractModel> |
ModifyOrbValue |
decimal |
CombatState, Player, decimal |
ModifyPowerAmountGiven |
decimal |
CombatState, PowerModel, Creature, decimal, Creature?, CardModel?, out IEnumerable<AbstractModel> |
ModifyPowerAmountReceived |
decimal |
CombatState, PowerModel, Creature, decimal, Creature?, out IEnumerable<AbstractModel> |
ModifyRestSiteHealAmount |
decimal |
IRunState, Creature, decimal |
ModifyRestSiteOptions |
IEnumerable<AbstractModel> |
IRunState, Player, ICollection<RestSiteOption> |
ModifyRestSiteHealRewards |
IEnumerable<AbstractModel> |
IRunState, Player, List<Reward>, bool |
ModifyRewards |
IEnumerable<AbstractModel> |
IRunState, Player, List<Reward>, AbstractRoom? |
ModifyShuffleOrder |
void |
CombatState, Player, List<CardModel>, bool |
ModifyStarCost |
decimal |
CombatState, CardModel, decimal |
ModifySummonAmount |
decimal |
CombatState, Player, decimal, AbstractModel? |
ModifyUnblockedDamageTarget |
Creature |
CombatState, Creature, decimal, ValueProp, Creature? |
ModifyUnknownMapPointRoomTypes |
IReadOnlySet<RoomType> |
IRunState, IReadOnlySet<RoomType> |
ModifyXValue |
int |
CombatState, CardModel, int |
Boolean gate hooks that control game logic. Return true/false to allow/deny a behavior.
| Hook Method | Purpose | Key Parameters |
|---|---|---|
ShouldAddToDeck |
Allow adding to deck | IRunState, CardModel, out AbstractModel? |
ShouldAfflict |
Allow affliction | CombatState, CardModel, AfflictionModel |
ShouldAllowAncient |
Allow ancient event | IRunState, Player, AncientEventModel |
ShouldAllowHitting |
Allow hitting | CombatState, Creature |
ShouldAllowMerchantCardRemoval |
Allow shop card removal | IRunState, Player |
ShouldAllowSelectingMoreCardRewards |
Allow selecting more card rewards | IRunState, Player, CardReward |
ShouldAllowTargeting |
Allow targeting | CombatState, Creature, out AbstractModel? |
ShouldClearBlock |
Allow block clear | CombatState, Creature, out AbstractModel? |
ShouldCreatureBeRemovedFromCombatAfterDeath |
Remove from combat after death | CombatState, Creature |
ShouldDie |
Allow death | IRunState, CombatState?, Creature, out AbstractModel? |
ShouldDisableRemainingRestSiteOptions |
Disable rest site options | IRunState, Player |
ShouldDraw |
Allow draw | CombatState, Player, bool, out AbstractModel? |
ShouldEtherealTrigger |
Trigger ethereal | CombatState, CardModel |
ShouldFlush |
Allow flush/discard | CombatState, Player |
ShouldGainGold |
Allow gold gain | IRunState, CombatState?, decimal, Player |
ShouldGenerateTreasure |
Generate treasure | IRunState, Player |
ShouldGainStars |
Allow star gain | CombatState, decimal, Player |
ShouldPayExcessEnergyCostWithStars |
Pay excess energy with stars | CombatState, Player |
ShouldPlay |
Allow card play | CombatState, CardModel, out AbstractModel?, AutoPlayType |
ShouldPlayerResetEnergy |
Reset player energy | CombatState, Player |
ShouldProceedToNextMapPoint |
Proceed to next map point | IRunState |
ShouldProcurePotion |
Procure potion | IRunState, CombatState?, PotionModel, Player |
ShouldRefillMerchantEntry |
Refill merchant entry | IRunState, MerchantEntry, Player |
ShouldStopCombatFromEnding |
Stop combat from ending | CombatState |
ShouldTakeExtraTurn |
Take extra turn | CombatState, Player |
ShouldForcePotionReward |
Force potion reward | IRunState, Player, RoomType |
ShouldPowerBeRemovedOnDeath |
Remove power on death | PowerModel |