2023-06-13 18:41:39 +08: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 System.Collections.Generic;
|
|
|
|
using System.Linq;
|
|
|
|
using osu.Game.Beatmaps;
|
|
|
|
using osu.Game.Rulesets.Catch.Objects;
|
2023-06-19 20:38:13 +08:00
|
|
|
using osu.Game.Rulesets.Judgements;
|
2023-06-13 18:41:39 +08:00
|
|
|
using osu.Game.Rulesets.Mods;
|
|
|
|
using osu.Game.Rulesets.Objects;
|
|
|
|
using osu.Game.Rulesets.Objects.Types;
|
2023-06-19 20:38:13 +08:00
|
|
|
using osu.Game.Rulesets.Scoring;
|
2023-06-13 18:41:39 +08:00
|
|
|
|
|
|
|
namespace osu.Game.Rulesets.Catch.Difficulty
|
|
|
|
{
|
|
|
|
internal class CatchScoreV1Processor
|
|
|
|
{
|
|
|
|
/// <summary>
|
2023-06-19 20:38:13 +08:00
|
|
|
/// The accuracy portion of the legacy (ScoreV1) total score.
|
2023-06-13 18:41:39 +08:00
|
|
|
/// </summary>
|
2023-06-19 20:38:13 +08:00
|
|
|
public int AccuracyScore { get; private set; }
|
2023-06-13 18:41:39 +08:00
|
|
|
|
|
|
|
/// <summary>
|
2023-06-19 20:38:13 +08:00
|
|
|
/// The combo-multiplied portion of the legacy (ScoreV1) total score.
|
2023-06-13 18:41:39 +08:00
|
|
|
/// </summary>
|
2023-06-19 20:38:13 +08:00
|
|
|
public int ComboScore { get; private set; }
|
2023-06-13 18:41:39 +08:00
|
|
|
|
|
|
|
/// <summary>
|
2023-06-19 20:38:13 +08:00
|
|
|
/// A ratio of <c>new_bonus_score / old_bonus_score</c> for converting the bonus score of legacy scores to the new scoring.
|
|
|
|
/// This is made up of all judgements that would be <see cref="HitResult.SmallBonus"/> or <see cref="HitResult.LargeBonus"/>.
|
2023-06-13 18:41:39 +08:00
|
|
|
/// </summary>
|
2023-06-19 20:38:13 +08:00
|
|
|
public double BonusScoreRatio => legacyBonusScore == 0 ? 0 : (double)modernBonusScore / legacyBonusScore;
|
2023-06-13 18:41:39 +08:00
|
|
|
|
2023-06-19 20:38:13 +08:00
|
|
|
private int legacyBonusScore;
|
|
|
|
private int modernBonusScore;
|
2023-06-13 18:41:39 +08:00
|
|
|
private int combo;
|
|
|
|
|
|
|
|
private readonly double scoreMultiplier;
|
|
|
|
|
|
|
|
public CatchScoreV1Processor(IBeatmap baseBeatmap, IBeatmap playableBeatmap, IReadOnlyList<Mod> 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;
|
2023-06-19 20:38:13 +08:00
|
|
|
|
2023-06-13 18:41:39 +08:00
|
|
|
bool isBonus = false;
|
2023-06-19 20:38:13 +08:00
|
|
|
HitResult bonusResult = HitResult.None;
|
2023-06-13 18:41:39 +08:00
|
|
|
|
|
|
|
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;
|
2023-06-19 20:38:13 +08:00
|
|
|
bonusResult = HitResult.LargeBonus;
|
2023-06-13 18:41:39 +08:00
|
|
|
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)
|
2023-06-19 20:38:13 +08:00
|
|
|
{
|
|
|
|
legacyBonusScore += scoreIncrease;
|
|
|
|
modernBonusScore += Judgement.ToNumericResult(bonusResult);
|
|
|
|
}
|
2023-06-13 18:41:39 +08:00
|
|
|
else
|
2023-06-19 20:38:13 +08:00
|
|
|
AccuracyScore += scoreIncrease;
|
2023-06-13 18:41:39 +08:00
|
|
|
|
|
|
|
if (increaseCombo)
|
|
|
|
combo++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|