private void CalculateSpecificStrain(DifficultyHitObjectOsu PreviousHitObject, BeatmapDifficultyCalculatorOsu.DifficultyType Type, double TimeRate) { double Addition = 0; double TimeElapsed = (double)(BaseHitObject.StartTime - PreviousHitObject.BaseHitObject.StartTime) / TimeRate; double Decay = Math.Pow(DECAY_BASE[(int)Type], TimeElapsed / 1000); if (BaseHitObject.IsType(HitObjectType.Spinner)) { // Do nothing for spinners } else if (BaseHitObject.IsType(HitObjectType.Slider)) { switch (Type) { case BeatmapDifficultyCalculatorOsu.DifficultyType.Speed: // For speed strain we treat the whole slider as a single spacing entity, since "Speed" is about how hard it is to click buttons fast. // The spacing weight exists to differentiate between being able to easily alternate or having to single. Addition = SpacingWeight(PreviousHitObject.LazySliderLengthFirst + PreviousHitObject.LazySliderLengthSubsequent * (PreviousHitObject.BaseHitObject.SegmentCount - 1) + DistanceTo(PreviousHitObject), Type) * SPACING_WEIGHT_SCALING[(int)Type]; break; case BeatmapDifficultyCalculatorOsu.DifficultyType.Aim: // For Aim strain we treat each slider segment and the jump after the end of the slider as separate jumps, since movement-wise there is no difference // to multiple jumps. Addition = ( SpacingWeight(PreviousHitObject.LazySliderLengthFirst, Type) + SpacingWeight(PreviousHitObject.LazySliderLengthSubsequent, Type) * (PreviousHitObject.BaseHitObject.SegmentCount - 1) + SpacingWeight(DistanceTo(PreviousHitObject), Type) ) * SPACING_WEIGHT_SCALING[(int)Type]; break; } } else if (BaseHitObject.IsType(HitObjectType.Normal)) { Addition = SpacingWeight(DistanceTo(PreviousHitObject), Type) * SPACING_WEIGHT_SCALING[(int)Type]; } // Scale addition by the time, that elapsed. Filter out HitObjects that are too close to be played anyway to avoid crazy values by division through close to zero. // You will never find maps that require this amongst ranked maps. Addition /= Math.Max(TimeElapsed, 50); Strains[(int)Type] = PreviousHitObject.Strains[(int)Type] * Decay + Addition; }
internal double DistanceTo(DifficultyHitObjectOsu other) { // Scale the distance by circle size. return((NormalizedStartPosition - other.NormalizedEndPosition).Length()); }
internal void CalculateStrains(DifficultyHitObjectOsu PreviousHitObject, double TimeRate) { CalculateSpecificStrain(PreviousHitObject, BeatmapDifficultyCalculatorOsu.DifficultyType.Speed, TimeRate); CalculateSpecificStrain(PreviousHitObject, BeatmapDifficultyCalculatorOsu.DifficultyType.Aim, TimeRate); }