diff --git a/Assets/Scripts/Games/CropStomp/Veggie.cs b/Assets/Scripts/Games/CropStomp/Veggie.cs index 67902e6ca..2e6e6e075 100644 --- a/Assets/Scripts/Games/CropStomp/Veggie.cs +++ b/Assets/Scripts/Games/CropStomp/Veggie.cs @@ -233,7 +233,7 @@ namespace HeavenStudio.Games.Scripts_CropStomp stompedBeat = cond.songPositionInBeatsAsDouble; - landBeat = targetBeat + (float)cond.SecsToBeats(Minigame.EndTime()-1, cond.GetBpmAtBeat(targetBeat)); + landBeat = targetBeat + (float)cond.SecsToBeats(Minigame.NgLateTime()-1, cond.GetBpmAtBeat(targetBeat)); if (autoTriggered) { diff --git a/Assets/Scripts/Games/KarateMan/KarateManJoe.cs b/Assets/Scripts/Games/KarateMan/KarateManJoe.cs index 704ef8218..3ba503553 100644 --- a/Assets/Scripts/Games/KarateMan/KarateManJoe.cs +++ b/Assets/Scripts/Games/KarateMan/KarateManJoe.cs @@ -201,7 +201,7 @@ namespace HeavenStudio.Games.Scripts_KarateMan switch (forceHand) { case 0: - if (cond.songPositionInBeatsAsDouble - lastPunchTime < 0.25f + (Minigame.LateTime() - 1f)) + if (cond.songPositionInBeatsAsDouble - lastPunchTime < 0.25f + (Minigame.JustLateTime() - 1f)) { lastPunchTime = double.MinValue; anim.DoScaledAnimationAsync("Straight", 0.5f); diff --git a/Assets/Scripts/Games/Minigame.cs b/Assets/Scripts/Games/Minigame.cs index d1ae707bf..8fb90574a 100644 --- a/Assets/Scripts/Games/Minigame.cs +++ b/Assets/Scripts/Games/Minigame.cs @@ -9,7 +9,7 @@ namespace HeavenStudio.Games { public class Minigame : MonoBehaviour { - public static double earlyTime = 0.075f, perfectTime = 0.06f, aceEarlyTime = 0.01f, aceLateTime = 0.01f, lateTime = 0.06f, endTime = 0.075f; + public static double ngEarlyTime = 0.075f, justEarlyTime = 0.06f, aceEarlyTime = 0.01f, aceLateTime = 0.01f, justLateTime = 0.06f, ngLateTime = 0.075f; public static float rankHiThreshold = 0.8f, rankOkThreshold = 0.6f; [SerializeField] public SoundSequence.SequenceKeyValue[] SoundSequences; @@ -45,7 +45,9 @@ namespace HeavenStudio.Games InputType inputType, PlayerActionEvent.ActionEventCallbackState OnHit, PlayerActionEvent.ActionEventCallback OnMiss, - PlayerActionEvent.ActionEventCallback OnBlank) + PlayerActionEvent.ActionEventCallback OnBlank, + PlayerActionEvent.ActionEventHittableQuery HittableQuery = null + ) { GameObject evtObj = new GameObject("ActionEvent" + (startBeat+timer)); @@ -59,6 +61,7 @@ namespace HeavenStudio.Games evt.OnHit = OnHit; evt.OnMiss = OnMiss; evt.OnBlank = OnBlank; + evt.IsHittable = HittableQuery; evt.OnDestroy = RemoveScheduledInput; @@ -98,8 +101,6 @@ namespace HeavenStudio.Games return evt; } - - //Clean up method used whenever a PlayerActionEvent has finished public void RemoveScheduledInput(PlayerActionEvent evt) { @@ -151,49 +152,36 @@ namespace HeavenStudio.Games } // now should fix the fast bpm problem - public static double EarlyTime() + public static double NgEarlyTime() { - return 1f - earlyTime; + return 1f - ngEarlyTime; } - public static double PerfectTime() + public static double JustEarlyTime() { - return 1f - perfectTime; + return 1f - justEarlyTime; } - public static double LateTime() + public static double JustLateTime() { - return 1f + lateTime; + return 1f + justLateTime; } - public static double EndTime() + public static double NgLateTime() { - return 1f + endTime; + return 1f + ngLateTime; } - public static double AceStartTime() + public static double AceEarlyTime() { return 1f - aceEarlyTime; } - public static double AceEndTime() + public static double AceLateTime() { return 1f + aceLateTime; } - // DEPRECATED: scales timing windows to the BPM in an ""intelligent"" manner - // only left for historical reasons - static float ScaleTimingMargin(float f) - { - float bpm = Conductor.instance.songBpm * Conductor.instance.musicSource.pitch; - float a = bpm / 120f; - float b = (Mathf.Log(a) + 2f) * 0.5f; - float r = Mathf.Lerp(a, b, 0.25f); - return r * f; - } - - public int firstEnable = 0; - public virtual void OnGameSwitch(double beat) { //Below is a template that can be used for handling previous entities. @@ -263,7 +251,7 @@ namespace HeavenStudio.Games public void ScoreMiss(double weight = 1f) { - GameManager.instance.ScoreInputAccuracy(0, true, EndTime(), weight, false); + GameManager.instance.ScoreInputAccuracy(0, true, NgLateTime(), weight, false); if (weight > 0) { GoForAPerfect.instance.Miss(); diff --git a/Assets/Scripts/Games/PlayerActionEvent.cs b/Assets/Scripts/Games/PlayerActionEvent.cs index 662122db1..2b6f32d93 100644 --- a/Assets/Scripts/Games/PlayerActionEvent.cs +++ b/Assets/Scripts/Games/PlayerActionEvent.cs @@ -18,10 +18,12 @@ namespace HeavenStudio.Games public static bool EnableAutoplayCheat = true; public delegate void ActionEventCallback(PlayerActionEvent caller); public delegate void ActionEventCallbackState(PlayerActionEvent caller, float state); + public delegate bool ActionEventHittableQuery(); 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 + public ActionEventHittableQuery IsHittable; //Checks if an input can be hit. Returning false will skip button checks. public ActionEventCallback OnDestroy; //Function to trigger whenever this event gets destroyed. /!\ Shouldn't be used for a minigame! Use OnMiss instead /!\ @@ -55,6 +57,11 @@ namespace HeavenStudio.Games this.OnMiss = OnMiss; } + public void setHittableQuery(ActionEventHittableQuery IsHittable) + { + this.IsHittable = IsHittable; + } + public void Enable() { enabled = true; } public void Disable() { enabled = false; } public void QueueDeletion() { markForDeletion = true; } @@ -105,7 +112,7 @@ namespace HeavenStudio.Games } //BUGFIX: ActionEvents destroyed too early - if (normalizedTime > Minigame.EndTime()) Miss(); + if (normalizedTime > Minigame.NgLateTime()) Miss(); if (lockedByEvent) { @@ -116,11 +123,11 @@ namespace HeavenStudio.Games return; } - if (!autoplayOnly && IsCorrectInput()) + if (!autoplayOnly && (IsHittable == null || IsHittable != null && IsHittable()) && IsCorrectInput()) { if (IsExpectingInputNow()) { - double stateProg = ((normalizedTime - Minigame.PerfectTime()) / (Minigame.LateTime() - Minigame.PerfectTime()) - 0.5f) * 2; + double stateProg = ((normalizedTime - Minigame.JustEarlyTime()) / (Minigame.JustLateTime() - Minigame.JustEarlyTime()) - 0.5f) * 2; Hit(stateProg, normalizedTime); } else @@ -186,8 +193,16 @@ namespace HeavenStudio.Games public bool IsExpectingInputNow() { + if (IsHittable != null) + { + if (!IsHittable()) return false; + } + if (!enabled) return false; + if (!isEligible) return false; + if (markForDeletion) return false; + double normalizedBeat = GetNormalizedTime(); - return normalizedBeat > Minigame.EarlyTime() && normalizedBeat < Minigame.EndTime(); + return normalizedBeat > Minigame.NgEarlyTime() && normalizedBeat < Minigame.NgLateTime(); } double GetNormalizedTime() @@ -195,9 +210,9 @@ namespace HeavenStudio.Games var cond = Conductor.instance; double currTime = cond.songPositionAsDouble; double targetTime = cond.GetSongPosFromBeat(startBeat + timer); - double min = targetTime - 1f; - double max = targetTime + 1f; - return 1f + (((currTime - min) / (max - min))-0.5f)*2; + + // HS timing window uses 1 as the middle point instead of 0 + return 1 + (currTime - targetTime); } //For the Autoplay @@ -210,7 +225,7 @@ namespace HeavenStudio.Games else { double normalizedBeat = GetNormalizedTime(); - double stateProg = ((normalizedBeat - Minigame.PerfectTime()) / (Minigame.LateTime() - Minigame.PerfectTime()) - 0.5f) * 2; + double stateProg = ((normalizedBeat - Minigame.JustEarlyTime()) / (Minigame.JustLateTime() - Minigame.JustEarlyTime()) - 0.5f) * 2; Hit(stateProg, normalizedBeat); } } @@ -251,27 +266,27 @@ namespace HeavenStudio.Games double TimeToAccuracy(double time) { - if (time >= Minigame.AceStartTime() && time <= Minigame.AceEndTime()) + if (time >= Minigame.AceEarlyTime() && time <= Minigame.AceLateTime()) { // Ace return 1.0; } double state = 0; - if (time >= Minigame.PerfectTime() && time <= Minigame.LateTime()) + if (time >= Minigame.JustEarlyTime() && time <= Minigame.JustLateTime()) { // Good Hit if (time > 1.0) { // late half of timing window - state = 1.0 - ((time - Minigame.AceEndTime()) / (Minigame.LateTime() - Minigame.AceEndTime())); + state = 1.0 - ((time - Minigame.AceLateTime()) / (Minigame.JustLateTime() - Minigame.AceLateTime())); state *= 1.0 - Minigame.rankHiThreshold; state += Minigame.rankHiThreshold; } else { //early half of timing window - state = ((time - Minigame.PerfectTime()) / (Minigame.AceStartTime() - Minigame.PerfectTime())); + state = ((time - Minigame.JustEarlyTime()) / (Minigame.AceEarlyTime() - Minigame.JustEarlyTime())); state *= 1.0 - Minigame.rankHiThreshold; state += Minigame.rankHiThreshold; } @@ -281,13 +296,13 @@ namespace HeavenStudio.Games if (time > 1.0) { // late half of timing window - state = 1.0 - ((time - Minigame.LateTime()) / (Minigame.EndTime() - Minigame.LateTime())); + state = 1.0 - ((time - Minigame.JustLateTime()) / (Minigame.NgLateTime() - Minigame.JustLateTime())); state *= Minigame.rankOkThreshold; } else { //early half of timing window - state = ((time - Minigame.PerfectTime()) / (Minigame.AceStartTime() - Minigame.PerfectTime())); + state = ((time - Minigame.JustEarlyTime()) / (Minigame.AceEarlyTime() - Minigame.JustEarlyTime())); state *= Minigame.rankOkThreshold; } } diff --git a/Assets/Scripts/Games/SpaceSoccer/Kicker.cs b/Assets/Scripts/Games/SpaceSoccer/Kicker.cs index 0f07d5a9d..00ff2ec2e 100644 --- a/Assets/Scripts/Games/SpaceSoccer/Kicker.cs +++ b/Assets/Scripts/Games/SpaceSoccer/Kicker.cs @@ -343,7 +343,7 @@ namespace HeavenStudio.Games.Scripts_SpaceSoccer var cond = Conductor.instance; ball = null; // queue the miss sound - MultiSound.Play(new MultiSound.Sound[] { new MultiSound.Sound("spaceSoccer/missNeutral", targetBeat + (float)cond.SecsToBeats(Minigame.EndTime()-1, + MultiSound.Play(new MultiSound.Sound[] { new MultiSound.Sound("spaceSoccer/missNeutral", targetBeat + (float)cond.SecsToBeats(Minigame.NgLateTime()-1, cond.GetBpmAtBeat(targetBeat)), SoundByte.GetPitchFromCents(UnityEngine.Random.Range(-75, 75), false)) }); } diff --git a/Assets/Scripts/UI/Overlays/SkillStarManager.cs b/Assets/Scripts/UI/Overlays/SkillStarManager.cs index e765dd5f5..ebbc76c0f 100644 --- a/Assets/Scripts/UI/Overlays/SkillStarManager.cs +++ b/Assets/Scripts/UI/Overlays/SkillStarManager.cs @@ -41,13 +41,13 @@ namespace HeavenStudio.Common { if (cond.songPositionInBeatsAsDouble > starStart && state == StarState.In) { - double offset = cond.SecsToBeats(Minigame.AceStartTime()-1, cond.GetBpmAtBeat(StarTargetTime)); + double offset = cond.SecsToBeats(Minigame.AceEarlyTime()-1, cond.GetBpmAtBeat(StarTargetTime)); if (cond.songPositionInBeatsAsDouble <= starStart + starLength + offset) starAnim.DoScaledAnimation("StarIn", starStart, starLength + (float)offset); else starAnim.Play("StarIn", -1, 1f); - offset = cond.SecsToBeats(Minigame.AceEndTime()-1, cond.GetBpmAtBeat(StarTargetTime)); + offset = cond.SecsToBeats(Minigame.AceLateTime()-1, cond.GetBpmAtBeat(StarTargetTime)); if (cond.songPositionInBeatsAsDouble > starStart + starLength + offset) KillStar(); } @@ -94,8 +94,8 @@ namespace HeavenStudio.Common public bool DoStarJust() { if (state == StarState.In && - cond.songPositionInBeatsAsDouble >= StarTargetTime + cond.SecsToBeats(Minigame.AceStartTime()-1, cond.GetBpmAtBeat(StarTargetTime)) && - cond.songPositionInBeatsAsDouble <= StarTargetTime + cond.SecsToBeats(Minigame.AceEndTime()-1, cond.GetBpmAtBeat(StarTargetTime)) + cond.songPositionInBeatsAsDouble >= StarTargetTime + cond.SecsToBeats(Minigame.AceEarlyTime()-1, cond.GetBpmAtBeat(StarTargetTime)) && + cond.songPositionInBeatsAsDouble <= StarTargetTime + cond.SecsToBeats(Minigame.AceLateTime()-1, cond.GetBpmAtBeat(StarTargetTime)) ) { state = StarState.Collected; diff --git a/Assets/Scripts/UI/Overlays/TimingAccuracyDisplay.cs b/Assets/Scripts/UI/Overlays/TimingAccuracyDisplay.cs index cb0c0cc68..98f27f7fb 100644 --- a/Assets/Scripts/UI/Overlays/TimingAccuracyDisplay.cs +++ b/Assets/Scripts/UI/Overlays/TimingAccuracyDisplay.cs @@ -87,12 +87,12 @@ namespace HeavenStudio.Common // SetArrowPos(time); // no Clamp() because double - time = System.Math.Max(Minigame.EarlyTime(), System.Math.Min(Minigame.EndTime(), time)); + time = System.Math.Max(Minigame.NgEarlyTime(), System.Math.Min(Minigame.NgLateTime(), time)); - if (time >= Minigame.AceStartTime() && time <= Minigame.AceEndTime()) + if (time >= Minigame.AceEarlyTime() && time <= Minigame.AceLateTime()) { type = Rating.Just; - frac = (float)((time - Minigame.AceStartTime()) / (Minigame.AceEndTime() - Minigame.AceStartTime())); + frac = (float)((time - Minigame.AceEarlyTime()) / (Minigame.AceLateTime() - Minigame.AceEarlyTime())); y = barJustTransform.localScale.y * frac - (barJustTransform.localScale.y * 0.5f); } else @@ -100,32 +100,32 @@ namespace HeavenStudio.Common if (time > 1.0) { // goes "down" - if (time <= Minigame.LateTime()) + if (time <= Minigame.JustLateTime()) { type = Rating.OK; - frac = (float)((time - Minigame.AceEndTime()) / (Minigame.LateTime() - Minigame.AceEndTime())); + frac = (float)((time - Minigame.AceLateTime()) / (Minigame.JustLateTime() - Minigame.AceLateTime())); y = ((barOKTransform.localScale.y - barJustTransform.localScale.y) * frac) + barJustTransform.localScale.y; } else { type = Rating.NG; - frac = (float)((time - Minigame.LateTime()) / (Minigame.EndTime() - Minigame.LateTime())); + frac = (float)((time - Minigame.JustLateTime()) / (Minigame.NgLateTime() - Minigame.JustLateTime())); y = ((barNGTransform.localScale.y - barOKTransform.localScale.y) * frac) + barOKTransform.localScale.y; } } else { // goes "up" - if (time >= Minigame.PerfectTime()) + if (time >= Minigame.JustEarlyTime()) { type = Rating.OK; - frac = (float)((time - Minigame.PerfectTime()) / (Minigame.AceStartTime() - Minigame.PerfectTime())); + frac = (float)((time - Minigame.JustEarlyTime()) / (Minigame.AceEarlyTime() - Minigame.JustEarlyTime())); y = ((barOKTransform.localScale.y - barJustTransform.localScale.y) * -frac) - barJustTransform.localScale.y; } else { type = Rating.NG; - frac = (float)((time - Minigame.EarlyTime()) / (Minigame.PerfectTime() - Minigame.EarlyTime())); + frac = (float)((time - Minigame.NgEarlyTime()) / (Minigame.JustEarlyTime() - Minigame.NgEarlyTime())); y = ((barNGTransform.localScale.y - barOKTransform.localScale.y) * -frac) - barOKTransform.localScale.y; } }