// Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Configuration; using System; using System.Collections.Generic; using osu.Game.Modes.Judgements; using osu.Game.Modes.UI; using osu.Game.Modes.Objects; namespace osu.Game.Modes { public abstract class ScoreProcessor { public virtual Score GetScore() => new Score { TotalScore = TotalScore, Combo = Combo, MaxCombo = HighestCombo, Accuracy = Accuracy, Health = Health, }; public readonly BindableDouble TotalScore = new BindableDouble { MinValue = 0 }; public readonly BindableDouble Accuracy = new BindableDouble { MinValue = 0, MaxValue = 1 }; public readonly BindableDouble Health = new BindableDouble { MinValue = 0, MaxValue = 1 }; public readonly BindableInt Combo = new BindableInt(); /// /// Keeps track of the highest combo ever achieved in this play. /// This is handled automatically by ScoreProcessor. /// public readonly BindableInt HighestCombo = new BindableInt(); /// /// Called when we reach a failing health of zero. /// public event Action Failed; /// /// Notifies subscribers that the score is in a failed state. /// protected void TriggerFailed() { Failed?.Invoke(); } } public abstract class ScoreProcessor : ScoreProcessor where TObject : HitObject where TJudgement : JudgementInfo { /// /// All judgements held by this ScoreProcessor. /// protected List Judgements; /// /// Are we allowed to fail? /// protected bool CanFail => true; /// /// Whether this ScoreProcessor has already triggered the failed event. /// protected bool HasFailed { get; private set; } protected ScoreProcessor(HitRenderer hitRenderer) { Combo.ValueChanged += delegate { HighestCombo.Value = Math.Max(HighestCombo.Value, Combo.Value); }; Judgements = new List(hitRenderer.Beatmap.HitObjects.Count); hitRenderer.OnJudgement += addJudgement; } private void addJudgement(TJudgement judgement) { Judgements.Add(judgement); UpdateCalculations(judgement); judgement.ComboAtHit = (ulong)Combo.Value; if (Health.Value == Health.MinValue && !HasFailed) { HasFailed = true; TriggerFailed(); } } /// /// Update any values that potentially need post-processing on a judgement change. /// /// A new JudgementInfo that triggered this calculation. May be null. protected abstract void UpdateCalculations(TJudgement newJudgement); } }