|
|
|
@ -121,7 +121,7 @@ namespace osu.Game.Rulesets.Scoring
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// The maximum <see cref="HitResult"/> of a basic (non-tick and non-bonus) hitobject.
|
|
|
|
|
/// Only populated via <see cref="ComputeFinalScore"/> or <see cref="ResetFromReplayFrame"/>.
|
|
|
|
|
/// Only populated via <see cref="ComputeScore(osu.Game.Rulesets.Scoring.ScoringMode,osu.Game.Scoring.ScoreInfo)"/> or <see cref="ResetFromReplayFrame"/>.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private HitResult? maxBasicResult;
|
|
|
|
|
|
|
|
|
@ -281,7 +281,7 @@ namespace osu.Game.Rulesets.Scoring
|
|
|
|
|
/// <param name="scoreInfo">The <see cref="ScoreInfo"/> to compute the total score of.</param>
|
|
|
|
|
/// <returns>The total score in the given <see cref="ScoringMode"/>.</returns>
|
|
|
|
|
[Pure]
|
|
|
|
|
public double ComputeFinalScore(ScoringMode mode, ScoreInfo scoreInfo)
|
|
|
|
|
public double ComputeScore(ScoringMode mode, ScoreInfo scoreInfo)
|
|
|
|
|
{
|
|
|
|
|
if (!ruleset.RulesetInfo.Equals(scoreInfo.Ruleset))
|
|
|
|
|
throw new ArgumentException($"Unexpected score ruleset. Expected \"{ruleset.RulesetInfo.ShortName}\" but was \"{scoreInfo.Ruleset.ShortName}\".");
|
|
|
|
@ -291,60 +291,6 @@ namespace osu.Game.Rulesets.Scoring
|
|
|
|
|
return ComputeScore(mode, current, maximum);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Computes the total score of a partially-completed <see cref="ScoreInfo"/>. This should be used when it is unknown whether a score is complete.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <remarks>
|
|
|
|
|
/// Requires <see cref="JudgementProcessor.ApplyBeatmap"/> to have been called before use.
|
|
|
|
|
/// </remarks>
|
|
|
|
|
/// <param name="mode">The <see cref="ScoringMode"/> to represent the score as.</param>
|
|
|
|
|
/// <param name="scoreInfo">The <see cref="ScoreInfo"/> to compute the total score of.</param>
|
|
|
|
|
/// <returns>The total score in the given <see cref="ScoringMode"/>.</returns>
|
|
|
|
|
[Pure]
|
|
|
|
|
public double ComputePartialScore(ScoringMode mode, ScoreInfo scoreInfo)
|
|
|
|
|
{
|
|
|
|
|
if (!ruleset.RulesetInfo.Equals(scoreInfo.Ruleset))
|
|
|
|
|
throw new ArgumentException($"Unexpected score ruleset. Expected \"{ruleset.RulesetInfo.ShortName}\" but was \"{scoreInfo.Ruleset.ShortName}\".");
|
|
|
|
|
|
|
|
|
|
if (!beatmapApplied)
|
|
|
|
|
throw new InvalidOperationException($"Cannot compute partial score without calling {nameof(ApplyBeatmap)}.");
|
|
|
|
|
|
|
|
|
|
ExtractScoringValues(scoreInfo, out var current, out _);
|
|
|
|
|
|
|
|
|
|
return ComputeScore(mode, current, MaximumScoringValues);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Computes the total score of a given <see cref="ScoreInfo"/> with a given custom max achievable combo.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <remarks>
|
|
|
|
|
/// This is useful for processing legacy scores in which the maximum achievable combo can be more accurately determined via external means (e.g. database values or difficulty calculation).
|
|
|
|
|
/// <p>Does not require <see cref="JudgementProcessor.ApplyBeatmap"/> to have been called before use.</p>
|
|
|
|
|
/// </remarks>
|
|
|
|
|
/// <param name="mode">The <see cref="ScoringMode"/> to represent the score as.</param>
|
|
|
|
|
/// <param name="scoreInfo">The <see cref="ScoreInfo"/> to compute the total score of.</param>
|
|
|
|
|
/// <param name="maxAchievableCombo">The maximum achievable combo for the provided beatmap.</param>
|
|
|
|
|
/// <returns>The total score in the given <see cref="ScoringMode"/>.</returns>
|
|
|
|
|
[Pure]
|
|
|
|
|
public double ComputeFinalLegacyScore(ScoringMode mode, ScoreInfo scoreInfo, int maxAchievableCombo)
|
|
|
|
|
{
|
|
|
|
|
if (!ruleset.RulesetInfo.Equals(scoreInfo.Ruleset))
|
|
|
|
|
throw new ArgumentException($"Unexpected score ruleset. Expected \"{ruleset.RulesetInfo.ShortName}\" but was \"{scoreInfo.Ruleset.ShortName}\".");
|
|
|
|
|
|
|
|
|
|
double accuracyRatio = scoreInfo.Accuracy;
|
|
|
|
|
double comboRatio = maxAchievableCombo > 0 ? (double)scoreInfo.MaxCombo / maxAchievableCombo : 1;
|
|
|
|
|
|
|
|
|
|
ExtractScoringValues(scoreInfo, out var current, out var maximum);
|
|
|
|
|
|
|
|
|
|
// For legacy osu!mania scores, a full-GREAT score has 100% accuracy. If combined with a full-combo, the score becomes indistinguishable from a full-PERFECT score.
|
|
|
|
|
// To get around this, the accuracy ratio is always recalculated based on the hit statistics rather than trusting the score.
|
|
|
|
|
// Note: This cannot be applied universally to all legacy scores, as some rulesets (e.g. catch) group multiple judgements together.
|
|
|
|
|
if (scoreInfo.IsLegacyScore && scoreInfo.Ruleset.OnlineID == 3 && maximum.BaseScore > 0)
|
|
|
|
|
accuracyRatio = current.BaseScore / maximum.BaseScore;
|
|
|
|
|
|
|
|
|
|
return ComputeScore(mode, accuracyRatio, comboRatio, current.BonusScore, maximum.CountBasicHitObjects);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Computes the total score from scoring values.
|
|
|
|
|
/// </summary>
|
|
|
|
@ -454,7 +400,7 @@ namespace osu.Game.Rulesets.Scoring
|
|
|
|
|
score.MaximumStatistics[result] = maximumResultCounts.GetValueOrDefault(result);
|
|
|
|
|
|
|
|
|
|
// Populate total score after everything else.
|
|
|
|
|
score.TotalScore = (long)Math.Round(ComputeFinalScore(ScoringMode.Standardised, score));
|
|
|
|
|
score.TotalScore = (long)Math.Round(ComputeScore(ScoringMode.Standardised, score));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|