11using MonoMod . RuntimeDetour ;
22using System . Linq ;
3- using System . Reflection ;
43
54namespace Celeste . Mod . CommunalHelper . Entities ;
65
@@ -42,11 +41,12 @@ public bool Visible
4241 if ( visible != value )
4342 for ( int i = 0 ; i < buttonImages . Length ; i ++ )
4443 buttonImages [ i ] . Visible = buttonOutlineImages [ i ] . Visible = value ;
44+
4545 visible = value ;
4646 }
4747 }
4848
49- private bool preventVisualUpdate = false ;
49+ private bool preventVisualUpdate ;
5050
5151 private bool pressed ;
5252 public bool Pressed
@@ -63,6 +63,7 @@ private set
6363 buttonOutlineImages [ i ] . Position = imagePositions [ i ] + offset ;
6464 }
6565 }
66+
6667 pressed = value ;
6768 }
6869 }
@@ -122,8 +123,8 @@ public void Update(AeroBlockCharged self, bool preventVisualUpdate)
122123 : Calc . Approach ( lerp , 0.0f , Engine . DeltaTime * 4f ) ;
123124
124125 Color color = Color . Lerp ( Color . White , self . alive ? self . activeColor : self . inactiveColor , lerp ) ;
125- for ( int i = 0 ; i < buttonImages . Length ; i ++ )
126- buttonImages [ i ] . Color = color ;
126+ foreach ( Image image in buttonImages )
127+ image . Color = color ;
127128 }
128129
129130 public void ChangeProperties ( int pressOffset , Color color )
@@ -154,14 +155,21 @@ public static Button TopButton(AeroBlockCharged entity, bool visible)
154155 private readonly bool loop ;
155156
156157 private readonly int cassetteIndex = - 1 ;
157- private CassetteListener listener ;
158+ private readonly CassetteListener listener ;
158159 private readonly bool moveOnCassetteTick ;
159160
160161 private bool alive = true ;
161162 private readonly bool SpirialisBug = false ;
162163 private readonly bool wallbounceLeniency ;
163164
164165 private Button leftButton , rightButton , topButton ;
166+ private Button ButtonFromDir ( int dir ) => dir switch
167+ {
168+ - 1 => leftButton ,
169+ 0 => topButton ,
170+ 1 => rightButton ,
171+ _ => null
172+ } ;
165173
166174 private bool buttonSfxOn = false ;
167175 private float buttonSfxLerp ;
@@ -175,8 +183,7 @@ public static Button TopButton(AeroBlockCharged entity, bool visible)
175183
176184 private readonly Color activeColor , inactiveColor ;
177185
178- private bool activatedThisTick = false ;
179- private bool activatedAlready = false ;
186+ private bool activatedPreviously , activatedThisTick ;
180187
181188 public AeroBlockCharged ( EntityData data , Vector2 offset )
182189 : this ( data . NodesWithPosition ( offset ) , data . Width , data . Height , data . Bool ( "loop" ) , data . HexColor ( "activeColor" , defaultOnColor ) , data . HexColor ( "inactiveColor" , defaultEndColor ) , data . Bool ( "hover" , true ) , data . Attr ( "buttonSequence" , DEFAULT_BUTTON_SEQUENCE ) , data . Bool ( "wallbounceLeniency" , false ) , data . Int ( "cassetteIndex" , - 1 ) , data . Bool ( "moveOnCassetteTick" ) )
@@ -247,7 +254,7 @@ private void OnActivated()
247254 private void OnDeactivated ( )
248255 {
249256 ChangeButtonProperties ( 2 , inactiveColor , inactiveColor ) ;
250- if ( moveOnCassetteTick && ! activatedThisTick && activatedAlready && alive )
257+ if ( moveOnCassetteTick && ! activatedThisTick && activatedPreviously && alive )
251258 IncrementPosition ( ) ;
252259 }
253260
@@ -330,6 +337,7 @@ private void EndSequence()
330337 Hold = 0.5f ,
331338 FadeOut = 0.5f ,
332339 } ) ;
340+
333341 Alarm . Set ( this , 0.5f , ( ) =>
334342 {
335343 blinker . Complete = true ;
@@ -349,34 +357,35 @@ private void Smash(Player player, Vector2 speed)
349357
350358 player . Speed = speed ;
351359 player . StateMachine . State = Player . StLaunch ;
360+
352361 Celeste . Freeze ( 0.05f ) ;
353362 Audio . Play ( CustomSFX . game_aero_block_smash , Center , "magic" , 1.0f ) ;
354363 Input . Rumble ( RumbleStrength . Strong , RumbleLength . Short ) ;
355- ( Scene as Level ) . DirectionalShake ( Vector2 . UnitY ) ;
364+ SceneAs < Level > ( ) . DirectionalShake ( Vector2 . UnitY ) ;
356365 windLayer . MulitplyVelocities ( - 0.5f ) ;
357366
358367 IncrementPosition ( ) ;
359368 }
360369
361370 private void IncrementPosition ( )
362371 {
363- activatedAlready = true ;
372+ activatedPreviously = true ;
364373 if ( IsCassette )
365374 activatedThisTick = true ;
366375
367376 positionIndex ++ ;
368377 if ( loop )
369378 positionIndex %= positions . Length ;
379+
370380 combinationIndex = ( combinationIndex + 1 ) % sequence . Length ;
381+
371382 if ( positionIndex < positions . Length )
372383 {
373384 Home = positions [ positionIndex ] ;
374385 ChangeCombination ( sequence [ combinationIndex ] ) ;
375386 }
376387 else
377- {
378388 EndSequence ( ) ;
379- }
380389 }
381390
382391 public override void Added ( Scene scene )
@@ -389,7 +398,7 @@ public override void Awake(Scene scene)
389398 {
390399 base . Awake ( scene ) ;
391400
392- // update visuals if deactivated on start
401+ // update visuals if we start deactivated
393402 if ( IsCassette && ( ! listener ? . Activated ?? false ) )
394403 ForceButtonDeactivate ( ) ;
395404 }
@@ -407,22 +416,15 @@ public override void Update()
407416 else
408417 ForceButtonDeactivate ( ) ;
409418
410- bool check = CheckAnyButton ( ) ;
411- if ( check )
419+ if ( CheckAnyButton ( ) && ! buttonSfxOn )
412420 {
413- if ( ! buttonSfxOn )
414- {
415- Audio . Play ( CustomSFX . game_aero_block_button_press , Center ) ;
416- buttonSfxOn = true ;
417- }
421+ Audio . Play ( CustomSFX . game_aero_block_button_press , Center ) ;
422+ buttonSfxOn = true ;
418423 }
419- else
424+ else if ( buttonSfxOn )
420425 {
421- if ( buttonSfxOn )
422- {
423- Audio . Play ( CustomSFX . game_aero_block_button_let_go , Center ) ;
424- buttonSfxOn = false ;
425- }
426+ Audio . Play ( CustomSFX . game_aero_block_button_let_go , Center ) ;
427+ buttonSfxOn = false ;
426428 }
427429
428430 float chargeSoundRate = buttonSfxOn ? 2.0f : ( alive ? 3.0f : 4.0f ) ;
@@ -453,8 +455,8 @@ internal static void Load()
453455 On . Celeste . Player . Jump += Player_Jump ;
454456 On . Celeste . Player . WallJump += Player_WallJump ;
455457 On . Celeste . Player . ClimbJump += Player_ClimbJump ;
456- On . Celeste . Player . SuperWallJump += Player_SuperWallJump ;
457458 On . Celeste . Player . SuperJump += Player_SuperJump ;
459+ On . Celeste . Player . SuperWallJump += Player_SuperWallJump ;
458460 }
459461 }
460462
@@ -463,111 +465,55 @@ internal static void Unload()
463465 On . Celeste . Player . Jump -= Player_Jump ;
464466 On . Celeste . Player . WallJump -= Player_WallJump ;
465467 On . Celeste . Player . ClimbJump -= Player_ClimbJump ;
466- On . Celeste . Player . SuperWallJump -= Player_SuperWallJump ;
467468 On . Celeste . Player . SuperJump -= Player_SuperJump ;
469+ On . Celeste . Player . SuperWallJump -= Player_SuperWallJump ;
468470 }
469471
470472 private static void Player_Jump ( On . Celeste . Player . orig_Jump orig , Player self , bool particles , bool playSfx )
471- {
472- if ( ! ( self . Scene . Tracker . Entities . TryGetValue ( typeof ( AeroBlockCharged ) , out var q ) && Collide . First ( self , q , self . Position + Vector2 . UnitY ) is AeroBlockCharged block ) ) { orig ( self , particles , playSfx ) ; return ; }
473- if ( block . SpirialisBug )
474- {
475- orig ( self , particles , playSfx ) ;
476- if ( self . OnGround ( ) && block is not null && block . CheckTopButton ( ) )
477- block . Smash ( self , Vector2 . UnitY * - 350 ) ;
478- self . varJumpSpeed = self . Speed . Y ;
479- }
480- else
481- {
482- orig ( self , particles , playSfx ) ;
483-
484- if ( ! self . OnGround ( ) )
485- return ;
486-
487- // jump
488- if ( block is not null && block . CheckTopButton ( ) )
489- block . Smash ( self , Vector2 . UnitY * - 350 ) ;
490- }
491- }
492-
473+ => SmashFirstTouchingAeroBlock ( ( ) => orig ( self , particles , playSfx ) , self , Vector2 . UnitY , block => self . OnGround ( ) && block . CheckTopButton ( ) , Vector2 . UnitY * - 350f ) ;
493474 private static void Player_WallJump ( On . Celeste . Player . orig_WallJump orig , Player self , int dir )
494- {
495- if ( ! ( self . Scene . Tracker . Entities . TryGetValue ( typeof ( AeroBlockCharged ) , out var q ) && Collide . First ( self , q , self . Position - Vector2 . UnitX * dir * 3 ) is AeroBlockCharged block ) ) { orig ( self , dir ) ; return ; }
496- if ( block . SpirialisBug )
497- {
498- orig ( self , dir ) ;
499- // wallbounce
500- if ( block is not null && ( dir < 0 ? block . CheckLeftButton ( ) : block . CheckRightButton ( ) ) )
501- block . Smash ( self , new Vector2 ( 300 * dir , - 300 ) ) ;
502- self . varJumpSpeed = self . Speed . Y ;
503- }
504- else
505- {
506- orig ( self , dir ) ;
507-
508- // walljump
509- if ( block is not null && ( dir < 0 ? block . CheckLeftButton ( ) : block . CheckRightButton ( ) ) )
510- block . Smash ( self , new Vector2 ( dir * 300 , - 300 ) ) ;
511- }
512- }
513-
475+ => SmashFirstTouchingAeroBlock ( ( ) => orig ( self , dir ) , self , - Vector2 . UnitX * dir * 3f , block => dir < 0 ? block . CheckLeftButton ( ) : block . CheckRightButton ( ) , new Vector2 ( dir * 300f , - 300f ) ) ;
514476 private static void Player_ClimbJump ( On . Celeste . Player . orig_ClimbJump orig , Player self )
515- {
516- orig ( self ) ;
517-
518- // climbjump
519- if ( ! ( self . Scene . Tracker . Entities . TryGetValue ( typeof ( AeroBlockCharged ) , out var q ) && Collide . First ( self , q , self . Position + Vector2 . UnitX * ( int ) self . Facing * 3 ) is AeroBlockCharged block ) ) { return ; }
520- if ( block is not null && ( self . Facing == Facings . Right ? block . CheckLeftButton ( ) : block . CheckRightButton ( ) ) )
521- {
522- float speed = ( ( int ) self . Facing == Math . Sign ( Input . MoveX . Value ) ) ? 300 : - 300 ;
523- block . Smash ( self , new Vector2 ( ( int ) self . Facing * speed , - 300 ) ) ;
524- }
525- }
526-
477+ => SmashFirstTouchingAeroBlock ( ( ) => orig ( self ) , self , Vector2 . UnitX * ( int ) self . Facing * 3f , block => self . Facing == Facings . Right ? block . CheckLeftButton ( ) : block . CheckRightButton ( ) , new Vector2 ( ( int ) self . Facing * ( int ) self . Facing == Math . Sign ( Input . MoveX . Value ) ? 300f : - 300f , - 300f ) ) ;
478+ private static void Player_SuperJump ( On . Celeste . Player . orig_SuperJump orig , Player self )
479+ => SmashFirstTouchingAeroBlock ( ( ) => orig ( self ) , self , Vector2 . UnitY , block => self . OnGround ( ) && block . CheckTopButton ( ) , new Vector2 ( self . Speed . X * 1.2f , - 350f ) ) ;
527480 private static void Player_SuperWallJump ( On . Celeste . Player . orig_SuperWallJump orig , Player self , int dir )
528- {
529- // check for blocks up to 5px away instead of 3px, since wallbounces have 2 more pixels of leniency than regular wall jumps
530- if ( ! ( self . Scene . Tracker . Entities . TryGetValue ( typeof ( AeroBlockCharged ) , out var q ) && Collide . First ( self , q , self . Position - Vector2 . UnitX * dir * 5 ) is AeroBlockCharged block ) ) { orig ( self , dir ) ; return ; }
531-
532- orig ( self , dir ) ;
533-
534- // wallbounce
535- var button = dir < 0 ? block . leftButton : block . rightButton ;
536- // button.Pressed is only true if madeline is within 3 pixels of the aero block, but wallbounces have 5 pixels of leniency
537- // this means that, if wallbounceLeniency is enabled, we want to check button.Visible as well to prevent there being a 2px window where it is possible to wallbounce but not recieve the boost
538- // (the 5px window is already enforced by the line which gets the reference to the aero block, so this doesn't mean you can receive a boost from an aero block you didn't wallbounce on)
539- if ( button is not null && ( button . Pressed || ( block . wallbounceLeniency && button . Visible ) ) )
481+ => SmashFirstTouchingAeroBlock ( ( ) => orig ( self , dir ) , self , - Vector2 . UnitX * dir * 5f , block =>
482+ {
483+ Button button = block . ButtonFromDir ( dir ) ;
484+ // button.Pressed is only true if madeline is within 3 pixels of the aero block, but wallbounces have 5 pixels of leniency
485+ // this means that, if wallbounceLeniency is enabled, we want to check button.Visible as well to prevent there being a 2px window where it is possible to wallbounce but not receive the boost
486+ // (the 5px window is already enforced by the time we get the aero block, so this doesn't mean you can receive a boost from an aero block you didn't wallbounce on)
487+ return button is not null && ( button . Pressed || ( block . wallbounceLeniency && button . Visible ) ) ;
488+ } , new Vector2 ( dir * 300f , - 400f ) , block =>
540489 {
541- block . Smash ( self , new Vector2 ( 300 * dir , - 400 ) ) ;
542-
543490 // give the button a quick (visual) press if it isn't already pressed, due to wallbounce leniency
544- if ( ! button . Pressed && block . wallbounceLeniency )
491+ Button button = block . ButtonFromDir ( dir ) ;
492+ if ( button is not null && ! button . Pressed && block . wallbounceLeniency )
545493 button . QuickForcePress ( ) ;
546-
547- if ( block . SpirialisBug )
548- self . varJumpSpeed = self . Speed . Y ;
549- }
550- }
551-
552- private static void Player_SuperJump ( On . Celeste . Player . orig_SuperJump orig , Player self )
494+ } ) ;
495+
496+ private static void SmashFirstTouchingAeroBlock ( Action callOrig , Player player , Vector2 checkOffset , Func < AeroBlockCharged , bool > smashCondition , Vector2 smashSpeed , Action < AeroBlockCharged > smashCallback = null )
553497 {
554- if ( ! ( self . Scene . Tracker . Entities . TryGetValue ( typeof ( AeroBlockCharged ) , out var q ) && Collide . First ( self , q , self . Position + Vector2 . UnitY ) is AeroBlockCharged block ) ) { orig ( self ) ; return ; }
555- if ( block . SpirialisBug )
498+ if ( player . Scene . Tracker
499+ . GetEntities < AeroBlockCharged > ( )
500+ . FirstOrDefault ( b => player . CollideCheck ( b , player . Position + checkOffset ) )
501+ is not AeroBlockCharged block )
556502 {
557- orig ( self ) ;
558- if ( self . OnGround ( ) && block is not null && block . CheckTopButton ( ) )
559- block . Smash ( self , new Vector2 ( self . Speed . X * 1.2f , - 350 ) ) ;
560- self . varJumpSpeed = self . Speed . Y ;
503+ callOrig ( ) ;
504+ return ;
561505 }
562- else
563- {
564- orig ( self ) ;
565-
566- if ( ! self . OnGround ( ) )
567- return ;
506+
507+ callOrig ( ) ;
568508
569- if ( block is not null && block . CheckTopButton ( ) )
570- block . Smash ( self , new Vector2 ( self . Speed . X * 1.2f , - 350 ) ) ;
509+ if ( smashCondition ( block ) )
510+ {
511+ block . Smash ( player , smashSpeed ) ;
512+
513+ if ( block . SpirialisBug )
514+ player . varJumpSpeed = player . Speed . Y ;
515+
516+ smashCallback ? . Invoke ( block ) ;
571517 }
572518 }
573519
0 commit comments