示例#1
0
        protected override double StrainValueOf(OsuDifficultyHitObject current)
        {
            double distance = current.Distance;

            double speedValue;

            if (distance > single_spacing_threshold)
            {
                speedValue = 1.25;
            }
            else if (distance > stream_spacing_threshold)
            {
                speedValue = 1.07 + 0.18 * (distance - stream_spacing_threshold) / (single_spacing_threshold - stream_spacing_threshold);
            }
            else if (distance > almost_diameter)
            {
                speedValue = 0.99 + 0.08 * (distance - almost_diameter) / (stream_spacing_threshold - almost_diameter);
            }
            else if (distance > almost_diameter / 2)
            {
                speedValue = 0.95 + 0.04 * (distance - almost_diameter / 2) / (almost_diameter / 2);
            }
            else
            {
                speedValue = 0.95;
            }

            return(speedValue / current.DeltaTime);
        }
示例#2
0
文件: Aim.cs 项目: ry00001/osu
        protected override double StrainValueOf(OsuDifficultyHitObject current)
        {
            double result = 0;

            const double scale = 90;

            double applyDiminishingExp(double val) => Math.Pow(val, 0.99);

            if (Previous.Count > 0)
            {
                if (current.Angle != null && current.Angle.Value > angle_bonus_begin)
                {
                    var angleBonus = Math.Sqrt(
                        Math.Max(Previous[0].JumpDistance - scale, 0)
                        * Math.Pow(Math.Sin(current.Angle.Value - angle_bonus_begin), 2)
                        * Math.Max(current.JumpDistance - scale, 0));
                    result = 1.5 * applyDiminishingExp(Math.Max(0, angleBonus)) / Math.Max(timing_threshold, Previous[0].StrainTime);
                }
            }

            double jumpDistanceExp   = applyDiminishingExp(current.JumpDistance);
            double travelDistanceExp = applyDiminishingExp(current.TravelDistance);

            return(Math.Max(
                       result + (jumpDistanceExp + travelDistanceExp + Math.Sqrt(travelDistanceExp * jumpDistanceExp)) / Math.Max(current.StrainTime, timing_threshold),
                       (Math.Sqrt(travelDistanceExp * jumpDistanceExp) + jumpDistanceExp + travelDistanceExp) / current.StrainTime
                       ));
        }
示例#3
0
文件: Speed.cs 项目: ry00001/osu
        protected override double StrainValueOf(OsuDifficultyHitObject current)
        {
            double distance  = Math.Min(SINGLE_SPACING_THRESHOLD, current.TravelDistance + current.JumpDistance);
            double deltaTime = Math.Max(max_speed_bonus, current.DeltaTime);

            double speedBonus = 1.0;

            if (deltaTime < min_speed_bonus)
            {
                speedBonus = 1 + Math.Pow((min_speed_bonus - deltaTime) / speed_balancing_factor, 2);
            }

            double angleBonus = 1.0;

            if (current.Angle != null && current.Angle.Value < angle_bonus_begin)
            {
                angleBonus = 1 + Math.Pow(Math.Sin(1.5 * (angle_bonus_begin - current.Angle.Value)), 2) / 3.57;
                if (current.Angle.Value < pi_over_2)
                {
                    angleBonus = 1.28;
                    if (distance < 90 && current.Angle.Value < pi_over_4)
                    {
                        angleBonus += (1 - angleBonus) * Math.Min((90 - distance) / 10, 1);
                    }
                    else if (distance < 90)
                    {
                        angleBonus += (1 - angleBonus) * Math.Min((90 - distance) / 10, 1) * Math.Sin((pi_over_2 - current.Angle.Value) / pi_over_4);
                    }
                }
            }

            return((1 + (speedBonus - 1) * 0.75) * angleBonus * (0.95 + speedBonus * Math.Pow(distance / SINGLE_SPACING_THRESHOLD, 3.5)) / current.StrainTime);
        }
