// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System; using System.Collections.Generic; using System.Linq; using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing; using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour; using osu.Game.Rulesets.Taiko.Difficulty.Skills; using osu.Game.Rulesets.Taiko.Mods; using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Rulesets.Taiko.Scoring; namespace osu.Game.Rulesets.Taiko.Difficulty { public class TaikoDifficultyCalculator : DifficultyCalculator { private const double difficulty_multiplier = 1.35; public override int Version => 20220902; private readonly IWorkingBeatmap workingBeatmap; public TaikoDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap) : base(ruleset, beatmap) { workingBeatmap = beatmap; } protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods, double clockRate) { return new Skill[] { new Peaks(mods) }; } protected override Mod[] DifficultyAdjustmentMods => new Mod[] { new TaikoModDoubleTime(), new TaikoModHalfTime(), new TaikoModEasy(), new TaikoModHardRock(), }; protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) { List difficultyHitObjects = new List(); List centreObjects = new List(); List rimObjects = new List(); List noteObjects = new List(); for (int i = 2; i < beatmap.HitObjects.Count; i++) { difficultyHitObjects.Add( new TaikoDifficultyHitObject( beatmap.HitObjects[i], beatmap.HitObjects[i - 1], beatmap.HitObjects[i - 2], clockRate, difficultyHitObjects, centreObjects, rimObjects, noteObjects, difficultyHitObjects.Count) ); } TaikoColourDifficultyPreprocessor.ProcessAndAssign(difficultyHitObjects); return difficultyHitObjects; } protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) { if (beatmap.HitObjects.Count == 0) return new TaikoDifficultyAttributes { Mods = mods }; var combined = (Peaks)skills[0]; double colourRating = combined.ColourDifficultyValue * difficulty_multiplier; double rhythmRating = combined.RhythmDifficultyValue * difficulty_multiplier; double staminaRating = combined.StaminaDifficultyValue * difficulty_multiplier; double combinedRating = combined.DifficultyValue() * difficulty_multiplier; double starRating = rescale(combinedRating * 1.4); HitWindows hitWindows = new TaikoHitWindows(); hitWindows.SetDifficulty(beatmap.Difficulty.OverallDifficulty); TaikoDifficultyAttributes attributes = new TaikoDifficultyAttributes { StarRating = starRating, Mods = mods, StaminaDifficulty = staminaRating, RhythmDifficulty = rhythmRating, ColourDifficulty = colourRating, PeakDifficulty = combinedRating, GreatHitWindow = hitWindows.WindowFor(HitResult.Great) / clockRate, MaxCombo = beatmap.HitObjects.Count(h => h is Hit), }; if (ComputeLegacyScoringValues) { TaikoLegacyScoreSimulator sv1Simulator = new TaikoLegacyScoreSimulator(); sv1Simulator.Simulate(workingBeatmap, beatmap, mods); attributes.LegacyAccuracyScore = sv1Simulator.AccuracyScore; attributes.LegacyComboScore = sv1Simulator.ComboScore; attributes.LegacyBonusScoreRatio = sv1Simulator.BonusScoreRatio; } return attributes; } /// /// Applies a final re-scaling of the star rating. /// /// The raw star rating value before re-scaling. private double rescale(double sr) { if (sr < 0) return sr; return 10.43 * Math.Log(sr / 8 + 1); } } }