2019-02-18 13:54:21 +08:00
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
2022-05-22 23:26:22 +08:00
using System.Collections.Generic ;
2020-06-08 15:30:26 +08:00
using System.Linq ;
2025-01-21 22:24:04 +08:00
using osu.Game.Beatmaps.ControlPoints ;
2019-02-18 13:54:21 +08:00
using osu.Game.Rulesets.Difficulty.Preprocessing ;
using osu.Game.Rulesets.Objects ;
2025-02-05 14:13:04 +08:00
using osu.Game.Rulesets.Taiko.Difficulty.Evaluators ;
2019-02-18 13:54:21 +08:00
using osu.Game.Rulesets.Taiko.Objects ;
2022-07-05 14:41:40 +08:00
using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour ;
2022-07-14 17:25:21 +08:00
using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Rhythm ;
2025-01-21 23:58:33 +08:00
using osu.Game.Rulesets.Taiko.Difficulty.Utils ;
2019-02-18 13:54:21 +08:00
namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing
{
2020-08-23 01:34:16 +08:00
/// <summary>
/// Represents a single hit object in taiko difficulty calculation.
/// </summary>
2024-12-27 21:30:30 +08:00
public class TaikoDifficultyHitObject : DifficultyHitObject , IHasInterval
2019-02-18 13:54:21 +08:00
{
2022-07-22 10:49:53 +08:00
/// <summary>
/// The list of all <see cref="TaikoDifficultyHitObject"/> of the same colour as this <see cref="TaikoDifficultyHitObject"/> in the beatmap.
/// </summary>
2022-06-28 10:38:58 +08:00
private readonly IReadOnlyList < TaikoDifficultyHitObject > ? monoDifficultyHitObjects ;
2022-07-22 10:49:53 +08:00
/// <summary>
/// The index of this <see cref="TaikoDifficultyHitObject"/> in <see cref="monoDifficultyHitObjects"/>.
/// </summary>
2022-06-13 17:29:26 +08:00
public readonly int MonoIndex ;
2022-07-22 10:49:53 +08:00
/// <summary>
/// The list of all <see cref="TaikoDifficultyHitObject"/> that is either a regular note or finisher in the beatmap
/// </summary>
2022-07-20 21:33:38 +08:00
private readonly IReadOnlyList < TaikoDifficultyHitObject > noteDifficultyHitObjects ;
2022-07-22 10:49:53 +08:00
/// <summary>
/// The index of this <see cref="TaikoDifficultyHitObject"/> in <see cref="noteDifficultyHitObjects"/>.
/// </summary>
2022-06-13 17:29:26 +08:00
public readonly int NoteIndex ;
2022-06-01 05:20:08 +08:00
2020-08-23 01:34:16 +08:00
/// <summary>
2025-02-05 14:13:04 +08:00
/// Rhythm data used by <see cref="RhythmEvaluator"/>.
/// This is populated via <see cref="TaikoRhythmDifficultyPreprocessor"/>.
2020-08-23 01:34:16 +08:00
/// </summary>
2025-02-05 14:01:59 +08:00
public readonly TaikoRhythmData RhythmData ;
2020-08-23 01:34:16 +08:00
2022-06-06 12:42:49 +08:00
/// <summary>
2025-02-05 14:13:04 +08:00
/// Colour data used by <see cref="ColourEvaluator"/> and <see cref="StaminaEvaluator"/>.
/// This is populated via <see cref="TaikoColourDifficultyPreprocessor"/>.
2022-06-06 12:42:49 +08:00
/// </summary>
2025-02-05 14:01:59 +08:00
public readonly TaikoColourData ColourData ;
2022-05-26 18:04:25 +08:00
2024-12-21 18:19:14 +08:00
/// <summary>
/// The adjusted BPM of this hit object, based on its slider velocity and scroll speed.
/// </summary>
public double EffectiveBPM ;
2020-08-23 01:34:16 +08:00
/// <summary>
/// Creates a new difficulty hit object.
/// </summary>
/// <param name="hitObject">The gameplay <see cref="HitObject"/> associated with this difficulty object.</param>
/// <param name="lastObject">The gameplay <see cref="HitObject"/> preceding <paramref name="hitObject"/>.</param>
/// <param name="clockRate">The rate of the gameplay clock. Modified by speed-changing mods.</param>
2022-06-06 16:11:26 +08:00
/// <param name="objects">The list of all <see cref="DifficultyHitObject"/>s in the current beatmap.</param>
/// <param name="centreHitObjects">The list of centre (don) <see cref="DifficultyHitObject"/>s in the current beatmap.</param>
/// <param name="rimHitObjects">The list of rim (kat) <see cref="DifficultyHitObject"/>s in the current beatmap.</param>
2022-08-15 20:26:54 +08:00
/// <param name="noteObjects">The list of <see cref="DifficultyHitObject"/>s that is a hit (i.e. not a drumroll or swell) in the current beatmap.</param>
2022-06-13 17:29:26 +08:00
/// <param name="index">The position of this <see cref="DifficultyHitObject"/> in the <paramref name="objects"/> list.</param>
2025-01-21 22:24:04 +08:00
/// <param name="controlPointInfo">The control point info of the beatmap.</param>
/// <param name="globalSliderVelocity">The global slider velocity of the beatmap.</param>
2025-02-05 14:13:04 +08:00
public TaikoDifficultyHitObject ( HitObject hitObject , HitObject lastObject , double clockRate ,
2022-07-15 19:07:01 +08:00
List < DifficultyHitObject > objects ,
List < TaikoDifficultyHitObject > centreHitObjects ,
List < TaikoDifficultyHitObject > rimHitObjects ,
2025-01-21 22:24:04 +08:00
List < TaikoDifficultyHitObject > noteObjects , int index ,
ControlPointInfo controlPointInfo ,
double globalSliderVelocity )
2022-06-09 17:49:11 +08:00
: base ( hitObject , lastObject , clockRate , objects , index )
2019-02-18 13:54:21 +08:00
{
2022-07-20 21:33:38 +08:00
noteDifficultyHitObjects = noteObjects ;
2020-05-11 13:53:42 +08:00
2025-02-05 14:01:59 +08:00
ColourData = new TaikoColourData ( ) ;
RhythmData = new TaikoRhythmData ( this ) ;
2022-05-26 18:04:25 +08:00
2025-02-05 14:13:04 +08:00
if ( hitObject is Hit hit )
2022-06-01 05:20:08 +08:00
{
2025-02-05 14:13:04 +08:00
switch ( hit . Type )
{
case HitType . Centre :
MonoIndex = centreHitObjects . Count ;
centreHitObjects . Add ( this ) ;
monoDifficultyHitObjects = centreHitObjects ;
break ;
case HitType . Rim :
MonoIndex = rimHitObjects . Count ;
rimHitObjects . Add ( this ) ;
monoDifficultyHitObjects = rimHitObjects ;
break ;
}
2022-06-07 13:30:24 +08:00
2022-08-15 20:54:23 +08:00
NoteIndex = noteObjects . Count ;
noteObjects . Add ( this ) ;
2022-08-15 20:26:54 +08:00
}
2025-01-21 22:24:04 +08:00
2025-01-27 04:15:13 +08:00
// Using `hitObject.StartTime` causes floating point error differences
2025-01-27 20:56:33 +08:00
double normalisedStartTime = StartTime * clockRate ;
2025-01-27 04:15:13 +08:00
2025-01-21 22:24:04 +08:00
// Retrieve the timing point at the note's start time
2025-01-27 20:56:33 +08:00
TimingControlPoint currentControlPoint = controlPointInfo . TimingPointAt ( normalisedStartTime ) ;
2025-01-21 22:24:04 +08:00
// Calculate the slider velocity at the note's start time.
2025-01-27 20:56:33 +08:00
double currentSliderVelocity = calculateSliderVelocity ( controlPointInfo , globalSliderVelocity , normalisedStartTime , clockRate ) ;
2025-01-21 22:24:04 +08:00
EffectiveBPM = currentControlPoint . BPM * currentSliderVelocity ;
}
/// <summary>
/// Calculates the slider velocity based on control point info and clock rate.
/// </summary>
private static double calculateSliderVelocity ( ControlPointInfo controlPointInfo , double globalSliderVelocity , double startTime , double clockRate )
{
var activeEffectControlPoint = controlPointInfo . EffectPointAt ( startTime ) ;
return globalSliderVelocity * ( activeEffectControlPoint . ScrollSpeed ) * clockRate ;
2019-02-18 13:54:21 +08:00
}
2020-05-11 13:50:02 +08:00
2022-07-15 19:07:01 +08:00
public TaikoDifficultyHitObject ? PreviousMono ( int backwardsIndex ) = > monoDifficultyHitObjects ? . ElementAtOrDefault ( MonoIndex - ( backwardsIndex + 1 ) ) ;
2022-06-01 05:20:08 +08:00
2022-07-15 19:07:01 +08:00
public TaikoDifficultyHitObject ? NextMono ( int forwardsIndex ) = > monoDifficultyHitObjects ? . ElementAtOrDefault ( MonoIndex + ( forwardsIndex + 1 ) ) ;
2022-06-06 16:11:26 +08:00
2022-07-20 21:33:38 +08:00
public TaikoDifficultyHitObject ? PreviousNote ( int backwardsIndex ) = > noteDifficultyHitObjects . ElementAtOrDefault ( NoteIndex - ( backwardsIndex + 1 ) ) ;
2022-06-06 16:11:26 +08:00
2022-07-20 21:33:38 +08:00
public TaikoDifficultyHitObject ? NextNote ( int forwardsIndex ) = > noteDifficultyHitObjects . ElementAtOrDefault ( NoteIndex + ( forwardsIndex + 1 ) ) ;
2025-02-05 14:13:04 +08:00
public double Interval = > DeltaTime ;
2019-02-18 13:54:21 +08:00
}
}