// Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Game.Rulesets.Objects.Types; using System; namespace osu.Game.Rulesets.Mania.Objects { internal class ManiaHitObjectDifficulty { /// /// Factor by how much individual / overall strain decays per second. /// /// /// These values are results of tweaking a lot and taking into account general feedback. /// internal const double INDIVIDUAL_DECAY_BASE = 0.125; internal const double OVERALL_DECAY_BASE = 0.30; internal ManiaHitObject BaseHitObject; private readonly int beatmapColumnCount; private readonly double endTime; private readonly double[] heldUntil; /// /// Measures jacks or more generally: repeated presses of the same button /// private readonly double[] individualStrains; internal double IndividualStrain { get { return individualStrains[BaseHitObject.Column]; } set { individualStrains[BaseHitObject.Column] = value; } } /// /// Measures note density in a way /// internal double OverallStrain = 1; public ManiaHitObjectDifficulty(ManiaHitObject baseHitObject, int columnCount) { BaseHitObject = baseHitObject; endTime = (baseHitObject as IHasEndTime)?.EndTime ?? baseHitObject.StartTime; beatmapColumnCount = columnCount; heldUntil = new double[beatmapColumnCount]; individualStrains = new double[beatmapColumnCount]; for (int i = 0; i < beatmapColumnCount; ++i) { individualStrains[i] = 0; heldUntil[i] = 0; } } internal void CalculateStrains(ManiaHitObjectDifficulty previousHitObject, double timeRate) { // TODO: Factor in holds double timeElapsed = (BaseHitObject.StartTime - previousHitObject.BaseHitObject.StartTime) / timeRate; double individualDecay = Math.Pow(INDIVIDUAL_DECAY_BASE, timeElapsed / 1000); double overallDecay = Math.Pow(OVERALL_DECAY_BASE, timeElapsed / 1000); double holdFactor = 1.0; // Factor to all additional strains in case something else is held double holdAddition = 0; // Addition to the current note in case it's a hold and has to be released awkwardly // Fill up the heldUntil array for (int i = 0; i < beatmapColumnCount; ++i) { heldUntil[i] = previousHitObject.heldUntil[i]; // If there is at least one other overlapping end or note, then we get an addition, buuuuuut... if (BaseHitObject.StartTime < heldUntil[i] && endTime > heldUntil[i]) { holdAddition = 1.0; } // ... this addition only is valid if there is _no_ other note with the same ending. Releasing multiple notes at the same time is just as easy as releasing 1 if (endTime == heldUntil[i]) { holdAddition = 0; } // We give a slight bonus to everything if something is held meanwhile if (heldUntil[i] > endTime) { holdFactor = 1.25; } // Decay individual strains individualStrains[i] = previousHitObject.individualStrains[i] * individualDecay; } heldUntil[BaseHitObject.Column] = endTime; // Increase individual strain in own column IndividualStrain += 2.0 * holdFactor; OverallStrain = previousHitObject.OverallStrain * overallDecay + (1.0 + holdAddition) * holdFactor; } } }