diff --git a/osu.Game.Rulesets.Soyokaze/Difficulty/Preprocessing/SoyokazeDifficultyHitObject.cs b/osu.Game.Rulesets.Soyokaze/Difficulty/Preprocessing/SoyokazeDifficultyHitObject.cs index 4f6a281..99c9963 100644 --- a/osu.Game.Rulesets.Soyokaze/Difficulty/Preprocessing/SoyokazeDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Soyokaze/Difficulty/Preprocessing/SoyokazeDifficultyHitObject.cs @@ -12,37 +12,40 @@ namespace osu.Game.Rulesets.Soyokaze.Difficulty.Preprocessing { public class SoyokazeDifficultyHitObject : DifficultyHitObject { - public const int COUNT = 8; + public const int MIN_COUNT = 2; + public const int MAX_COUNT = 8; public SoyokazeAction Button = (SoyokazeAction)(-1); - public int Consecutive = 0; - public int ButtonVariety = 0; - public double TotalDeltaTime = 0.0; - public double ConsecutiveDeltaTime = 0.0; + public int ButtonVariety; + public double TotalDeltaTime; + public double ConsecutiveDeltaTime; public SoyokazeDifficultyHitObject(double clockRate, HitObject[] hitObjects, List diffObjects, int index) - : base(hitObjects[COUNT - 1], hitObjects[COUNT - 2], clockRate, diffObjects, index) + : base(hitObjects[^1], hitObjects[^2], clockRate, diffObjects, index) { - Button = (hitObjects[COUNT - 1] as SoyokazeHitObject).Button; + Button = (hitObjects[^1] as SoyokazeHitObject).Button; - for (int i = hitObjects.Length - 1; i >= 0; i--) + bool[] counted = new bool[8]; + for (int i = 0; i < hitObjects.Length; i++) { - if ((hitObjects[i] as SoyokazeHitObject).Button != Button) - break; - Consecutive++; + if (!(hitObjects[i] is SoyokazeHitObject obj) || counted[(int)obj.Button]) + continue; + + counted[(int)obj.Button] = true; + ButtonVariety++; } - bool[] counted = new bool[COUNT]; - foreach (SoyokazeHitObject hitObject in hitObjects) + SoyokazeHitObject lastConsecutive = null; + for (int i = 2; i < hitObjects.Length; i++) { - if (counted[(int)hitObject.Button]) + if (!(hitObjects[^i] is SoyokazeHitObject obj) || obj.Button != Button) continue; - counted[(int)hitObject.Button] = true; - ButtonVariety++; - } - TotalDeltaTime = Math.Max((hitObjects[COUNT - 1].StartTime - hitObjects[0].StartTime) / clockRate, 1); - ConsecutiveDeltaTime = Math.Max((hitObjects[COUNT - 1].StartTime - hitObjects[COUNT - Consecutive].StartTime) / clockRate, 1); + lastConsecutive = obj; + break; + } + TotalDeltaTime = Math.Max((hitObjects[^1].StartTime - hitObjects[0].StartTime) / clockRate, 1); + ConsecutiveDeltaTime = Math.Max((hitObjects[^1].StartTime - lastConsecutive?.StartTime ?? -1e6) / clockRate, 1); } } } diff --git a/osu.Game.Rulesets.Soyokaze/Difficulty/Skills/SkillRead.cs b/osu.Game.Rulesets.Soyokaze/Difficulty/Skills/SkillRead.cs index 73c1cb1..0166675 100644 --- a/osu.Game.Rulesets.Soyokaze/Difficulty/Skills/SkillRead.cs +++ b/osu.Game.Rulesets.Soyokaze/Difficulty/Skills/SkillRead.cs @@ -10,9 +10,8 @@ namespace osu.Game.Rulesets.Soyokaze.Difficulty.Skills { public class SkillRead : StrainDecaySkill { - // slow decay and medium multiplier = buff consistently fast and cluttered maps - protected override double SkillMultiplier => 7.0; - protected override double StrainDecayBase => 0.3; + protected override double SkillMultiplier => 1.59; + protected override double StrainDecayBase => 0.08; public SkillRead(Mod[] mods) : base(mods) diff --git a/osu.Game.Rulesets.Soyokaze/Difficulty/Skills/SkillSpeed.cs b/osu.Game.Rulesets.Soyokaze/Difficulty/Skills/SkillSpeed.cs index d4e01c9..96e0cac 100644 --- a/osu.Game.Rulesets.Soyokaze/Difficulty/Skills/SkillSpeed.cs +++ b/osu.Game.Rulesets.Soyokaze/Difficulty/Skills/SkillSpeed.cs @@ -1,6 +1,7 @@ // Copyright (c) Alden Wu . Licensed under the MIT Licence. // See the LICENSE file in the repository root for full licence text. +using System; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Mods; @@ -10,9 +11,8 @@ namespace osu.Game.Rulesets.Soyokaze.Difficulty.Skills { public class SkillSpeed : StrainDecaySkill { - // fast decay and high multiplier = buff short and fast bursts/triples - protected override double SkillMultiplier => 13.5; - protected override double StrainDecayBase => 0.115; + protected override double SkillMultiplier => 0.85; + protected override double StrainDecayBase => 0.71; public SkillSpeed(Mod[] mods) : base(mods) @@ -23,10 +23,7 @@ protected override double StrainValueOf(DifficultyHitObject current) { SoyokazeDifficultyHitObject soyokazeObject = current as SoyokazeDifficultyHitObject; - if (soyokazeObject.Consecutive < 2) - return 0; - - return SkillMultiplier * (soyokazeObject.Consecutive - 1) / soyokazeObject.ConsecutiveDeltaTime; + return SkillMultiplier / Math.Pow(soyokazeObject.ConsecutiveDeltaTime, 0.32); } } } diff --git a/osu.Game.Rulesets.Soyokaze/Difficulty/SoyokazeDifficultyCalculator.cs b/osu.Game.Rulesets.Soyokaze/Difficulty/SoyokazeDifficultyCalculator.cs index c04a1da..84d4c3c 100644 --- a/osu.Game.Rulesets.Soyokaze/Difficulty/SoyokazeDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Soyokaze/Difficulty/SoyokazeDifficultyCalculator.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using osu.Framework.Logging; using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Difficulty.Preprocessing; @@ -19,6 +20,12 @@ public class SoyokazeDifficultyCalculator : DifficultyCalculator { private const double difficulty_multiplier = 0.445; + // SR values which are good and should be exponentially curved between + private const double x1 = 1.3; + private const double x2 = 6.8; + private static readonly double k = Math.Pow(x1, x2 / (x2 - x1)) * Math.Pow(x2, x1 / (x1 - x2)); + private static readonly double a = Math.Pow(x1 / x2, 1 / (x1 - x2)); + public SoyokazeDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap) : base(ruleset, beatmap) { @@ -34,16 +41,15 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat double speedRating = Math.Sqrt(skills[0].DifficultyValue()) * difficulty_multiplier; double readRating = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier; + double baseStarRating = speedRating + readRating + (speedRating - readRating) / 3; - double starRating = speedRating + readRating + (speedRating - readRating) / 3; - - int maxCombo = beatmap.HitObjects.Count; + double starRating = k * Math.Pow(a, baseStarRating); return new SoyokazeDifficultyAttributes { StarRating = starRating, Mods = mods, - MaxCombo = maxCombo, + MaxCombo = beatmap.HitObjects.Count, }; } @@ -51,10 +57,13 @@ protected override IEnumerable CreateDifficultyHitObjects(I { var diffObjects = new List(); - for (int i = 0; i < beatmap.HitObjects.Count - SoyokazeDifficultyHitObject.COUNT; i++) + for (int i = SoyokazeDifficultyHitObject.MIN_COUNT; i <= beatmap.HitObjects.Count; i++) { - var hitObjects = beatmap.HitObjects.Skip(i).Take(SoyokazeDifficultyHitObject.COUNT).ToArray(); - var diffObject = new SoyokazeDifficultyHitObject(clockRate, hitObjects, diffObjects, i); + int begin = Math.Max(0, i - SoyokazeDifficultyHitObject.MAX_COUNT); + int end = i; + var hitObjects = beatmap.HitObjects.Skip(begin).Take(end - begin).ToArray(); + var diffObject = new SoyokazeDifficultyHitObject(clockRate, hitObjects, diffObjects, i - SoyokazeDifficultyHitObject.MIN_COUNT); + diffObjects.Add(diffObject); }