mirror of
https://github.com/ppy/osu.git
synced 2024-09-22 00:47:24 +08:00
Update with latest changes
This commit is contained in:
parent
d04da46522
commit
9461097b00
@ -2,6 +2,8 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using osu.Game.Rulesets.Difficulty.Preprocessing;
|
using osu.Game.Rulesets.Difficulty.Preprocessing;
|
||||||
using osu.Game.Rulesets.Difficulty.Skills;
|
using osu.Game.Rulesets.Difficulty.Skills;
|
||||||
using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing;
|
using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing;
|
||||||
@ -12,130 +14,108 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills
|
|||||||
public class Colour : Skill
|
public class Colour : Skill
|
||||||
{
|
{
|
||||||
protected override double SkillMultiplier => 1;
|
protected override double SkillMultiplier => 1;
|
||||||
protected override double StrainDecayBase => 0.3;
|
protected override double StrainDecayBase => 0.4;
|
||||||
|
|
||||||
private ColourSwitch lastColourSwitch = ColourSwitch.None;
|
private bool prevIsKat = false;
|
||||||
private int sameColourCount = 1;
|
|
||||||
|
|
||||||
private readonly int[] previousDonLengths = { 0, 0 };
|
private int currentMonoLength = 1;
|
||||||
private readonly int[] previousKatLengths = { 0, 0 };
|
private List<int> monoHistory = new List<int>();
|
||||||
|
private readonly int mono_history_max_length = 5;
|
||||||
|
private int monoHistoryLength = 0;
|
||||||
|
|
||||||
private int sameTypeCount = 1;
|
private double sameParityPenalty()
|
||||||
|
{
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: make this smarter (dont initialise with "Don")
|
private double repititionPenalty(int notesSince)
|
||||||
private bool previousIsKat;
|
{
|
||||||
|
double d = notesSince;
|
||||||
|
return Math.Atan(d / 30) / (Math.PI / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private double patternLengthPenalty(int patternLength)
|
||||||
|
{
|
||||||
|
double shortPatternPenalty = Math.Min(0.25 * patternLength, 1.0);
|
||||||
|
double longPatternPenalty = Math.Max(Math.Min(2.5 - 0.15 * patternLength, 1.0), 0.0);
|
||||||
|
return Math.Min(shortPatternPenalty, longPatternPenalty);
|
||||||
|
}
|
||||||
|
|
||||||
protected override double StrainValueOf(DifficultyHitObject current)
|
protected override double StrainValueOf(DifficultyHitObject current)
|
||||||
{
|
{
|
||||||
return StrainValueOfNew(current);
|
double objectDifficulty = 0.0;
|
||||||
}
|
|
||||||
|
|
||||||
protected double StrainValueOfNew(DifficultyHitObject current)
|
|
||||||
{
|
|
||||||
double returnVal = 0.0;
|
|
||||||
double returnMultiplier = 1.0;
|
|
||||||
|
|
||||||
if (previousIsKat != ((TaikoDifficultyHitObject)current).IsKat)
|
|
||||||
{
|
|
||||||
returnVal = 1.5 - (1.75 / (sameTypeCount + 0.65));
|
|
||||||
|
|
||||||
if (previousIsKat)
|
|
||||||
{
|
|
||||||
if (sameTypeCount % 2 == previousDonLengths[0] % 2)
|
|
||||||
{
|
|
||||||
returnMultiplier *= 0.8;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (previousKatLengths[0] == sameTypeCount)
|
|
||||||
{
|
|
||||||
returnMultiplier *= 0.525;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (previousKatLengths[1] == sameTypeCount)
|
|
||||||
{
|
|
||||||
returnMultiplier *= 0.75;
|
|
||||||
}
|
|
||||||
|
|
||||||
previousKatLengths[1] = previousKatLengths[0];
|
|
||||||
previousKatLengths[0] = sameTypeCount;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (sameTypeCount % 2 == previousKatLengths[0] % 2)
|
|
||||||
{
|
|
||||||
returnMultiplier *= 0.8;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (previousDonLengths[0] == sameTypeCount)
|
|
||||||
{
|
|
||||||
returnMultiplier *= 0.525;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (previousDonLengths[1] == sameTypeCount)
|
|
||||||
{
|
|
||||||
returnMultiplier *= 0.75;
|
|
||||||
}
|
|
||||||
|
|
||||||
previousDonLengths[1] = previousDonLengths[0];
|
|
||||||
previousDonLengths[0] = sameTypeCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
sameTypeCount = 1;
|
|
||||||
previousIsKat = ((TaikoDifficultyHitObject)current).IsKat;
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sameTypeCount += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Math.Min(1.25, returnVal) * returnMultiplier;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected double StrainValueOfOld(DifficultyHitObject current)
|
|
||||||
{
|
|
||||||
double addition = 0;
|
|
||||||
|
|
||||||
// We get an extra addition if we are not a slider or spinner
|
|
||||||
if (current.LastObject is Hit && current.BaseObject is Hit && current.DeltaTime < 1000)
|
if (current.LastObject is Hit && current.BaseObject is Hit && current.DeltaTime < 1000)
|
||||||
{
|
{
|
||||||
if (hasColourChange(current))
|
|
||||||
addition = 0.75;
|
TaikoDifficultyHitObject currentHO = (TaikoDifficultyHitObject)current;
|
||||||
|
|
||||||
|
if (currentHO.IsKat == prevIsKat)
|
||||||
|
{
|
||||||
|
currentMonoLength += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
objectDifficulty = 1.0;
|
||||||
|
|
||||||
|
if (monoHistoryLength > 0 && (monoHistory[monoHistoryLength - 1] + currentMonoLength) % 2 == 0)
|
||||||
|
{
|
||||||
|
objectDifficulty *= sameParityPenalty();
|
||||||
|
}
|
||||||
|
|
||||||
|
monoHistory.Add(currentMonoLength);
|
||||||
|
monoHistoryLength += 1;
|
||||||
|
|
||||||
|
if (monoHistoryLength > mono_history_max_length)
|
||||||
|
{
|
||||||
|
monoHistory.RemoveAt(0);
|
||||||
|
monoHistoryLength -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int l = 2; l <= mono_history_max_length / 2; l++)
|
||||||
|
{
|
||||||
|
for (int start = monoHistoryLength - l - 1; start >= 0; start--)
|
||||||
|
{
|
||||||
|
bool samePattern = true;
|
||||||
|
|
||||||
|
for (int i = 0; i < l; i++)
|
||||||
|
{
|
||||||
|
if (monoHistory[start + i] != monoHistory[monoHistoryLength - l + i])
|
||||||
|
{
|
||||||
|
samePattern = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (samePattern) // Repitition found!
|
||||||
|
{
|
||||||
|
int notesSince = 0;
|
||||||
|
for (int i = start; i < monoHistoryLength; i++) notesSince += monoHistory[i];
|
||||||
|
objectDifficulty *= repititionPenalty(notesSince);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
currentMonoLength = 1;
|
||||||
|
prevIsKat = currentHO.IsKat;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
/*
|
||||||
|
string path = @"out.txt";
|
||||||
|
using (StreamWriter sw = File.AppendText(path))
|
||||||
{
|
{
|
||||||
lastColourSwitch = ColourSwitch.None;
|
if (((TaikoDifficultyHitObject)current).IsKat) sw.WriteLine("k " + Math.Min(1.25, returnVal) * returnMultiplier);
|
||||||
sameColourCount = 1;
|
else sw.WriteLine("d " + Math.Min(1.25, returnVal) * returnMultiplier);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
return addition;
|
return objectDifficulty;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool hasColourChange(DifficultyHitObject current)
|
|
||||||
{
|
|
||||||
var taikoCurrent = (TaikoDifficultyHitObject)current;
|
|
||||||
|
|
||||||
if (!taikoCurrent.HasTypeChange)
|
|
||||||
{
|
|
||||||
sameColourCount++;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var oldColourSwitch = lastColourSwitch;
|
|
||||||
var newColourSwitch = sameColourCount % 2 == 0 ? ColourSwitch.Even : ColourSwitch.Odd;
|
|
||||||
|
|
||||||
lastColourSwitch = newColourSwitch;
|
|
||||||
sameColourCount = 1;
|
|
||||||
|
|
||||||
// We only want a bonus if the parity of the color switch changes
|
|
||||||
return oldColourSwitch != ColourSwitch.None && oldColourSwitch != newColourSwitch;
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum ColourSwitch
|
|
||||||
{
|
|
||||||
None,
|
|
||||||
Even,
|
|
||||||
Odd
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,9 +49,13 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills
|
|||||||
// Penalty for notes so slow that alting is not necessary.
|
// Penalty for notes so slow that alting is not necessary.
|
||||||
private double speedPenalty(double noteLengthMS)
|
private double speedPenalty(double noteLengthMS)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (noteLengthMS < 80) return 1;
|
if (noteLengthMS < 80) return 1;
|
||||||
if (noteLengthMS < 160) return Math.Max(0, 1.4 - 0.005 * noteLengthMS);
|
// return Math.Max(0, 1.4 - 0.005 * noteLengthMS);
|
||||||
if (noteLengthMS < 300) return 0.6;
|
if (noteLengthMS < 210) return Math.Max(0, 1.4 - 0.005 * noteLengthMS);
|
||||||
|
if (noteLengthMS < 210) return 0.6;
|
||||||
|
|
||||||
|
currentStrain = 0.0;
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,10 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
|
|||||||
{
|
{
|
||||||
public class TaikoDifficultyAttributes : DifficultyAttributes
|
public class TaikoDifficultyAttributes : DifficultyAttributes
|
||||||
{
|
{
|
||||||
|
public double StaminaStrain;
|
||||||
|
public double RhythmStrain;
|
||||||
|
public double ColourStrain;
|
||||||
|
public double ApproachRate;
|
||||||
public double GreatHitWindow;
|
public double GreatHitWindow;
|
||||||
public int MaxCombo;
|
public int MaxCombo;
|
||||||
}
|
}
|
||||||
|
@ -29,10 +29,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
private double readingPenalty(double staminaDifficulty)
|
private double simpleColourPenalty(double staminaDifficulty, double colorDifficulty)
|
||||||
{
|
{
|
||||||
return Math.Max(0, 1 - staminaDifficulty / 14);
|
return 0.79 - Math.Atan(staminaDifficulty / colorDifficulty - 12) / Math.PI / 2;
|
||||||
// return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private double norm(double p, double v1, double v2, double v3)
|
private double norm(double p, double v1, double v2, double v3)
|
||||||
@ -48,15 +47,13 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
|
|||||||
{
|
{
|
||||||
if (sr <= 1) return sr;
|
if (sr <= 1) return sr;
|
||||||
sr -= 1;
|
sr -= 1;
|
||||||
sr = 1.5 * Math.Pow(sr, 0.76);
|
sr = 1.6 * Math.Pow(sr, 0.7);
|
||||||
sr += 1;
|
sr += 1;
|
||||||
return sr;
|
return sr;
|
||||||
}
|
}
|
||||||
|
|
||||||
private double combinedDifficulty(Skill colour, Skill rhythm, Skill stamina1, Skill stamina2)
|
private double combinedDifficulty(double staminaPenalty, Skill colour, Skill rhythm, Skill stamina1, Skill stamina2)
|
||||||
{
|
{
|
||||||
double staminaRating = (stamina1.DifficultyValue() + stamina2.DifficultyValue()) * staminaSkillMultiplier;
|
|
||||||
double readingPenalty = this.readingPenalty(staminaRating);
|
|
||||||
|
|
||||||
double difficulty = 0;
|
double difficulty = 0;
|
||||||
double weight = 1;
|
double weight = 1;
|
||||||
@ -64,9 +61,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
|
|||||||
|
|
||||||
for (int i = 0; i < colour.StrainPeaks.Count; i++)
|
for (int i = 0; i < colour.StrainPeaks.Count; i++)
|
||||||
{
|
{
|
||||||
double colourPeak = colour.StrainPeaks[i] * colourSkillMultiplier * readingPenalty;
|
double colourPeak = colour.StrainPeaks[i] * colourSkillMultiplier;
|
||||||
double rhythmPeak = rhythm.StrainPeaks[i] * rhythmSkillMultiplier;
|
double rhythmPeak = rhythm.StrainPeaks[i] * rhythmSkillMultiplier;
|
||||||
double staminaPeak = (stamina1.StrainPeaks[i] + stamina2.StrainPeaks[i]) * staminaSkillMultiplier;
|
double staminaPeak = (stamina1.StrainPeaks[i] + stamina2.StrainPeaks[i]) * staminaSkillMultiplier * staminaPenalty;
|
||||||
peaks.Add(norm(2, colourPeak, rhythmPeak, staminaPeak));
|
peaks.Add(norm(2, colourPeak, rhythmPeak, staminaPeak));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,11 +82,13 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
|
|||||||
return new TaikoDifficultyAttributes { Mods = mods, Skills = skills };
|
return new TaikoDifficultyAttributes { Mods = mods, Skills = skills };
|
||||||
|
|
||||||
double staminaRating = (skills[2].DifficultyValue() + skills[3].DifficultyValue()) * staminaSkillMultiplier;
|
double staminaRating = (skills[2].DifficultyValue() + skills[3].DifficultyValue()) * staminaSkillMultiplier;
|
||||||
double readingPenalty = this.readingPenalty(staminaRating);
|
double colourRating = skills[0].DifficultyValue() * colourSkillMultiplier;
|
||||||
|
|
||||||
double colourRating = skills[0].DifficultyValue() * colourSkillMultiplier * readingPenalty;
|
|
||||||
double rhythmRating = skills[1].DifficultyValue() * rhythmSkillMultiplier;
|
double rhythmRating = skills[1].DifficultyValue() * rhythmSkillMultiplier;
|
||||||
double combinedRating = combinedDifficulty(skills[0], skills[1], skills[2], skills[3]);
|
|
||||||
|
double staminaPenalty = simpleColourPenalty(staminaRating, colourRating);
|
||||||
|
staminaRating *= staminaPenalty;
|
||||||
|
|
||||||
|
double combinedRating = combinedDifficulty(staminaPenalty, skills[0], skills[1], skills[2], skills[3]);
|
||||||
|
|
||||||
// Console.WriteLine("colour\t" + colourRating);
|
// Console.WriteLine("colour\t" + colourRating);
|
||||||
// Console.WriteLine("rhythm\t" + rhythmRating);
|
// Console.WriteLine("rhythm\t" + rhythmRating);
|
||||||
@ -107,6 +106,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
|
|||||||
{
|
{
|
||||||
StarRating = starRating,
|
StarRating = starRating,
|
||||||
Mods = mods,
|
Mods = mods,
|
||||||
|
StaminaStrain = staminaRating,
|
||||||
|
RhythmStrain = rhythmRating,
|
||||||
|
ColourStrain = colourRating,
|
||||||
// Todo: This int cast is temporary to achieve 1:1 results with osu!stable, and should be removed in the future
|
// Todo: This int cast is temporary to achieve 1:1 results with osu!stable, and should be removed in the future
|
||||||
GreatHitWindow = (int)(hitWindows.WindowFor(HitResult.Great)) / clockRate,
|
GreatHitWindow = (int)(hitWindows.WindowFor(HitResult.Great)) / clockRate,
|
||||||
MaxCombo = beatmap.HitObjects.Count(h => h is Hit),
|
MaxCombo = beatmap.HitObjects.Count(h => h is Hit),
|
||||||
|
Loading…
Reference in New Issue
Block a user