示例#4
0
        protected override double StrainValueOf(OsuDifficultyHitObject current)
        {
            double distance = current.TravelDistance + current.JumpDistance;

            double speedValue;

            if (distance > single_spacing_threshold)
            {
                speedValue = 2.5;
            }
            else if (distance > stream_spacing_threshold)
            {
                speedValue = 1.6 + 0.9 * (distance - stream_spacing_threshold) / (single_spacing_threshold - stream_spacing_threshold);
            }
            else if (distance > almost_diameter)
            {
                speedValue = 1.2 + 0.4 * (distance - almost_diameter) / (stream_spacing_threshold - almost_diameter);
            }
            else if (distance > almost_diameter / 2)
            {
                speedValue = 0.95 + 0.25 * (distance - almost_diameter / 2) / (almost_diameter / 2);
            }
            else
            {
                speedValue = 0.95;
            }

            return(speedValue / current.StrainTime);
        }
示例#5
0
        private double strainValueOf(DifficultyHitObject current)
        {
            if (current.BaseObject is Spinner)
            {
                return(0);
            }

            var osuCurrent   = (OsuDifficultyHitObject)current;
            var osuHitObject = (OsuHitObject)(osuCurrent.BaseObject);

            double scalingFactor        = 52.0 / osuHitObject.Radius;
            double smallDistNerf        = 1.0;
            double cumulativeStrainTime = 0.0;

            double result = 0.0;

            OsuDifficultyHitObject lastObj = osuCurrent;

            // This is iterating backwards in time from the current object.
            for (int i = 0; i < Previous.Count; i++)
            {
                var currentObj       = (OsuDifficultyHitObject)Previous[i];
                var currentHitObject = (OsuHitObject)(currentObj.BaseObject);

                if (!(currentObj.BaseObject is Spinner))
                {
                    double jumpDistance = (osuHitObject.StackedPosition - currentHitObject.EndPosition).Length;

                    cumulativeStrainTime += lastObj.StrainTime;

                    // We want to nerf objects that can be easily seen within the Flashlight circle radius.
                    if (i == 0)
                    {
                        smallDistNerf = Math.Min(1.0, jumpDistance / 75.0);
                    }

                    // We also want to nerf stacks so that only the first object of the stack is accounted for.
                    double stackNerf = Math.Min(1.0, (currentObj.LazyJumpDistance / scalingFactor) / 25.0);

                    // Bonus based on how visible the object is.
                    double opacityBonus = 1.0 + max_opacity_bonus * (1.0 - osuCurrent.OpacityAt(currentHitObject.StartTime, hidden));

                    result += stackNerf * opacityBonus * scalingFactor * jumpDistance / cumulativeStrainTime;
                }

                lastObj = currentObj;
            }

            result = Math.Pow(smallDistNerf * result, 2.0);

            // Additional bonus for Hidden due to there being no approach circles.
            if (hidden)
            {
                result *= 1.0 + hidden_bonus;
            }

            return(result);
        }
示例#6
0
文件: Aim.cs 项目: emu1337/osu
        private double calculateControlBonus(OsuDifficultyHitObject osuCurrent, OsuDifficultyHitObject osuPrevious)
        {
            var prevCursSpeed = Math.Max(1, osuPrevious.JumpDistance / osuPrevious.StrainTime * control_spacing_scale);
            var curCursSpeed  = Math.Max(1, osuCurrent.JumpDistance / osuCurrent.StrainTime * control_spacing_scale);

            var speedRatio = Math.Max(prevCursSpeed / curCursSpeed, curCursSpeed / prevCursSpeed);

            var speedChange = Math.Pow(speedRatio, 2.5) / (osuCurrent.StrainTime + osuPrevious.StrainTime);

            return(speedChange * osuCurrent.JumpDistance / 1600);
        }
示例#7
0
文件: Skill.cs 项目: vbe0201/osu
        /// <summary>
        /// Process an <see cref="OsuDifficultyHitObject"/> and update current strain values accordingly.
        /// </summary>
        public void Process(OsuDifficultyHitObject current)
        {
            currentStrain *= strainDecay(current.DeltaTime);
            if (!(current.BaseObject is Spinner))
            {
                currentStrain += StrainValueOf(current) * SkillMultiplier;
            }

            currentSectionPeak = Math.Max(currentStrain, currentSectionPeak);

            Previous.Push(current);
        }
