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.
2020-06-08 15:30:26 +08:00
using System ;
2022-05-22 23:26:22 +08:00
using System.Collections.Generic ;
2020-06-08 15:30:26 +08:00
using System.Linq ;
2019-02-18 13:54:21 +08:00
using osu.Game.Rulesets.Difficulty.Preprocessing ;
using osu.Game.Rulesets.Objects ;
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 ;
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>
2019-02-18 13:54:21 +08:00
public class TaikoDifficultyHitObject : DifficultyHitObject
{
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>
/// The rhythm required to hit this hit object.
/// </summary>
2020-05-11 13:50:02 +08:00
public readonly TaikoDifficultyHitObjectRhythm Rhythm ;
2020-08-23 01:34:16 +08:00
2022-06-06 12:42:49 +08:00
/// <summary>
2022-06-23 17:10:30 +08:00
/// Colour data for this hit object. This is used by colour evaluator to calculate colour difficulty, but can be used
/// by other skills in the future.
/// This need to be writeable by TaikoDifficultyHitObjectColour so that it can assign potentially reused instances
2022-06-06 12:42:49 +08:00
/// </summary>
2022-07-21 19:15:22 +08:00
public TaikoDifficultyHitObjectColour Colour ;
2022-05-26 18:04:25 +08:00
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="lastLastObject">The gameplay <see cref="HitObject"/> preceding <paramref name="lastObject"/>.</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>
/// <param name="noteObjects">The list of <see cref="DifficultyHitObject"/>s that is a hit (i.e. not a slider or spinner) 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>
2022-07-14 16:29:23 +08:00
public TaikoDifficultyHitObject ( HitObject hitObject , HitObject lastObject , HitObject lastLastObject , double clockRate ,
2022-07-15 19:07:01 +08:00
List < DifficultyHitObject > objects ,
List < TaikoDifficultyHitObject > centreHitObjects ,
List < TaikoDifficultyHitObject > rimHitObjects ,
List < TaikoDifficultyHitObject > noteObjects , int index )
2022-06-09 17:49:11 +08:00
: base ( hitObject , lastObject , clockRate , objects , index )
2019-02-18 13:54:21 +08:00
{
2022-07-21 19:15:22 +08:00
// Create the Colour object, its properties should be filled in by TaikoDifficultyPreprocessor
Colour = new TaikoDifficultyHitObjectColour ( ) ;
2020-05-11 13:53:42 +08:00
var currentHit = hitObject as Hit ;
2022-07-20 21:33:38 +08:00
noteDifficultyHitObjects = noteObjects ;
2020-05-11 13:53:42 +08:00
2020-08-23 01:34:16 +08:00
Rhythm = getClosestRhythm ( lastObject , lastLastObject , clockRate ) ;
2022-07-14 16:29:23 +08:00
HitType ? hitType = currentHit ? . Type ;
2022-05-26 18:04:25 +08:00
2022-07-15 19:07:01 +08:00
if ( hitType = = HitType . Centre )
2022-06-01 05:20:08 +08:00
{
2022-06-13 17:29:26 +08:00
MonoIndex = centreHitObjects . Count ;
2022-06-01 05:20:08 +08:00
centreHitObjects . Add ( this ) ;
monoDifficultyHitObjects = centreHitObjects ;
}
2022-07-15 19:07:01 +08:00
else if ( hitType = = HitType . Rim )
2022-06-01 05:20:08 +08:00
{
2022-06-13 17:29:26 +08:00
MonoIndex = rimHitObjects . Count ;
2022-06-01 05:20:08 +08:00
rimHitObjects . Add ( this ) ;
monoDifficultyHitObjects = rimHitObjects ;
}
2022-06-07 13:30:24 +08:00
// Need to be done after HitType is set.
2022-07-14 16:29:23 +08:00
if ( hitType = = null ) return ;
2022-06-07 13:30:24 +08:00
2022-06-13 17:29:26 +08:00
NoteIndex = noteObjects . Count ;
2022-06-09 17:22:55 +08:00
noteObjects . Add ( this ) ;
2019-02-18 13:54:21 +08:00
}
2020-05-11 13:50:02 +08:00
2020-08-23 01:34:16 +08:00
/// <summary>
/// List of most common rhythm changes in taiko maps.
/// </summary>
/// <remarks>
/// The general guidelines for the values are:
/// <list type="bullet">
/// <item>rhythm changes with ratio closer to 1 (that are <i>not</i> 1) are harder to play,</item>
/// <item>speeding up is <i>generally</i> harder than slowing down (with exceptions of rhythm changes requiring a hand switch).</item>
/// </list>
/// </remarks>
2020-08-22 23:10:31 +08:00
private static readonly TaikoDifficultyHitObjectRhythm [ ] common_rhythms =
2020-06-08 15:30:26 +08:00
{
2020-08-22 23:10:31 +08:00
new TaikoDifficultyHitObjectRhythm ( 1 , 1 , 0.0 ) ,
new TaikoDifficultyHitObjectRhythm ( 2 , 1 , 0.3 ) ,
new TaikoDifficultyHitObjectRhythm ( 1 , 2 , 0.5 ) ,
new TaikoDifficultyHitObjectRhythm ( 3 , 1 , 0.3 ) ,
new TaikoDifficultyHitObjectRhythm ( 1 , 3 , 0.35 ) ,
2020-08-23 01:34:16 +08:00
new TaikoDifficultyHitObjectRhythm ( 3 , 2 , 0.6 ) , // purposefully higher (requires hand switch in full alternating gameplay style)
2020-08-22 23:10:31 +08:00
new TaikoDifficultyHitObjectRhythm ( 2 , 3 , 0.4 ) ,
new TaikoDifficultyHitObjectRhythm ( 5 , 4 , 0.5 ) ,
new TaikoDifficultyHitObjectRhythm ( 4 , 5 , 0.7 )
} ;
2020-08-23 01:34:16 +08:00
/// <summary>
/// Returns the closest rhythm change from <see cref="common_rhythms"/> required to hit this object.
/// </summary>
/// <param name="lastObject">The gameplay <see cref="HitObject"/> preceding this one.</param>
/// <param name="lastLastObject">The gameplay <see cref="HitObject"/> preceding <paramref name="lastObject"/>.</param>
/// <param name="clockRate">The rate of the gameplay clock.</param>
private TaikoDifficultyHitObjectRhythm getClosestRhythm ( HitObject lastObject , HitObject lastLastObject , double clockRate )
{
double prevLength = ( lastObject . StartTime - lastLastObject . StartTime ) / clockRate ;
double ratio = DeltaTime / prevLength ;
return common_rhythms . OrderBy ( x = > Math . Abs ( x . Ratio - ratio ) ) . First ( ) ;
}
2022-06-01 05:20:08 +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 ) ) ;
2019-02-18 13:54:21 +08:00
}
}