mirror of
https://github.com/ppy/osu.git
synced 2025-03-24 06:47:18 +08:00
Changes to highAR and angle nerf
HighAR now have passive strain bonus to buff low SR maps Angle nerf now applied inplace (copied from HD calc)
This commit is contained in:
parent
83d391e54b
commit
9e6ae3587a
osu.Game.Rulesets.Osu/Difficulty
@ -3,10 +3,10 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Extensions.ObjectExtensions;
|
||||
using osu.Game.Rulesets.Difficulty.Preprocessing;
|
||||
using osu.Game.Rulesets.Osu.Difficulty.Preprocessing;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
|
||||
@ -20,23 +20,90 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
|
||||
|
||||
public static double CalculateDenstityOf(OsuDifficultyHitObject currObj)
|
||||
{
|
||||
double pastObjectDifficultyInfluence = 0;
|
||||
double density = 0;
|
||||
double densityAnglesNerf = -2; // we have threshold of 2, so 2 or same angles won't be punished
|
||||
|
||||
foreach (var loopObj in retrievePastVisibleObjects(currObj))
|
||||
OsuDifficultyHitObject? prevObj0 = null;
|
||||
OsuDifficultyHitObject? prevObj1 = null;
|
||||
OsuDifficultyHitObject? prevObj2 = null;
|
||||
|
||||
double prevConstantAngle = 0;
|
||||
|
||||
foreach (var loopObj in retrievePastVisibleObjects(currObj).Reverse())
|
||||
{
|
||||
double loopDifficulty = currObj.OpacityAt(loopObj.BaseObject.StartTime, false);
|
||||
|
||||
// Small distances means objects may be cheesed, so it doesn't matter whether they are arranged confusingly.
|
||||
// For HD: it's not subtracting anything cuz it's multiplied by the aim difficulty anyways.
|
||||
loopDifficulty *= logistic((loopObj.MinimumJumpDistance - 60) / 10);
|
||||
|
||||
//double timeBetweenCurrAndLoopObj = (currObj.BaseObject.StartTime - loopObj.BaseObject.StartTime) / clockRateEstimate;
|
||||
// Reduce density bonus for this object if they're too apart in time
|
||||
// Nerf starts on 1500ms and reaches maximum (*=0) on 3000ms
|
||||
double timeBetweenCurrAndLoopObj = currObj.StartTime - loopObj.StartTime;
|
||||
loopDifficulty *= getTimeNerfFactor(timeBetweenCurrAndLoopObj);
|
||||
|
||||
pastObjectDifficultyInfluence += loopDifficulty;
|
||||
if (prevObj0.IsNull())
|
||||
{
|
||||
prevObj0 = loopObj;
|
||||
continue;
|
||||
}
|
||||
|
||||
density += loopDifficulty;
|
||||
|
||||
// Angles nerf
|
||||
|
||||
if (loopObj.Angle.IsNotNull() && prevObj0.Angle.IsNotNull())
|
||||
{
|
||||
double angleDifference = Math.Abs(prevObj0.Angle.Value - loopObj.Angle.Value);
|
||||
|
||||
// Nerf alternating angles case
|
||||
if (prevObj1.IsNotNull() && prevObj2.IsNotNull() && prevObj1.Angle.IsNotNull() && prevObj2.Angle.IsNotNull())
|
||||
{
|
||||
// Normalized difference
|
||||
double angleDifference1 = Math.Abs(prevObj1.Angle.Value - loopObj.Angle.Value) / Math.PI;
|
||||
double angleDifference2 = Math.Abs(prevObj2.Angle.Value - prevObj0.Angle.Value) / Math.PI;
|
||||
|
||||
// Will be close to 1 if angleDifference1 and angleDifference2 was both close to 0
|
||||
double alternatingFactor = Math.Pow((1 - angleDifference1) * (1 - angleDifference2), 2);
|
||||
|
||||
// Be sure to nerf only same rhythms
|
||||
double rhythmFactor = 1 - getRhythmDifference(loopObj.StrainTime, prevObj0.StrainTime); // 0 on different rhythm, 1 on same rhythm
|
||||
rhythmFactor *= 1 - getRhythmDifference(prevObj0.StrainTime, prevObj1.StrainTime);
|
||||
rhythmFactor *= 1 - getRhythmDifference(prevObj1.StrainTime, prevObj2.StrainTime);
|
||||
|
||||
double acuteAngleFactor = 1 - Math.Min(loopObj.Angle.Value, prevObj0.Angle.Value) / Math.PI;
|
||||
|
||||
double prevAngleAdjust = Math.Max(angleDifference - angleDifference1, 0);
|
||||
|
||||
prevAngleAdjust *= alternatingFactor; // Nerf if alternating
|
||||
prevAngleAdjust *= rhythmFactor; // Nerf if same rhythms
|
||||
prevAngleAdjust *= acuteAngleFactor;
|
||||
|
||||
angleDifference -= prevAngleAdjust;
|
||||
}
|
||||
|
||||
// Reduce angles nerf if objects are too apart in time
|
||||
// Angle nerf is starting being reduced from 200ms (150BPM jump) and it reduced to 0 on 2000ms
|
||||
double longIntervalFactor = Math.Clamp(1 - (loopObj.StrainTime - 200) / (2000 - 200), 0, 1);
|
||||
|
||||
// Current angle nerf. Angle difference less than 15 degrees is considered the same
|
||||
double currConstantAngle = Math.Cos(4 * Math.Min(Math.PI / 12, angleDifference)) * longIntervalFactor;
|
||||
|
||||
// Apply the nerf only when it's repeated
|
||||
double currentAngleNerf = Math.Min(currConstantAngle, prevConstantAngle);
|
||||
|
||||
densityAnglesNerf += Math.Min(currentAngleNerf, loopDifficulty);
|
||||
prevConstantAngle = currConstantAngle;
|
||||
}
|
||||
|
||||
prevObj2 = prevObj1;
|
||||
prevObj1 = prevObj0;
|
||||
prevObj0 = loopObj;
|
||||
}
|
||||
|
||||
return pastObjectDifficultyInfluence;
|
||||
// Apply angles nerf
|
||||
density -= Math.Max(0, densityAnglesNerf);
|
||||
return density;
|
||||
}
|
||||
|
||||
public static double CalculateOverlapDifficultyOf(OsuDifficultyHitObject currObj)
|
||||
@ -71,8 +138,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
|
||||
screenOverlapDifficulty = Math.Max(0, screenOverlapDifficulty - 0.5); // make overlap value =1 cost significantly less
|
||||
|
||||
double overlapBonus = overlap_multiplier * screenOverlapDifficulty * difficulty;
|
||||
|
||||
difficulty *= getConstantAngleNerfFactor(currObj);
|
||||
difficulty += overlapBonus;
|
||||
|
||||
//difficulty *= 1 + overlap_multiplier * screenOverlapDifficulty;
|
||||
@ -185,77 +250,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
|
||||
}
|
||||
}
|
||||
|
||||
private static double getConstantAngleNerfFactor(OsuDifficultyHitObject current)
|
||||
{
|
||||
const double time_limit = 2000;
|
||||
const double time_limit_low = 200;
|
||||
|
||||
double constantAngleCount = 0;
|
||||
int index = 0;
|
||||
double currentTimeGap = 0;
|
||||
|
||||
OsuDifficultyHitObject prevLoopObj = current;
|
||||
|
||||
OsuDifficultyHitObject? prevLoopObj1 = null;
|
||||
OsuDifficultyHitObject? prevLoopObj2 = null;
|
||||
|
||||
double prevConstantAngle = 0;
|
||||
|
||||
while (currentTimeGap < time_limit)
|
||||
{
|
||||
var loopObj = (OsuDifficultyHitObject)current.Previous(index);
|
||||
|
||||
if (loopObj.IsNull())
|
||||
break;
|
||||
|
||||
double longIntervalFactor = Math.Clamp(1 - (loopObj.StrainTime - time_limit_low) / (time_limit - time_limit_low), 0, 1);
|
||||
|
||||
if (loopObj.Angle.IsNotNull() && prevLoopObj.Angle.IsNotNull())
|
||||
{
|
||||
double angleDifference = Math.Abs(prevLoopObj.Angle.Value - loopObj.Angle.Value);
|
||||
|
||||
// Nerf alternating angles case
|
||||
if (prevLoopObj1.IsNotNull() && prevLoopObj2.IsNotNull() && prevLoopObj1.Angle.IsNotNull() && prevLoopObj2.Angle.IsNotNull())
|
||||
{
|
||||
// Normalized difference
|
||||
double angleDifference1 = Math.Abs(prevLoopObj1.Angle.Value - loopObj.Angle.Value) / Math.PI;
|
||||
double angleDifference2 = Math.Abs(prevLoopObj2.Angle.Value - prevLoopObj.Angle.Value) / Math.PI;
|
||||
|
||||
// Will be close to 1 if angleDifference1 and angleDifference2 was both close to 0
|
||||
double alternatingFactor = Math.Pow((1 - angleDifference1) * (1 - angleDifference2), 2);
|
||||
|
||||
// Be sure to nerf only same rhythms
|
||||
double rhythmFactor = 1 - getRhythmDifference(loopObj.StrainTime, prevLoopObj.StrainTime); // 0 on different rhythm, 1 on same rhythm
|
||||
rhythmFactor *= 1 - getRhythmDifference(prevLoopObj.StrainTime, prevLoopObj1.StrainTime);
|
||||
rhythmFactor *= 1 - getRhythmDifference(prevLoopObj1.StrainTime, prevLoopObj2.StrainTime);
|
||||
|
||||
double acuteAngleFactor = 1 - Math.Min(loopObj.Angle.Value, prevLoopObj.Angle.Value) / Math.PI;
|
||||
|
||||
double prevAngleAdjust = Math.Max(angleDifference - angleDifference1, 0);
|
||||
|
||||
prevAngleAdjust *= alternatingFactor; // Nerf if alternating
|
||||
prevAngleAdjust *= rhythmFactor; // Nerf if same rhythms
|
||||
prevAngleAdjust *= acuteAngleFactor;
|
||||
|
||||
angleDifference -= prevAngleAdjust;
|
||||
}
|
||||
|
||||
double currConstantAngle = Math.Cos(4 * Math.Min(Math.PI / 8, angleDifference)) * longIntervalFactor;
|
||||
constantAngleCount += Math.Min(currConstantAngle, prevConstantAngle);
|
||||
prevConstantAngle = currConstantAngle;
|
||||
}
|
||||
|
||||
currentTimeGap = current.StartTime - loopObj.StartTime;
|
||||
index++;
|
||||
|
||||
prevLoopObj2 = prevLoopObj1;
|
||||
prevLoopObj1 = prevLoopObj;
|
||||
prevLoopObj = loopObj;
|
||||
}
|
||||
|
||||
return Math.Pow(Math.Min(1, 2 / constantAngleCount), 2);
|
||||
}
|
||||
|
||||
private static double getTimeNerfFactor(double deltaTime)
|
||||
{
|
||||
return Math.Clamp(2 - deltaTime / (reading_window_size / 2), 0, 1);
|
||||
|
@ -16,7 +16,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
||||
public class ReadingLowAR : GraphSkill
|
||||
{
|
||||
private readonly List<double> difficulties = new List<double>();
|
||||
//private double skillMultiplier => 2.3;
|
||||
private double skillMultiplier => 2;
|
||||
|
||||
public ReadingLowAR(Mod[] mods)
|
||||
|
@ -64,15 +64,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
||||
}
|
||||
public override double DifficultyValue()
|
||||
{
|
||||
// Get number how much high AR adjust changed difficulty
|
||||
double difficultyRatio = aimComponent.DifficultyValue() / aimComponentNoAdjust.DifficultyValue();
|
||||
|
||||
// Calculate how much preempt should change to account for high AR adjust
|
||||
double difficulty = ReadingHighAREvaluator.GetDifficulty(preempt) * difficultyRatio;
|
||||
double adjustedPreempt = ReadingHighAREvaluator.GetPreempt(difficulty);
|
||||
|
||||
Console.WriteLine($"Degree of High AR Complexity = {difficultyRatio:0.##}, {preempt:0} -> {adjustedPreempt:0}");
|
||||
|
||||
// Simulating summing to get the most correct value possible
|
||||
double aimValue = Math.Sqrt(aimComponent.DifficultyValue()) * OsuDifficultyCalculator.DIFFICULTY_MULTIPLIER;
|
||||
double speedValue = Math.Sqrt(speedComponent.DifficultyValue()) * OsuDifficultyCalculator.DIFFICULTY_MULTIPLIER;
|
||||
@ -83,15 +74,15 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
||||
double power = OsuDifficultyCalculator.SUM_POWER;
|
||||
double totalPerformance = Math.Pow(Math.Pow(aimPerformance, power) + Math.Pow(speedPerformance, power), 1.0 / power);
|
||||
|
||||
// First half of length bonus is in SR to not inflate short AR11 maps
|
||||
// First half of length bonus is in SR to not inflate Star Rating short AR11 maps
|
||||
double lengthBonus = OsuPerformanceCalculator.CalculateDefaultLengthBonus(objectsCount);
|
||||
totalPerformance *= lengthBonus;
|
||||
|
||||
double adjustedDifficulty = OsuStrainSkill.PerformanceToDifficulty(totalPerformance);
|
||||
double difficultyValue = Math.Pow(adjustedDifficulty / OsuDifficultyCalculator.DIFFICULTY_MULTIPLIER, 2.0);
|
||||
|
||||
return 75 * Math.Sqrt(difficultyValue * difficulty);
|
||||
// return difficultyValue;
|
||||
// have the same value as difficultyValue at 500pp point
|
||||
return 75 * Math.Sqrt(difficultyValue);
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,7 +97,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
||||
private bool adjustHighAR;
|
||||
private double currentStrain;
|
||||
|
||||
private double skillMultiplier => 18.5;
|
||||
private double skillMultiplier => 17.8;
|
||||
private double defaultValueMultiplier => 30;
|
||||
private double strainDecayBase => 0.15;
|
||||
|
||||
private double strainDecay(double ms) => Math.Pow(strainDecayBase, ms / 1000);
|
||||
@ -118,12 +110,13 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
||||
currentStrain *= strainDecay(current.DeltaTime);
|
||||
|
||||
double aimDifficulty = AimEvaluator.EvaluateDifficultyOf(current, true);
|
||||
aimDifficulty *= ReadingHighAREvaluator.EvaluateDifficultyOf(current, adjustHighAR);
|
||||
double readingDifficulty = ReadingHighAREvaluator.EvaluateDifficultyOf(current, adjustHighAR);
|
||||
aimDifficulty *= Math.Pow(readingDifficulty, 2);
|
||||
aimDifficulty *= skillMultiplier;
|
||||
|
||||
currentStrain += aimDifficulty;
|
||||
|
||||
return currentStrain;
|
||||
return currentStrain + defaultValueMultiplier * ReadingHighAREvaluator.EvaluateDifficultyOf(current, adjustHighAR);
|
||||
}
|
||||
}
|
||||
|
||||
@ -151,7 +144,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
||||
currentStrain *= strainDecay(currODHO.StrainTime);
|
||||
|
||||
double speedDifficulty = SpeedEvaluator.EvaluateDifficultyOf(current) * skillMultiplier;
|
||||
speedDifficulty *= ReadingHighAREvaluator.EvaluateDifficultyOf(current, false);
|
||||
speedDifficulty *= Math.Pow(ReadingHighAREvaluator.EvaluateDifficultyOf(current, false), 2);
|
||||
currentStrain += speedDifficulty;
|
||||
|
||||
currentRhythm = currODHO.RhythmDifficulty;
|
||||
|
Loading…
x
Reference in New Issue
Block a user