osu/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs

116 lines
3.8 KiB
C#
Raw Normal View History

2020-05-11 05:50:02 +00: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.
using System;
using osu.Game.Rulesets.Difficulty.Preprocessing;
using osu.Game.Rulesets.Difficulty.Skills;
2020-08-18 17:13:18 +00:00
using osu.Game.Rulesets.Difficulty.Utils;
2020-05-11 05:50:02 +00:00
using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing;
using osu.Game.Rulesets.Taiko.Objects;
namespace osu.Game.Rulesets.Taiko.Difficulty.Skills
{
public class Colour : Skill
{
2020-08-12 16:35:56 +00:00
private const int mono_history_max_length = 5;
2020-05-11 05:50:02 +00:00
protected override double SkillMultiplier => 1;
2020-05-22 11:50:21 +00:00
protected override double StrainDecayBase => 0.4;
2020-05-11 05:50:02 +00:00
2020-08-12 16:35:56 +00:00
private HitType? previousHitType;
2020-05-11 05:50:02 +00:00
2020-08-13 04:47:35 +00:00
/// <summary>
/// Length of the current mono pattern.
/// </summary>
2020-05-22 11:50:21 +00:00
private int currentMonoLength = 1;
2020-08-13 04:47:35 +00:00
/// <summary>
/// List of the last <see cref="mono_history_max_length"/> most recent mono patterns, with the most recent at the end of the list.
/// </summary>
2020-08-18 17:13:18 +00:00
private readonly LimitedCapacityQueue<int> monoHistory = new LimitedCapacityQueue<int>(mono_history_max_length);
2020-05-11 05:53:42 +00:00
2020-08-12 16:35:56 +00:00
protected override double StrainValueOf(DifficultyHitObject current)
2020-05-22 11:50:21 +00:00
{
2020-08-12 16:35:56 +00:00
if (!(current.LastObject is Hit && current.BaseObject is Hit && current.DeltaTime < 1000))
{
previousHitType = null;
return 0.0;
}
var taikoCurrent = (TaikoDifficultyHitObject)current;
double objectStrain = 0.0;
2020-08-18 17:39:03 +00:00
if (previousHitType != null && taikoCurrent.HitType != previousHitType)
2020-08-12 16:35:56 +00:00
{
2020-08-13 04:47:35 +00:00
// The colour has changed.
2020-08-12 16:35:56 +00:00
objectStrain = 1.0;
if (monoHistory.Count < 2)
2020-08-13 04:47:35 +00:00
{
// There needs to be at least two streaks to determine a strain.
2020-08-12 16:35:56 +00:00
objectStrain = 0.0;
2020-08-13 04:47:35 +00:00
}
2020-08-12 16:35:56 +00:00
else if ((monoHistory[^1] + currentMonoLength) % 2 == 0)
2020-08-13 04:47:35 +00:00
{
// The last streak in the history is guaranteed to be a different type to the current streak.
// If the total number of notes in the two streaks is even, apply a penalty.
2020-08-12 16:35:56 +00:00
objectStrain *= sameParityPenalty();
2020-08-13 04:47:35 +00:00
}
2020-08-12 16:35:56 +00:00
objectStrain *= repetitionPenalties();
currentMonoLength = 1;
}
else
{
currentMonoLength += 1;
}
previousHitType = taikoCurrent.HitType;
return objectStrain;
2020-05-22 11:50:21 +00:00
}
2020-05-11 05:53:42 +00:00
2020-08-13 04:47:35 +00:00
/// <summary>
/// The penalty to apply when the total number of notes in the two most recent colour streaks is even.
/// </summary>
private double sameParityPenalty() => 0.0;
2020-05-11 05:50:02 +00:00
2020-08-13 04:47:35 +00:00
/// <summary>
/// The penalty to apply due to the length of repetition in colour streaks.
/// </summary>
2020-06-08 07:30:26 +00:00
private double repetitionPenalties()
2020-05-11 05:50:02 +00:00
{
2020-08-18 13:24:30 +00:00
const int l = 2;
2020-06-08 07:30:26 +00:00
double penalty = 1.0;
2020-05-11 05:50:02 +00:00
2020-08-18 17:13:18 +00:00
monoHistory.Enqueue(currentMonoLength);
2020-05-11 05:50:02 +00:00
2020-08-18 13:24:30 +00:00
for (int start = monoHistory.Count - l - 1; start >= 0; start--)
2020-06-08 07:30:26 +00:00
{
if (!isSamePattern(start, l))
continue;
2020-05-22 11:50:21 +00:00
int notesSince = 0;
for (int i = start; i < monoHistory.Count; i++) notesSince += monoHistory[i];
penalty *= repetitionPenalty(notesSince);
break;
2020-06-08 07:30:26 +00:00
}
2020-05-11 05:50:02 +00:00
2020-06-08 07:30:26 +00:00
return penalty;
}
2020-05-11 05:50:02 +00:00
private bool isSamePattern(int start, int l)
{
for (int i = 0; i < l; i++)
{
if (monoHistory[start + i] != monoHistory[monoHistory.Count - l + i])
return false;
}
return true;
}
2020-08-13 04:47:35 +00:00
private double repetitionPenalty(int notesSince) => Math.Min(1.0, 0.032 * notesSince);
2020-05-11 05:50:02 +00:00
}
}