示例#8
0
文件: Flashlight.cs 项目: roridev/osu
        private double strainValueOf(DifficultyHitObject current)
        {
            if (current.BaseObject is Spinner)
            {
                return(0);
            }

            var osuCurrent   = (OsuDifficultyHitObject)current;
            var osuHitObject = (OsuHitObject)(osuCurrent.BaseObject);

            double scalingFactor        = 52.0 / osuHitObject.Radius;
            double smallDistNerf        = 1.0;
            double cumulativeStrainTime = 0.0;

            double result = 0.0;

            OsuDifficultyHitObject lastObj = osuCurrent;

            // This is iterating backwards in time from the current object.
            for (int i = 0; i < Previous.Count; i++)
            {
                var currentObj       = (OsuDifficultyHitObject)Previous[i];
                var currentHitObject = (OsuHitObject)(currentObj.BaseObject);

                if (!(currentObj.BaseObject is Spinner))
                {
                    double jumpDistance = (osuHitObject.StackedPosition - currentHitObject.EndPosition).Length;

                    cumulativeStrainTime += lastObj.StrainTime;

                    // We want to nerf objects that can be easily seen within the Flashlight circle radius.
                    if (i == 0)
                    {
                        smallDistNerf = Math.Min(1.0, jumpDistance / 75.0);
                    }

                    // We also want to nerf stacks so that only the first object of the stack is accounted for.
                    double stackNerf = Math.Min(1.0, (currentObj.LazyJumpDistance / scalingFactor) / 25.0);

                    result += stackNerf * scalingFactor * jumpDistance / cumulativeStrainTime;
                }

                lastObj = currentObj;
            }

            return(Math.Pow(smallDistNerf * result, 2.0));
        }
示例#9
0
 protected override double StrainValueOf(OsuDifficultyHitObject current)
 {
     /* double distance = current.Distance;
      *
      * double speedValue;
      * if (distance > single_spacing_threshold)
      *  speedValue = 2.5;
      * else if (distance > stream_spacing_threshold)
      *  speedValue = 1.6 + 0.9 * (distance - stream_spacing_threshold) / (single_spacing_threshold - stream_spacing_threshold);
      * else if (distance > almost_diameter)
      *  speedValue = 1.2 + 0.4 * (distance - almost_diameter) / (stream_spacing_threshold - almost_diameter);
      * else if (distance > almost_diameter / 2)
      *  speedValue = 0.95 + 0.25 * (distance - almost_diameter / 2) / (almost_diameter / 2);
      * else
      *  speedValue = 0.95;
      */
     return(1 / current.DeltaTime);
 }
        protected override IEnumerable <DifficultyHitObject> CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate)
        {
            // The first jump is formed by the first two hitobjects of the map.
            // If the map has less than two OsuHitObjects, the enumerator will not return anything.
            difficultyHitObjects.Clear();
            for (int i = 1; i < beatmap.HitObjects.Count; i++)
            {
                var lastLast = i > 1 ? beatmap.HitObjects[i - 2] : null;
                var last     = beatmap.HitObjects[i - 1];
                var current  = beatmap.HitObjects[i];

                var difficultyHitObject = new OsuDifficultyHitObject(current, lastLast, last, difficultyHitObjects, clockRate);

                yield return(difficultyHitObject);

                difficultyHitObjects.Add(difficultyHitObject);
            }
        }
示例#11
0
        protected override double StrainValueOf(OsuDifficultyHitObject current)
        {
            double distance = Math.Pow(current.Distance, 0.99);
            double time     = current.DeltaTime;

            // Any 1/4 note above 150 BPM will receive a buff if the angle is 90 degrees or below
            if (current.JumpAngle <= 90 && current.JumpAngle >= 0 && distance > 39)
            {
                time *= 0.67 + Math.Min(time, 100) / 300;
            }
            // Any jump with an angle of above 60 degrees will scale harder with distance
            if (current.JumpAngle > 60)
            {
                distance += Math.Pow(Math.Max(current.Distance - (current.BaseObject.Radius / 52) * current.BaseObject.Radius, 0), 1.3) * ((current.JumpAngle - 60) / 1200);
            }
            double aimValue = distance / time;

            return(aimValue);
        }
