1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-15 05:17:25 +08:00
osu-lazer/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs

117 lines
4.5 KiB
C#
Raw Normal View History

2020-05-11 13:50:02 +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.Linq;
2020-05-11 13:50:02 +08:00
using osu.Game.Rulesets.Difficulty.Preprocessing;
using osu.Game.Rulesets.Difficulty.Skills;
2020-08-19 01:13:18 +08:00
using osu.Game.Rulesets.Difficulty.Utils;
using osu.Game.Rulesets.Mods;
2020-05-11 13:50:02 +08:00
using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing;
2020-06-08 15:30:26 +08:00
using osu.Game.Rulesets.Taiko.Objects;
2020-05-11 13:50:02 +08:00
namespace osu.Game.Rulesets.Taiko.Difficulty.Skills
{
/// <summary>
/// Calculates the stamina coefficient of taiko difficulty.
/// </summary>
/// <remarks>
/// The reference play style chosen uses two hands, with full alternating (the hand changes after every hit).
/// </remarks>
public class Stamina : StrainDecaySkill
2020-05-11 13:50:02 +08:00
{
protected override double SkillMultiplier => 1;
protected override double StrainDecayBase => 0.4;
/// <summary>
/// Maximum number of entries to keep in <see cref="notePairDurationHistory"/>.
/// </summary>
2020-06-08 15:30:26 +08:00
private const int max_history_length = 2;
2020-08-22 23:51:35 +08:00
/// <summary>
/// The index of the hand this <see cref="Stamina"/> instance is associated with.
/// </summary>
/// <remarks>
/// The value of 0 indicates the left hand (full alternating gameplay starting with left hand is assumed).
/// This naturally translates onto index offsets of the objects in the map.
/// </remarks>
2020-08-22 23:51:35 +08:00
private readonly int hand;
/// <summary>
/// Stores the last <see cref="max_history_length"/> durations between notes hit with the hand indicated by <see cref="hand"/>.
/// </summary>
2020-08-19 01:13:18 +08:00
private readonly LimitedCapacityQueue<double> notePairDurationHistory = new LimitedCapacityQueue<double>(max_history_length);
2020-05-11 13:50:02 +08:00
/// <summary>
/// Stores the <see cref="DifficultyHitObject.DeltaTime"/> of the last object that was hit by the <i>other</i> hand.
/// </summary>
2020-05-11 13:50:02 +08:00
private double offhandObjectDuration = double.MaxValue;
/// <summary>
/// Creates a <see cref="Stamina"/> skill.
/// </summary>
/// <param name="mods">Mods for use in skill calculations.</param>
/// <param name="rightHand">Whether this instance is performing calculations for the right hand.</param>
public Stamina(Mod[] mods, bool rightHand)
: base(mods)
2020-05-11 13:50:02 +08:00
{
2020-08-22 23:51:35 +08:00
hand = rightHand ? 1 : 0;
2020-05-11 13:50:02 +08:00
}
protected override double StrainValueOf(DifficultyHitObject current)
{
2020-06-08 15:30:26 +08:00
if (!(current.BaseObject is Hit))
{
return 0.0;
}
2020-05-11 13:50:02 +08:00
2020-06-08 15:30:26 +08:00
TaikoDifficultyHitObject hitObject = (TaikoDifficultyHitObject)current;
2020-05-11 13:50:02 +08:00
2020-08-12 23:59:22 +08:00
if (hitObject.ObjectIndex % 2 == hand)
2020-05-11 13:50:02 +08:00
{
2020-06-08 15:30:26 +08:00
double objectStrain = 1;
2020-05-11 13:50:02 +08:00
2020-08-12 23:59:22 +08:00
if (hitObject.ObjectIndex == 1)
2020-05-11 13:50:02 +08:00
return 1;
2020-08-19 01:13:18 +08:00
notePairDurationHistory.Enqueue(hitObject.DeltaTime + offhandObjectDuration);
2020-05-11 13:50:02 +08:00
2020-06-08 15:30:26 +08:00
double shortestRecentNote = notePairDurationHistory.Min();
objectStrain += speedBonus(shortestRecentNote);
2020-05-11 13:50:02 +08:00
2020-06-08 15:30:26 +08:00
if (hitObject.StaminaCheese)
2020-08-12 23:59:22 +08:00
objectStrain *= cheesePenalty(hitObject.DeltaTime + offhandObjectDuration);
2020-05-11 13:50:02 +08:00
2020-06-08 15:30:26 +08:00
return objectStrain;
2020-05-11 13:50:02 +08:00
}
2020-05-11 13:53:42 +08:00
2020-08-12 23:59:22 +08:00
offhandObjectDuration = hitObject.DeltaTime;
2020-06-08 15:30:26 +08:00
return 0;
2020-05-11 13:50:02 +08:00
}
/// <summary>
/// Applies a penalty for hit objects marked with <see cref="TaikoDifficultyHitObject.StaminaCheese"/>.
/// </summary>
/// <param name="notePairDuration">The duration between the current and previous note hit using the hand indicated by <see cref="hand"/>.</param>
2020-08-22 23:51:35 +08:00
private double cheesePenalty(double notePairDuration)
2020-05-11 13:50:02 +08:00
{
2020-08-22 23:51:35 +08:00
if (notePairDuration > 125) return 1;
if (notePairDuration < 100) return 0.6;
return 0.6 + (notePairDuration - 100) * 0.016;
}
/// <summary>
/// Applies a speed bonus dependent on the time since the last hit performed using this hand.
/// </summary>
/// <param name="notePairDuration">The duration between the current and previous note hit using the hand indicated by <see cref="hand"/>.</param>
2020-08-22 23:51:35 +08:00
private double speedBonus(double notePairDuration)
{
if (notePairDuration >= 200) return 0;
double bonus = 200 - notePairDuration;
bonus *= bonus;
return bonus / 100000;
2020-05-11 13:50:02 +08:00
}
}
}