示例#1
0
        // 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);
        }
示例#2
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;
        }