diff --git a/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs b/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs index dc6d5b28ee..c74d4b84e4 100644 --- a/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs +++ b/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs @@ -17,51 +17,48 @@ namespace osu.Game.Rulesets.Catch.Scoring private int maximumTinyDroplets; private int hitTinyDroplets; + private int maximumBasicJudgements; + private int currentBasicJudgements; public CatchScoreProcessor() : base(new CatchRuleset()) { } - protected override double ComputeTotalScore() + protected override double ComputeTotalScore(double comboRatio, double accuracyRatio, double bonusPortion) { - double comboRatio = MaxComboPortion > 0 ? ComboPortion / MaxComboPortion : 1; double fruitHitsRatio = maximumTinyDroplets == 0 ? 0 : (double)hitTinyDroplets / maximumTinyDroplets; const int tiny_droplets_portion = 400000; - return ( - ((1000000 - tiny_droplets_portion) + tiny_droplets_portion * (1 - tinyDropletScale)) * comboRatio + - tiny_droplets_portion * tinyDropletScale * fruitHitsRatio + - BonusPortion - ) * ScoreMultiplier; + return ((1000000 - tiny_droplets_portion) + tiny_droplets_portion * (1 - tinyDropletScale)) * comboRatio + + tiny_droplets_portion * tinyDropletScale * fruitHitsRatio + + bonusPortion; } - protected override void AddScoreChange(JudgementResult result) + protected override double GetComboScoreChange(JudgementResult result) + => Judgement.ToNumericResult(result.Type) * Math.Min(Math.Max(0.5, Math.Log(result.ComboAfterJudgement, combo_base)), Math.Log(combo_cap, combo_base)); + + protected override void ApplyScoreChange(JudgementResult result) { - var change = computeScoreChange(result); - ComboPortion += change.combo; - BonusPortion += change.bonus; - hitTinyDroplets += change.tinyDropletHits; + base.ApplyScoreChange(result); + + if (result.HitObject is TinyDroplet) + hitTinyDroplets++; + + if (result.Type.IsBasic()) + currentBasicJudgements++; } protected override void RemoveScoreChange(JudgementResult result) { - var change = computeScoreChange(result); - ComboPortion -= change.combo; - BonusPortion -= change.bonus; - hitTinyDroplets -= change.tinyDropletHits; - } + base.RemoveScoreChange(result); - private (double combo, double bonus, int tinyDropletHits) computeScoreChange(JudgementResult result) - { if (result.HitObject is TinyDroplet) - return (0, 0, 1); + hitTinyDroplets--; - if (result.Type.IsBonus()) - return (0, Judgement.ToNumericResult(result.Type), 0); - - return (Judgement.ToNumericResult(result.Type) * Math.Min(Math.Max(0.5, Math.Log(result.ComboAfterJudgement, combo_base)), Math.Log(combo_cap, combo_base)), 0, 0); + if (result.Type.IsBasic()) + currentBasicJudgements--; } protected override void Reset(bool storeResults) @@ -71,14 +68,16 @@ namespace osu.Game.Rulesets.Catch.Scoring if (storeResults) { maximumTinyDroplets = hitTinyDroplets; + maximumBasicJudgements = currentBasicJudgements; - if (maximumTinyDroplets + MaxBasicJudgements == 0) + if (maximumTinyDroplets + maximumBasicJudgements == 0) tinyDropletScale = 0; else - tinyDropletScale = (double)maximumTinyDroplets / (maximumTinyDroplets + MaxBasicJudgements); + tinyDropletScale = (double)maximumTinyDroplets / (maximumTinyDroplets + maximumBasicJudgements); } hitTinyDroplets = 0; + currentBasicJudgements = 0; } } } diff --git a/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs b/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs index 544b9add32..214aded2d7 100644 --- a/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs +++ b/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs @@ -16,38 +16,14 @@ namespace osu.Game.Rulesets.Mania.Scoring { } - protected override double ComputeTotalScore() + protected override double ComputeTotalScore(double comboRatio, double accuracyRatio, double bonusPortion) { - double comboRatio = MaxComboPortion > 0 ? ComboPortion / MaxComboPortion : 1; - double accuracyRatio = MaxBasicJudgements > 0 ? (double)CurrentBasicJudgements / MaxBasicJudgements : 1; - - return ( - 200000 * comboRatio + - 800000 * Math.Pow(Accuracy.Value, 2 + 2 * Accuracy.Value) * accuracyRatio + - BonusPortion - ) * ScoreMultiplier; + return 200000 * comboRatio + + 800000 * Math.Pow(Accuracy.Value, 2 + 2 * Accuracy.Value) * accuracyRatio + + bonusPortion; } - protected override void AddScoreChange(JudgementResult result) - { - var change = computeScoreChange(result); - ComboPortion += change.combo; - BonusPortion += change.bonus; - } - - protected override void RemoveScoreChange(JudgementResult result) - { - var change = computeScoreChange(result); - ComboPortion -= change.combo; - BonusPortion -= change.bonus; - } - - private (double combo, double bonus) computeScoreChange(JudgementResult result) - { - if (result.Type.IsBonus()) - return (0, Judgement.ToNumericResult(result.Type)); - - return (Judgement.ToNumericResult(result.Type) * Math.Min(Math.Max(0.5, Math.Log(result.ComboAfterJudgement, combo_base)), Math.Log(400, combo_base)), 0); - } + protected override double GetComboScoreChange(JudgementResult result) + => Judgement.ToNumericResult(result.Type) * Math.Min(Math.Max(0.5, Math.Log(result.ComboAfterJudgement, combo_base)), Math.Log(400, combo_base)); } } diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs index edd0880271..5028d5b8d6 100644 --- a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs +++ b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs @@ -13,16 +13,11 @@ namespace osu.Game.Rulesets.Osu.Scoring { } - protected override double ComputeTotalScore() + protected override double ComputeTotalScore(double comboRatio, double accuracyRatio, double bonusPortion) { - double comboRatio = MaxComboPortion > 0 ? ComboPortion / MaxComboPortion : 1; - double accuracyRatio = MaxBasicJudgements > 0 ? (double)CurrentBasicJudgements / MaxBasicJudgements : 1; - - return ( - 700000 * comboRatio + - 300000 * Math.Pow(Accuracy.Value, 10) * accuracyRatio + - BonusPortion - ) * ScoreMultiplier; + return 700000 * comboRatio + + 300000 * Math.Pow(Accuracy.Value, 10) * accuracyRatio + + bonusPortion; } } } diff --git a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs index 32f4421ed2..e0f83505cf 100644 --- a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs +++ b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs @@ -17,46 +17,28 @@ namespace osu.Game.Rulesets.Taiko.Scoring { } - protected override double ComputeTotalScore() + protected override double ComputeTotalScore(double comboRatio, double accuracyRatio, double bonusPortion) { - double comboRatio = MaxComboPortion > 0 ? ComboPortion / MaxComboPortion : 1; - double accuracyRatio = MaxBasicJudgements > 0 ? (double)CurrentBasicJudgements / MaxBasicJudgements : 1; - - return ( - 250000 * comboRatio + - 750000 * Math.Pow(Accuracy.Value, 3.6) * accuracyRatio + - BonusPortion - ) * ScoreMultiplier; + return 250000 * comboRatio + + 750000 * Math.Pow(Accuracy.Value, 3.6) * accuracyRatio + + bonusPortion; } - protected override void AddScoreChange(JudgementResult result) + protected override double GetBonusScoreChange(JudgementResult result) => base.GetBonusScoreChange(result) * strongScaleValue(result); + + protected override double GetComboScoreChange(JudgementResult result) { - var change = computeScoreChange(result); - ComboPortion += change.combo; - BonusPortion += change.bonus; + return Judgement.ToNumericResult(result.Type) + * Math.Min(Math.Max(0.5, Math.Log(result.ComboAfterJudgement, combo_base)), Math.Log(400, combo_base)) + * strongScaleValue(result); } - protected override void RemoveScoreChange(JudgementResult result) + private double strongScaleValue(JudgementResult result) { - var change = computeScoreChange(result); - ComboPortion -= change.combo; - BonusPortion -= change.bonus; - } - - private (double combo, double bonus) computeScoreChange(JudgementResult result) - { - double hitValue = Judgement.ToNumericResult(result.Type); - if (result.HitObject is StrongNestedHitObject strong) - { - double strongBonus = strong.Parent is DrumRollTick ? 3 : 7; - hitValue *= strongBonus; - } + return strong.Parent is DrumRollTick ? 3 : 7; - if (result.Type.IsBonus()) - return (0, hitValue); - - return (hitValue * Math.Min(Math.Max(0.5, Math.Log(result.ComboAfterJudgement, combo_base)), Math.Log(400, combo_base)), 0); + return 1; } } } diff --git a/osu.Game/Rulesets/Difficulty/PerformanceBreakdownCalculator.cs b/osu.Game/Rulesets/Difficulty/PerformanceBreakdownCalculator.cs index 3dd7f934a8..64a04f896f 100644 --- a/osu.Game/Rulesets/Difficulty/PerformanceBreakdownCalculator.cs +++ b/osu.Game/Rulesets/Difficulty/PerformanceBreakdownCalculator.cs @@ -68,7 +68,7 @@ namespace osu.Game.Rulesets.Difficulty ScoreProcessor scoreProcessor = ruleset.CreateScoreProcessor(); scoreProcessor.Mods.Value = perfectPlay.Mods; scoreProcessor.ApplyBeatmap(playableBeatmap); - perfectPlay.TotalScore = scoreProcessor.MaxTotalScore; + perfectPlay.TotalScore = scoreProcessor.MaximumTotalScore; // compute rank achieved // default to SS, then adjust the rank with mods diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 0ec9c884c3..a94ee9c181 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -90,10 +90,18 @@ namespace osu.Game.Rulesets.Scoring /// /// The maximum achievable total score. /// - public long MaxTotalScore { get; private set; } + public long MaximumTotalScore { get; private set; } /// - /// The sum of all accuracy-affecting judgements at the current time. + /// The maximum sum of accuracy-affecting judgements at the current point in time. + /// + /// + /// Used to compute accuracy. + /// + private double currentMaximumBaseScore; + + /// + /// The sum of all accuracy-affecting judgements at the current point in time. /// /// /// Used to compute accuracy. @@ -101,42 +109,34 @@ namespace osu.Game.Rulesets.Scoring private double currentBaseScore; /// - /// The maximum sum of accuracy-affecting judgements at the current time. + /// The count of all basic judgements in the beatmap. /// - /// - /// Used to compute accuracy. - /// - private double currentMaxBaseScore; + private int maximumCountBasicJudgements; /// - /// The total count of basic judgements in the beatmap. + /// The count of basic judgements at the current point in time. /// - protected int MaxBasicJudgements { get; private set; } + private int currentCountBasicJudgements; /// - /// The current count of basic judgements by the player. + /// The maximum combo score in the beatmap. /// - protected int CurrentBasicJudgements { get; private set; } + private double maximumComboPortion; /// - /// The current combo score. + /// The combo score at the current point in time. /// - protected double ComboPortion { get; set; } + private double currentComboPortion; /// - /// The maximum achievable combo score. + /// The bonus score at the current point in time. /// - protected double MaxComboPortion { get; private set; } - - /// - /// The current bonus score. - /// - protected double BonusPortion { get; set; } + private double currentBonusPortion; /// /// The total score multiplier. /// - protected double ScoreMultiplier { get; private set; } = 1; + private double scoreMultiplier = 1; public Dictionary MaximumStatistics { @@ -171,10 +171,10 @@ namespace osu.Game.Rulesets.Scoring Mods.ValueChanged += mods => { - ScoreMultiplier = 1; + scoreMultiplier = 1; foreach (var m in mods.NewValue) - ScoreMultiplier *= m.ScoreMultiplier; + scoreMultiplier *= m.ScoreMultiplier; updateScore(); }; @@ -207,15 +207,21 @@ namespace osu.Game.Rulesets.Scoring result.ComboAfterJudgement = Combo.Value; if (result.Type.IsBasic()) - CurrentBasicJudgements++; + currentCountBasicJudgements++; if (result.Type.AffectsAccuracy()) { - currentMaxBaseScore += Judgement.ToNumericResult(result.Judgement.MaxResult); + currentMaximumBaseScore += Judgement.ToNumericResult(result.Judgement.MaxResult); currentBaseScore += Judgement.ToNumericResult(result.Type); } - AddScoreChange(result); + if (result.Type.IsBonus()) + currentBonusPortion += GetBonusScoreChange(result); + + if (result.Type.AffectsCombo()) + currentComboPortion += GetComboScoreChange(result); + + ApplyScoreChange(result); hitEvents.Add(CreateHitEvent(result)); lastHitObject = result.HitObject; @@ -245,14 +251,20 @@ namespace osu.Game.Rulesets.Scoring return; if (result.Type.IsBasic()) - CurrentBasicJudgements--; + currentCountBasicJudgements--; if (result.Type.AffectsAccuracy()) { - currentMaxBaseScore -= Judgement.ToNumericResult(result.Judgement.MaxResult); + currentMaximumBaseScore -= Judgement.ToNumericResult(result.Judgement.MaxResult); currentBaseScore -= Judgement.ToNumericResult(result.Type); } + if (result.Type.IsBonus()) + currentBonusPortion -= GetBonusScoreChange(result); + + if (result.Type.AffectsCombo()) + currentComboPortion -= GetComboScoreChange(result); + RemoveScoreChange(result); Debug.Assert(hitEvents.Count > 0); @@ -262,42 +274,37 @@ namespace osu.Game.Rulesets.Scoring updateScore(); } - protected virtual void AddScoreChange(JudgementResult result) - { - if (result.Type.IsBonus()) - BonusPortion += Judgement.ToNumericResult(result.Type); + protected virtual double GetBonusScoreChange(JudgementResult result) => Judgement.ToNumericResult(result.Type); - if (result.Type.AffectsCombo()) - ComboPortion += Judgement.ToNumericResult(result.Type) * (1 + result.ComboAfterJudgement / 10d); + protected virtual double GetComboScoreChange(JudgementResult result) => Judgement.ToNumericResult(result.Type) * (1 + result.ComboAfterJudgement / 10d); + + protected virtual void ApplyScoreChange(JudgementResult result) + { } protected virtual void RemoveScoreChange(JudgementResult result) { - if (result.Type.IsBonus()) - BonusPortion -= Judgement.ToNumericResult(result.Type); - - if (result.Type.AffectsCombo()) - ComboPortion -= Judgement.ToNumericResult(result.Type) * (1 + result.ComboAfterJudgement / 10d); } private void updateScore() { - Accuracy.Value = currentMaxBaseScore > 0 ? currentBaseScore / currentMaxBaseScore : 1; - TotalScore.Value = (long)Math.Round(ComputeTotalScore()); + Accuracy.Value = currentMaximumBaseScore > 0 ? currentBaseScore / currentMaximumBaseScore : 1; + + double comboRatio = maximumComboPortion > 0 ? currentComboPortion / maximumComboPortion : 1; + double accuracyRatio = maximumCountBasicJudgements > 0 ? (double)currentCountBasicJudgements / maximumCountBasicJudgements : 1; + + TotalScore.Value = (long)Math.Round(ComputeTotalScore(comboRatio, accuracyRatio, currentBonusPortion) * scoreMultiplier); } - protected virtual double ComputeTotalScore() + protected virtual double ComputeTotalScore(double comboRatio, double accuracyRatio, double bonusPortion) { - double comboRatio = MaxComboPortion > 0 ? ComboPortion / MaxComboPortion : 1; - double accuracyRatio = MaxBasicJudgements > 0 ? (double)CurrentBasicJudgements / MaxBasicJudgements : 1; - return (int)Math.Round (( 700000 * comboRatio + 300000 * Math.Pow(Accuracy.Value, 10) * accuracyRatio + - BonusPortion - ) * ScoreMultiplier); + bonusPortion + ) * scoreMultiplier); } /// @@ -313,22 +320,22 @@ namespace osu.Game.Rulesets.Scoring if (storeResults) { - MaxComboPortion = ComboPortion; - MaxBasicJudgements = CurrentBasicJudgements; + maximumComboPortion = currentComboPortion; + maximumCountBasicJudgements = currentCountBasicJudgements; maximumResultCounts.Clear(); maximumResultCounts.AddRange(scoreResultCounts); - MaxTotalScore = TotalScore.Value; + MaximumTotalScore = TotalScore.Value; } scoreResultCounts.Clear(); currentBaseScore = 0; - currentMaxBaseScore = 0; - CurrentBasicJudgements = 0; - ComboPortion = 0; - BonusPortion = 0; + currentMaximumBaseScore = 0; + currentCountBasicJudgements = 0; + currentComboPortion = 0; + currentBonusPortion = 0; TotalScore.Value = 0; Accuracy.Value = 1; @@ -338,7 +345,7 @@ namespace osu.Game.Rulesets.Scoring HighestCombo.Value = 0; currentBaseScore = 0; - currentMaxBaseScore = 0; + currentMaximumBaseScore = 0; } ///