示例#12
0
文件: Aim.cs 项目: emu1337/osu
        private double calculateRepeatJumpPenalty(OsuDifficultyHitObject osuCurrent)
        {
            if (osuCurrent.LastDistance == null)
            {
                return(0);
            }

            if (osuCurrent.JumpDistance < repeatjump_min_spacing)
            {
                return(0);
            }

            const double spacing_range = repeatjump_max_spacing - repeatjump_min_spacing;
            double       spacingScale  = Math.Min(osuCurrent.JumpDistance - repeatjump_min_spacing, spacing_range) / spacing_range;

            const double start_distance      = 2.5 * 52;
            double       jumpScale           = osuCurrent.JumpDistance / (6 * 52);
            double       scaledStartDistance = jumpScale * start_distance;
            double       innerDistance       = Math.Max(scaledStartDistance - (double)osuCurrent.LastDistance, 0) / scaledStartDistance;

            return(innerDistance * spacingScale * 0.065);
        }
示例#13
0
        /// <summary>
        /// Process an <see cref="OsuDifficultyHitObject"/> and update current strain values accordingly.
        /// </summary>
        public void Process(OsuDifficultyHitObject current)
        {
            //At roughly the equivalent of 50 stacked 220 bpm 1/4 notes, we start to decay less to account for stamina.
            //The threshold at which we do this goes up every time this happens.
            if (SkillMultiplier == 1400 && currentStrain >= staminaThreshold && decayMultiplier < 1.67 && current.DeltaTime < 100)
            {
                decayMultiplier  *= 1.03;
                staminaThreshold *= Math.Pow(1.03, 2);
            }
            //Strain decay will very rapidly approach the normal value once the streaming stops.
            else if (SkillMultiplier == 1400 && current.DeltaTime >= 100)
            {
                double staminaRecovery = 1 / Math.Pow(1.03, 5);
                decayMultiplier  = Math.Max(1, decayMultiplier * staminaRecovery);
                staminaThreshold = Math.Max(1, staminaThreshold * Math.Pow(staminaRecovery, 2));
                double time = current.DeltaTime - 100;
                //Any extended break during gameplay will most likely force decay to go back to its original value.
                for (int i = 0; time > 0; i++)
                {
                    time            -= 75;
                    decayMultiplier  = Math.Max(1, decayMultiplier * Math.Pow(staminaRecovery, 1 + i));
                    staminaThreshold = Math.Max(234.63, staminaThreshold * Math.Pow(Math.Pow(staminaRecovery, 2), 1 + i));
                    if (decayMultiplier == 1)
                    {
                        break;
                    }
                }
            }
            currentStrain *= strainDecay(current.DeltaTime);
            if (!(current.BaseObject is Spinner))
            {
                currentStrain += StrainValueOf(current) * SkillMultiplier;
            }

            currentSectionPeak = Math.Max(currentStrain, currentSectionPeak);

            Previous.Push(current);
        }
示例#14
0
 protected override double StrainValueOf(OsuDifficultyHitObject current)
 => (Math.Pow(current.TravelDistance, 0.99) + Math.Pow(current.JumpDistance, 0.99)) / current.StrainTime;
示例#15
0
文件: Skill.cs 项目: vbe0201/osu
 /// <summary>
 /// Calculates the strain value of an <see cref="OsuDifficultyHitObject"/>. This value is affected by previously processed objects.
 /// </summary>
 protected abstract double StrainValueOf(OsuDifficultyHitObject current);
