diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs new file mode 100644 index 0000000000..6f141f50ae --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs @@ -0,0 +1,46 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Rulesets.Difficulty.Preprocessing; +using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing; +using osu.Game.Rulesets.Taiko.Objects; + +namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators +{ + public class StaminaEvaluator + { + /// + /// Applies a speed bonus dependent on the time since the last hit performed using this key. + /// + /// The duration between the current and previous note hit using the same key. + private static double speedBonus(double notePairDuration) + { + return 175 / (notePairDuration + 100); + } + + /// + /// Evaluates the minimum mechanical stamina required to play the current object. This is calculated using the + /// maximum possible interval between two hits using the same key, by alternating 2 keys for each colour. + /// + public static double EvaluateDifficultyOf(DifficultyHitObject current) + { + if (!(current.BaseObject is Hit)) + { + return 0.0; + } + + // Find the previous hit object hit by the current key, which is two notes of the same colour prior. + TaikoDifficultyHitObject taikoCurrent = (TaikoDifficultyHitObject)current; + TaikoDifficultyHitObject keyPrevious = taikoCurrent.PreviousMono(1); + if (keyPrevious == null) + { + // There is no previous hit object hit by the current key + return 0.0; + } + + double objectStrain = 0.5; + objectStrain += speedBonus(taikoCurrent.StartTime - keyPrevious.StartTime); + return objectStrain; + } + } +} diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs index 8d2eadafe1..0949b8349a 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs @@ -15,6 +15,14 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing /// public class TaikoDifficultyHitObject : DifficultyHitObject { + // TODO: Review this - these was originally handled in TaikodifficultyCalculator.CreateDifficultyHitObjects, but + // it might be a good idea to encapsulate as much detail within the class as possible. + private static List centreHitObjects = new List(); + private static List rimHitObjects = new List(); + + private readonly IReadOnlyList monoDifficultyHitObjects; + public readonly int MonoPosition; + /// /// The rhythm required to hit this hit object. /// @@ -62,6 +70,18 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing Colour = TaikoDifficultyHitObjectColour.GetInstanceFor(this); } + if (HitType == Objects.HitType.Centre) + { + MonoPosition = centreHitObjects.Count(); + centreHitObjects.Add(this); + monoDifficultyHitObjects = centreHitObjects; + } + else if (HitType == Objects.HitType.Rim) + { + MonoPosition = rimHitObjects.Count(); + rimHitObjects.Add(this); + monoDifficultyHitObjects = rimHitObjects; + } } /// @@ -100,5 +120,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing return common_rhythms.OrderBy(x => Math.Abs(x.Ratio - ratio)).First(); } + + public TaikoDifficultyHitObject PreviousMono(int backwardsIndex) => monoDifficultyHitObjects.ElementAtOrDefault(MonoPosition - (backwardsIndex + 1)); + + public TaikoDifficultyHitObject NextMono(int forwardsIndex) => monoDifficultyHitObjects.ElementAtOrDefault(MonoPosition + (forwardsIndex + 1)); } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/SingleKeyStamina.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/SingleKeyStamina.cs deleted file mode 100644 index 4b8a8033a4..0000000000 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/SingleKeyStamina.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System; -using osu.Game.Rulesets.Difficulty.Preprocessing; -using osu.Game.Rulesets.Difficulty.Skills; -using osu.Game.Rulesets.Taiko.Difficulty.Evaluators; - -namespace osu.Game.Rulesets.Taiko.Difficulty.Skills -{ - /// - /// Stamina of a single key, calculated based on repetition speed. - /// - public class SingleKeyStamina - { - private const double StrainDecayBase = 0.4; - - private double CurrentStrain = 0; - - private double? previousHitTime; - - /// - /// Similar to - /// - public double StrainValueOf(DifficultyHitObject current) - { - if (previousHitTime == null) - { - previousHitTime = current.StartTime; - return 0; - } - - // CurrentStrain += strainDecay(current.StartTime - current.Previous(0).StartTime); - // CurrentStrain += 0.5 + 0.5 * strainDecay(current.StartTime - current.Previous(0).StartTime); - CurrentStrain += 1; - CurrentStrain *= ColourEvaluator.EvaluateDifficultyOf(current) * 0.1 + 0.9; - CurrentStrain *= strainDecay(current.StartTime - previousHitTime.Value); - previousHitTime = current.StartTime; - return CurrentStrain; - } - - /// - /// Applies a speed bonus dependent on the time since the last hit performed using this key. - /// - /// The duration between the current and previous note hit using the same key. - private double strainDecay(double notePairDuration) - { - return Math.Pow(StrainDecayBase, notePairDuration / 1000); - // return 175 / (notePairDuration + 100); - } - } -} diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs index 7196b68df2..713944a6e0 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs @@ -4,8 +4,8 @@ using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing; using osu.Game.Rulesets.Taiko.Difficulty.Evaluators; +using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing; using osu.Game.Rulesets.Taiko.Objects; namespace osu.Game.Rulesets.Taiko.Difficulty.Skills @@ -21,28 +21,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills protected override double SkillMultiplier => 3.6; protected override double StrainDecayBase => 0; - private readonly SingleKeyStamina[] centreKeyStamina = - { - new SingleKeyStamina(), - new SingleKeyStamina() - }; - - private readonly SingleKeyStamina[] rimKeyStamina = - { - new SingleKeyStamina(), - new SingleKeyStamina() - }; - - /// - /// Current index into for a centre hit. - /// - private int centreKeyIndex; - - /// - /// Current index into for a rim hit. - /// - private int rimKeyIndex; - /// /// Creates a skill. /// @@ -52,34 +30,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills { } - /// - /// Get the next to use for the given . - /// - /// The current . - private SingleKeyStamina getNextSingleKeyStamina(TaikoDifficultyHitObject current) - { - // Alternate key for the same color. - if (current.HitType == HitType.Centre) - { - centreKeyIndex = (centreKeyIndex + 1) % 2; - return centreKeyStamina[centreKeyIndex]; - } - - rimKeyIndex = (rimKeyIndex + 1) % 2; - return rimKeyStamina[rimKeyIndex]; - } - protected override double StrainValueOf(DifficultyHitObject current) { - if (!(current.BaseObject is Hit)) - { - return 0.0; - } - - TaikoDifficultyHitObject hitObject = (TaikoDifficultyHitObject)current; - double objectStrain = getNextSingleKeyStamina(hitObject).StrainValueOf(hitObject); - // objectStrain *= ColourEvaluator.EvaluateDifficultyOf(current) * 0.3 + 0.7; - return objectStrain; + return StaminaEvaluator.EvaluateDifficultyOf(current); } } }