2022-05-03 20:36:55 +00:00
using System.Collections ;
using System.Collections.Generic ;
using UnityEngine ;
using DG.Tweening ;
using HeavenStudio.Util ;
using Starpelly ;
namespace HeavenStudio.Games
{
public class PlayerActionEvent : PlayerActionObject
{
2022-05-06 20:05:19 +00:00
public delegate void ActionEventCallback ( PlayerActionEvent caller ) ;
public delegate void ActionEventCallbackState ( PlayerActionEvent caller , float state ) ;
2022-05-04 18:05:51 +00:00
2022-05-03 20:36:55 +00:00
public ActionEventCallbackState OnHit ; //Function to trigger when an input has been done perfectly
public ActionEventCallback OnMiss ; //Function to trigger when an input has been missed
public ActionEventCallback OnBlank ; //Function to trigger when an input has been recorded while this is pending
2022-05-06 20:05:19 +00:00
public ActionEventCallback OnDestroy ; //Function to trigger whenever this event gets destroyed. /!\ Shouldn't be used for a minigame! Use OnMiss instead /!\
2022-05-04 18:05:51 +00:00
2022-05-03 20:36:55 +00:00
public float startBeat ;
public float timer ;
2022-05-04 17:21:11 +00:00
public bool canHit = true ; //Indicates if you can still hit the cue or not. If set to false, it'll guarantee a miss
2022-05-06 20:05:19 +00:00
public bool enabled = true ; //Indicates if the PlayerActionEvent is enabled. If set to false, it'll not trigger any events and destroy itself AFTER it's not relevant anymore
2022-05-04 17:21:11 +00:00
public bool autoplayOnly = false ; //Indicates if the input event only triggers when it's autoplay. If set to true, NO Miss or Blank events will be triggered when you're not autoplaying.
public bool noAutoplay = false ; //Indicates if this PlayerActionEvent is recognized by the autoplay. /!\ Overrides autoPlayOnly /!\
2022-05-06 20:05:19 +00:00
public InputType inputType ; //The type of input. Check the InputType class to see a list of all of them
2022-05-03 20:36:55 +00:00
2022-05-06 20:05:19 +00:00
public bool perfectOnly = false ; //Indicates that the input only recognize perfect inputs.
2022-05-03 20:36:55 +00:00
public void setHitCallback ( ActionEventCallbackState OnHit )
{
this . OnHit = OnHit ;
}
public void setMissCallback ( ActionEventCallback OnMiss )
{
this . OnMiss = OnMiss ;
}
public void Enable ( ) { enabled = true ; }
public void Disable ( ) { enabled = false ; }
public void CanHit ( bool canHit )
{
this . canHit = canHit ;
}
public void Update ( )
{
if ( ! Conductor . instance . NotStopped ( ) ) { CleanUp ( ) ; } // If the song is stopped entirely in the editor, destroy itself as we don't want duplicates
2022-05-04 17:21:11 +00:00
if ( noAutoplay & & autoplayOnly ) autoplayOnly = false ;
if ( noAutoplay & & triggersAutoplay ) { triggersAutoplay = false ; }
2022-05-03 20:36:55 +00:00
float normalizedBeat = Conductor . instance . GetPositionFromBeat ( startBeat , timer ) ;
2022-05-28 02:40:16 +00:00
// allows ace detection with this new system
float stateProg = ( ( normalizedBeat - Minigame . PerfectTime ( ) ) / ( Minigame . LateTime ( ) - Minigame . PerfectTime ( ) ) - 0.5f ) * 2 ;
2022-05-03 20:36:55 +00:00
StateCheck ( normalizedBeat ) ;
2022-05-28 02:40:16 +00:00
//BUGFIX: ActionEvents destroyed too early
if ( normalizedBeat > Minigame . EndTime ( ) ) Miss ( ) ;
2022-05-03 20:36:55 +00:00
2022-05-04 17:21:11 +00:00
if ( IsCorrectInput ( ) & & ! autoplayOnly )
2022-05-03 20:36:55 +00:00
{
if ( state . perfect )
{
2022-05-28 02:40:16 +00:00
Hit ( stateProg ) ;
2022-05-03 20:36:55 +00:00
}
2022-05-06 20:05:19 +00:00
else if ( state . early & & ! perfectOnly )
2022-05-03 20:36:55 +00:00
{
2022-05-04 17:21:11 +00:00
Hit ( - 1f ) ;
2022-05-03 20:36:55 +00:00
}
2022-05-06 20:05:19 +00:00
else if ( state . late & & ! perfectOnly )
2022-05-03 20:36:55 +00:00
{
2022-05-04 17:21:11 +00:00
Hit ( 1f ) ;
2022-05-03 20:36:55 +00:00
}
else
{
Blank ( ) ;
}
}
2022-05-04 18:37:52 +00:00
}
public bool IsExpectingInputNow ( )
{
float normalizedBeat = Conductor . instance . GetPositionFromBeat ( startBeat , timer ) ;
return normalizedBeat > Minigame . EarlyTime ( ) & & normalizedBeat < Minigame . EndTime ( ) ;
}
2022-05-03 20:36:55 +00:00
public bool IsCorrectInput ( )
{
2022-05-04 16:42:06 +00:00
// This one is a mouthful but it's an evil good to detect the correct input
// Forgive me for those input type names
2022-05-03 20:36:55 +00:00
return (
2022-05-04 16:42:06 +00:00
//General inputs, both down and up
2022-07-28 23:12:21 +00:00
( PlayerInput . Pressed ( ) & & inputType . HasFlag ( InputType . STANDARD_DOWN ) ) | |
( PlayerInput . AltPressed ( ) & & inputType . HasFlag ( InputType . STANDARD_ALT_DOWN ) ) | |
( PlayerInput . GetAnyDirectionDown ( ) & & inputType . HasFlag ( InputType . DIRECTION_DOWN ) ) | |
( PlayerInput . PressedUp ( ) & & inputType . HasFlag ( InputType . STANDARD_UP ) ) | |
( PlayerInput . AltPressedUp ( ) & & inputType . HasFlag ( InputType . STANDARD_ALT_UP ) ) | |
( PlayerInput . GetAnyDirectionUp ( ) & & inputType . HasFlag ( InputType . DIRECTION_UP ) ) | |
2022-05-04 16:42:06 +00:00
//Specific directional inputs
2022-07-28 23:12:21 +00:00
( PlayerInput . GetSpecificDirectionDown ( PlayerInput . DOWN ) & & inputType . HasFlag ( InputType . DIRECTION_DOWN_DOWN ) ) | |
( PlayerInput . GetSpecificDirectionDown ( PlayerInput . UP ) & & inputType . HasFlag ( InputType . DIRECTION_UP_DOWN ) ) | |
( PlayerInput . GetSpecificDirectionDown ( PlayerInput . LEFT ) & & inputType . HasFlag ( InputType . DIRECTION_LEFT_DOWN ) ) | |
( PlayerInput . GetSpecificDirectionDown ( PlayerInput . RIGHT ) & & inputType . HasFlag ( InputType . DIRECTION_RIGHT_DOWN ) ) | |
( PlayerInput . GetSpecificDirectionUp ( PlayerInput . DOWN ) & & inputType . HasFlag ( InputType . DIRECTION_DOWN_UP ) ) | |
( PlayerInput . GetSpecificDirectionUp ( PlayerInput . UP ) & & inputType . HasFlag ( InputType . DIRECTION_UP_UP ) ) | |
( PlayerInput . GetSpecificDirectionUp ( PlayerInput . LEFT ) & & inputType . HasFlag ( InputType . DIRECTION_LEFT_UP ) ) | |
( PlayerInput . GetSpecificDirectionUp ( PlayerInput . RIGHT ) & & inputType . HasFlag ( InputType . DIRECTION_RIGHT_UP ) )
2022-05-03 20:36:55 +00:00
) ;
}
//For the Autoplay
public override void OnAce ( )
{
2022-05-28 02:40:16 +00:00
float normalizedBeat = Conductor . instance . GetPositionFromBeat ( startBeat , timer ) ;
// allows ace detection with this new system
float stateProg = ( ( normalizedBeat - Minigame . PerfectTime ( ) ) / ( Minigame . LateTime ( ) - Minigame . PerfectTime ( ) ) - 0.5f ) * 2 ;
Hit ( stateProg ) ;
2022-05-03 20:36:55 +00:00
}
2022-05-04 17:21:11 +00:00
//The state parameter is either -1 -> Early, 0 -> Perfect, 1 -> Late
public void Hit ( float state )
2022-05-03 20:36:55 +00:00
{
if ( OnHit ! = null & & enabled )
{
if ( canHit )
{
2022-05-06 20:05:19 +00:00
OnHit ( this , state ) ;
2022-05-03 20:36:55 +00:00
CleanUp ( ) ;
} else
{
2022-05-06 20:05:19 +00:00
Blank ( ) ;
2022-05-03 20:36:55 +00:00
}
}
}
public void Miss ( )
{
2022-05-04 17:21:11 +00:00
if ( OnMiss ! = null & & enabled & & ! autoplayOnly )
2022-05-03 20:36:55 +00:00
{
2022-05-06 20:05:19 +00:00
OnMiss ( this ) ;
2022-05-03 20:36:55 +00:00
}
2022-05-04 17:21:11 +00:00
CleanUp ( ) ;
2022-05-03 20:36:55 +00:00
}
public void Blank ( )
{
2022-05-04 17:21:11 +00:00
if ( OnBlank ! = null & & enabled & & ! autoplayOnly )
2022-05-03 20:36:55 +00:00
{
2022-05-06 20:05:19 +00:00
OnBlank ( this ) ;
2022-05-03 20:36:55 +00:00
}
}
public void CleanUp ( )
{
2022-05-04 18:05:51 +00:00
OnDestroy ( this ) ;
2022-05-03 20:36:55 +00:00
Destroy ( this . gameObject ) ;
}
}
}