示例#16
0
文件: Speed.cs 项目: roridev/osu
        /// <summary>
        /// Calculates a rhythm multiplier for the difficulty of the tap associated with historic data of the current <see cref="OsuDifficultyHitObject"/>.
        /// </summary>
        private double calculateRhythmBonus(DifficultyHitObject current)
        {
            if (current.BaseObject is Spinner)
            {
                return(0);
            }

            int previousIslandSize = 0;

            double rhythmComplexitySum = 0;
            int    islandSize          = 1;
            double startRatio          = 0; // store the ratio of the current start of an island to buff for tighter rhythms

            bool firstDeltaSwitch = false;

            int rhythmStart = 0;

            while (rhythmStart < Previous.Count - 2 && current.StartTime - Previous[rhythmStart].StartTime < history_time_max)
            {
                rhythmStart++;
            }

            for (int i = rhythmStart; i > 0; i--)
            {
                OsuDifficultyHitObject currObj = (OsuDifficultyHitObject)Previous[i - 1];
                OsuDifficultyHitObject prevObj = (OsuDifficultyHitObject)Previous[i];
                OsuDifficultyHitObject lastObj = (OsuDifficultyHitObject)Previous[i + 1];

                double currHistoricalDecay = (history_time_max - (current.StartTime - currObj.StartTime)) / history_time_max; // scales note 0 to 1 from history to now

                currHistoricalDecay = Math.Min((double)(Previous.Count - i) / Previous.Count, currHistoricalDecay);           // either we're limited by time or limited by object count.

                double currDelta = currObj.StrainTime;
                double prevDelta = prevObj.StrainTime;
                double lastDelta = lastObj.StrainTime;
                double currRatio = 1.0 + 6.0 * Math.Min(0.5, Math.Pow(Math.Sin(Math.PI / (Math.Min(prevDelta, currDelta) / Math.Max(prevDelta, currDelta))), 2)); // fancy function to calculate rhythmbonuses.

                double windowPenalty = Math.Min(1, Math.Max(0, Math.Abs(prevDelta - currDelta) - greatWindow * 0.6) / (greatWindow * 0.6));

                windowPenalty = Math.Min(1, windowPenalty);

                double effectiveRatio = windowPenalty * currRatio;

                if (firstDeltaSwitch)
                {
                    if (!(prevDelta > 1.25 * currDelta || prevDelta * 1.25 < currDelta))
                    {
                        if (islandSize < 7)
                        {
                            islandSize++; // island is still progressing, count size.
                        }
                    }
                    else
                    {
                        if (Previous[i - 1].BaseObject is Slider) // bpm change is into slider, this is easy acc window
                        {
                            effectiveRatio *= 0.125;
                        }

                        if (Previous[i].BaseObject is Slider) // bpm change was from a slider, this is easier typically than circle -> circle
                        {
                            effectiveRatio *= 0.25;
                        }

                        if (previousIslandSize == islandSize) // repeated island size (ex: triplet -> triplet)
                        {
                            effectiveRatio *= 0.25;
                        }

                        if (previousIslandSize % 2 == islandSize % 2) // repeated island polartiy (2 -> 4, 3 -> 5)
                        {
                            effectiveRatio *= 0.50;
                        }

                        if (lastDelta > prevDelta + 10 && prevDelta > currDelta + 10) // previous increase happened a note ago, 1/1->1/2-1/4, dont want to buff this.
                        {
                            effectiveRatio *= 0.125;
                        }

                        rhythmComplexitySum += Math.Sqrt(effectiveRatio * startRatio) * currHistoricalDecay * Math.Sqrt(4 + islandSize) / 2 * Math.Sqrt(4 + previousIslandSize) / 2;

                        startRatio = effectiveRatio;

                        previousIslandSize = islandSize;  // log the last island size.

                        if (prevDelta * 1.25 < currDelta) // we're slowing down, stop counting
                        {
                            firstDeltaSwitch = false;     // if we're speeding up, this stays true and  we keep counting island size.
                        }
                        islandSize = 1;
                    }
                }
                else if (prevDelta > 1.25 * currDelta) // we want to be speeding up.
                {
                    // Begin counting island until we change speed again.
                    firstDeltaSwitch = true;
                    startRatio       = effectiveRatio;
                    islandSize       = 1;
                }
            }

            return(Math.Sqrt(4 + rhythmComplexitySum * rhythm_multiplier) / 2); //produces multiplier that can be applied to strain. range [1, infinity) (not really though)
        }
示例#17
0
 protected override double StrainValueOf(OsuDifficultyHitObject current) => Math.Pow(current.JumpDistance, 0.99) / current.DeltaTime;