From 3ec97121e1a62bbfdec75de21d0afa6d1b94098b Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 13 Jun 2023 19:41:39 +0900 Subject: [PATCH] Add ScoreV1 calculation for CatchRuleset --- .../Difficulty/CatchDifficultyCalculator.cs | 8 ++ .../Difficulty/CatchScoreV1Processor.cs | 133 ++++++++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 osu.Game.Rulesets.Catch/Difficulty/CatchScoreV1Processor.cs diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index 42cfde268e..fb7c4f05f4 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -25,9 +25,12 @@ namespace osu.Game.Rulesets.Catch.Difficulty public override int Version => 20220701; + private readonly IWorkingBeatmap workingBeatmap; + public CatchDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap) : base(ruleset, beatmap) { + workingBeatmap = beatmap; } protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) @@ -38,12 +41,17 @@ namespace osu.Game.Rulesets.Catch.Difficulty // this is the same as osu!, so there's potential to share the implementation... maybe double preempt = IBeatmapDifficultyInfo.DifficultyRange(beatmap.Difficulty.ApproachRate, 1800, 1200, 450) / clockRate; + CatchScoreV1Processor sv1Processor = new CatchScoreV1Processor(workingBeatmap.Beatmap, beatmap, mods); + return new CatchDifficultyAttributes { StarRating = Math.Sqrt(skills[0].DifficultyValue()) * star_scaling_factor, Mods = mods, ApproachRate = preempt > 1200.0 ? -(preempt - 1800.0) / 120.0 : -(preempt - 1200.0) / 150.0 + 5.0, MaxCombo = beatmap.HitObjects.Count(h => h is Fruit) + beatmap.HitObjects.OfType().SelectMany(j => j.NestedHitObjects).Count(h => !(h is TinyDroplet)), + LegacyTotalScore = sv1Processor.TotalScore, + LegacyComboScore = sv1Processor.ComboScore, + LegacyBonusScore = sv1Processor.BonusScore }; } diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchScoreV1Processor.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchScoreV1Processor.cs new file mode 100644 index 0000000000..b5c3838fdc --- /dev/null +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchScoreV1Processor.cs @@ -0,0 +1,133 @@ +// 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.Catch.Objects; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Types; + +namespace osu.Game.Rulesets.Catch.Difficulty +{ + internal class CatchScoreV1Processor + { + public int TotalScore => BaseScore + ComboScore + BonusScore; + + /// + /// Amount of score that is combo-and-difficulty-multiplied, excluding mod multipliers. + /// + public int ComboScore { get; private set; } + + /// + /// Amount of score that is NOT combo-and-difficulty-multiplied. + /// + public int BaseScore { get; private set; } + + /// + /// Amount of score whose judgements would be treated as "bonus" in ScoreV2. + /// + public int BonusScore { get; private set; } + + private int combo; + + private readonly double scoreMultiplier; + + public CatchScoreV1Processor(IBeatmap baseBeatmap, IBeatmap playableBeatmap, IReadOnlyList mods) + { + int countNormal = 0; + int countSlider = 0; + int countSpinner = 0; + + foreach (HitObject obj in baseBeatmap.HitObjects) + { + switch (obj) + { + case IHasPath: + countSlider++; + break; + + case IHasDuration: + countSpinner++; + break; + + default: + countNormal++; + break; + } + } + + int objectCount = countNormal + countSlider + countSpinner; + + int difficultyPeppyStars = (int)Math.Round( + (baseBeatmap.Difficulty.DrainRate + + baseBeatmap.Difficulty.OverallDifficulty + + baseBeatmap.Difficulty.CircleSize + + Math.Clamp(objectCount / baseBeatmap.Difficulty.DrainRate * 8, 0, 16)) / 38 * 5); + + scoreMultiplier = difficultyPeppyStars * mods.Aggregate(1.0, (current, mod) => current * mod.ScoreMultiplier); + + foreach (var obj in playableBeatmap.HitObjects) + simulateHit(obj); + } + + private void simulateHit(HitObject hitObject) + { + bool increaseCombo = true; + bool addScoreComboMultiplier = false; + bool isBonus = false; + + int scoreIncrease = 0; + + switch (hitObject) + { + case TinyDroplet: + scoreIncrease = 10; + increaseCombo = false; + break; + + case Droplet: + scoreIncrease = 100; + break; + + case Fruit: + scoreIncrease = 300; + addScoreComboMultiplier = true; + increaseCombo = true; + break; + + case Banana: + scoreIncrease = 1100; + increaseCombo = false; + isBonus = true; + break; + + case JuiceStream: + foreach (var nested in hitObject.NestedHitObjects) + simulateHit(nested); + return; + + case BananaShower: + foreach (var nested in hitObject.NestedHitObjects) + simulateHit(nested); + return; + } + + if (addScoreComboMultiplier) + { + // ReSharper disable once PossibleLossOfFraction (intentional to match osu-stable...) + ComboScore += (int)(Math.Max(0, combo - 1) * (scoreIncrease / 25 * scoreMultiplier)); + } + + if (isBonus) + BonusScore += scoreIncrease; + else + BaseScore += scoreIncrease; + + if (increaseCombo) + combo++; + } + } +}