44using Mono . Cecil . Cil ;
55using Monocle ;
66using MonoMod . Cil ;
7+ using MonoMod . RuntimeDetour ;
78using MonoMod . Utils ;
89using System ;
910using System . Collections ;
@@ -26,6 +27,8 @@ public static class InGameOverworldHelper {
2627 private static MethodInfo m_PlayExpandSfx = typeof ( OuiChapterPanel )
2728 . GetMethod ( "PlayExpandSfx" , BindingFlags . NonPublic | BindingFlags . Instance ) ;
2829
30+ private static List < Hook > altSidesHelperHooks = new List < Hook > ( ) ;
31+
2932 public static void Load ( ) {
3033 Everest . Events . Level . OnPause += OnPause ;
3134 On . Celeste . Audio . SetMusic += OnSetMusic ;
@@ -46,6 +49,20 @@ public static void Load() {
4649 On . Celeste . Mod . AssetReloadHelper . ReloadLevel += OnReloadLevel ;
4750 }
4851
52+ public static void Initialize ( ) {
53+ if ( Everest . Loader . DependencyLoaded ( new EverestModuleMetadata ( ) { Name = "AltSidesHelper" , Version = new Version ( 1 , 2 , 0 ) } ) ) {
54+ Type altSidesHelperModule = Everest . Modules . Where ( m => m . GetType ( ) . FullName == "AltSidesHelper.AltSidesHelperModule" ) . First ( ) . GetType ( ) ;
55+
56+ altSidesHelperHooks . Add ( new Hook (
57+ altSidesHelperModule . GetMethod ( "ResetCrystalHeart" , BindingFlags . NonPublic | BindingFlags . Static ) ,
58+ typeof ( InGameOverworldHelper ) . GetMethod ( "resetCrystalHeartAfterAltSidesHelper" , BindingFlags . NonPublic | BindingFlags . Static ) ) ) ;
59+
60+ altSidesHelperHooks . Add ( new Hook (
61+ altSidesHelperModule . GetMethod ( "CustomizeCrystalHeart" , BindingFlags . NonPublic | BindingFlags . Static ) ,
62+ typeof ( InGameOverworldHelper ) . GetMethod ( "customizeCrystalHeartAfterAltSidesHelper" , BindingFlags . NonPublic | BindingFlags . Static ) ) ) ;
63+ }
64+ }
65+
4966 public static void Unload ( ) {
5067 Everest . Events . Level . OnPause -= OnPause ;
5168 On . Celeste . Audio . SetMusic -= OnSetMusic ;
@@ -64,6 +81,11 @@ public static void Unload() {
6481 On . Celeste . OuiChapterPanel . Start -= OnOuiChapterPanelStart ;
6582 On . Celeste . Player . Die -= OnPlayerDie ;
6683 On . Celeste . Mod . AssetReloadHelper . ReloadLevel -= OnReloadLevel ;
84+
85+ foreach ( Hook hook in altSidesHelperHooks ) {
86+ hook . Dispose ( ) ;
87+ }
88+ altSidesHelperHooks . Clear ( ) ;
6789 }
6890
6991 private static void OnOuiChapterPanelStart ( On . Celeste . OuiChapterPanel . orig_Start orig , OuiChapterPanel self , string checkpoint ) {
@@ -198,22 +220,42 @@ private static void customizeCrystalHeart(OuiChapterPanel panel) {
198220 string mapName = sid . DialogKeyify ( ) ;
199221 string mapLevelSet = AreaData . Get ( sid ) ? . GetLevelSet ( ) . DialogKeyify ( ) ;
200222
201- if ( HeartSpriteBank . Has ( "crystalHeart_" + mapName ) ) {
202- // this map has a custom heart registered: use it.
203- animId = "crystalHeart_" + mapName ;
204- } else if ( HeartSpriteBank . Has ( "crystalHeart_" + mapLevelSet ) ) {
205- // this level set has a custom heart registered: use it.
206- animId = "crystalHeart_" + mapLevelSet ;
207- }
223+ for ( int side = 0 ; side < 3 ; side ++ ) {
224+ string sideName = mapName ;
225+ if ( side == 1 ) {
226+ sideName += "_B" ;
227+ } else if ( side == 2 ) {
228+ sideName += "_C" ;
229+ }
230+
231+ if ( HeartSpriteBank . Has ( "crystalHeart_" + sideName ) ) {
232+ // this map has a custom heart registered: use it.
233+ animId = "crystalHeart_" + sideName ;
234+ } else if ( HeartSpriteBank . Has ( "crystalHeart_" + mapLevelSet ) ) {
235+ // this level set has a custom heart registered: use it.
236+ animId = "crystalHeart_" + mapLevelSet ;
237+ }
208238
209- if ( animId != null ) {
210- Sprite heartSprite = HeartSpriteBank . Create ( animId ) ;
211- new DynData < OuiChapterPanel > ( panel ) . Get < HeartGemDisplay > ( "heart" ) . Sprites [ 0 ] = heartSprite ;
212- heartSprite . Play ( "spin" ) ;
213- new DynData < OuiChapterPanel > ( panel ) [ "heartDirty" ] = true ;
239+ if ( animId != null ) {
240+ Sprite heartSprite = HeartSpriteBank . Create ( animId ) ;
241+ new DynData < OuiChapterPanel > ( panel ) . Get < HeartGemDisplay > ( "heart" ) . Sprites [ side ] = heartSprite ;
242+ heartSprite . Play ( "spin" ) ;
243+ new DynData < OuiChapterPanel > ( panel ) [ "heartDirty" ] = true ;
244+ }
214245 }
215246 }
216247
248+ // AltSidesHelper does very similar stuff to us, and we want to override what it does if the XMLs are asking for it.
249+ private static void resetCrystalHeartAfterAltSidesHelper ( Action < OuiChapterPanel > orig , OuiChapterPanel panel ) {
250+ orig ( panel ) ;
251+ resetCrystalHeart ( panel ) ;
252+ }
253+
254+ private static void customizeCrystalHeartAfterAltSidesHelper ( Action < OuiChapterPanel > orig , OuiChapterPanel panel ) {
255+ orig ( panel ) ;
256+ customizeCrystalHeart ( panel ) ;
257+ }
258+
217259 private static bool OnSaveDataFoundAnyCheckpoints ( On . Celeste . SaveData . orig_FoundAnyCheckpoints orig , SaveData self , AreaKey area ) {
218260 // if this is a collab chapter panel, display the second page (containing the credits) if they are defined in English.txt.
219261 // otherwise, if there is a saved state, also display the chapter panel.
0 commit comments