// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System; using System.Collections.Generic; using System.Linq; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Difficulty.Evaluators; using osu.Game.Rulesets.Osu.Objects; namespace osu.Game.Rulesets.Osu.Difficulty.Skills { /// /// Represents the skill required to correctly aim at every object in the map with a uniform CircleSize and normalized distances. /// public class Aim : OsuStrainSkill { public readonly bool IncludeSliders; public Aim(Mod[] mods, bool includeSliders) : base(mods) { IncludeSliders = includeSliders; } private double currentStrain; private double skillMultiplier => 25.6; private double strainDecayBase => 0.15; private readonly List sliderStrains = new List(); private double strainDecay(double ms) => Math.Pow(strainDecayBase, ms / 1000); protected override double CalculateInitialStrain(double time, DifficultyHitObject current) => currentStrain * strainDecay(time - current.Previous(0).StartTime); protected override double StrainValueAt(DifficultyHitObject current) { currentStrain *= strainDecay(current.DeltaTime); currentStrain += AimEvaluator.EvaluateDifficultyOf(current, IncludeSliders) * skillMultiplier; if (current.BaseObject is Slider) { sliderStrains.Add(currentStrain); } return currentStrain; } public double GetDifficultSliders() { if (sliderStrains.Count == 0) return 0; double[] sortedStrains = sliderStrains.OrderDescending().ToArray(); double maxSliderStrain = sortedStrains.Max(); if (maxSliderStrain == 0) return 0; return sortedStrains.Sum(strain => 1.0 / (1.0 + Math.Exp(-(strain / maxSliderStrain * 12.0 - 6.0)))); } } }