// Caution: The subjective values are strong with this one private static double spacingWeight(double distance, RpDifficultyCalculator.DifficultyType type) { switch (type) { case RpDifficultyCalculator.DifficultyType.Speed: if (distance > single_spacing_threshold) { return(2.5); } if (distance > stream_spacing_threshold) { return(1.6 + 0.9 * (distance - stream_spacing_threshold) / (single_spacing_threshold - stream_spacing_threshold)); } if (distance > almost_diameter) { return(1.2 + 0.4 * (distance - almost_diameter) / (stream_spacing_threshold - almost_diameter)); } if (distance > almost_diameter / 2) { return(0.95 + 0.25 * (distance - almost_diameter / 2) / (almost_diameter / 2)); } return(0.95); case RpDifficultyCalculator.DifficultyType.Aim: return(Math.Pow(distance, 0.99)); } Debug.Assert(false, "Invalid osu difficulty hit object type."); return(0); }
private void calculateSpecificStrain(RpHitObjectDifficulty previousHitObject, RpDifficultyCalculator.DifficultyType type, double timeRate) { double addition = 0; var timeElapsed = (BaseHitObject.StartTime - previousHitObject.BaseHitObject.StartTime) / timeRate; var decay = Math.Pow(DECAY_BASE[(int)type], timeElapsed / 1000); if (BaseHitObject.ObjectType == ObjectType.ContainerGroup) { // Do nothing for spinners } else if (BaseHitObject.ObjectType == ObjectType.Hold) { switch (type) { case RpDifficultyCalculator.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.lazySliderLength + DistanceTo(previousHitObject), type) * spacing_weight_scaling[(int)type]; break; case RpDifficultyCalculator.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.lazySliderLength, type) + spacingWeight(DistanceTo(previousHitObject), type) ) * spacing_weight_scaling[(int)type]; break; } } else if (BaseHitObject.ObjectType == ObjectType.Hit) { 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; }