mirror of
https://github.com/ppy/osu.git
synced 2025-03-14 05:47:20 +08:00
fixed high AR (i hope)
This commit is contained in:
parent
4051413c92
commit
98873e2401
@ -211,9 +211,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
|
||||
public static double EvaluateInpredictabilityOf(DifficultyHitObject current)
|
||||
{
|
||||
// make the sum equal to 1
|
||||
const double velocity_change_part = 0.25;
|
||||
const double angle_change_part = 0.45;
|
||||
const double rhythm_change_part = 0.3;
|
||||
const double velocity_change_part = 0.8;
|
||||
const double angle_change_part = 0.1;
|
||||
const double rhythm_change_part = 0.1;
|
||||
|
||||
if (current.BaseObject is Spinner || current.Index == 0 || current.Previous(0).BaseObject is Spinner)
|
||||
return 0;
|
||||
@ -349,4 +349,38 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
|
||||
}
|
||||
private static double logistic(double x) => 1 / (1 + Math.Exp(-x));
|
||||
}
|
||||
|
||||
public static class ReadingHighAREvaluator
|
||||
{
|
||||
public static double EvaluateDifficultyOf(DifficultyHitObject current, bool applyAdjust = false)
|
||||
{
|
||||
var currObj = (OsuDifficultyHitObject)current;
|
||||
|
||||
double result = GetDifficulty(currObj.Preempt);
|
||||
|
||||
if (applyAdjust)
|
||||
{
|
||||
double inpredictability = ReadingEvaluator.EvaluateInpredictabilityOf(current);
|
||||
|
||||
// follow lines make high AR easier, so apply nerf if object isn't new combo
|
||||
inpredictability *= 1 + 0.1 * (800 - currObj.FollowLineTime) / 800;
|
||||
|
||||
result *= 0.98 + 0.6 * inpredictability;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// High AR curve
|
||||
// https://www.desmos.com/calculator/srzbeumngi
|
||||
public static double GetDifficulty(double preempt)
|
||||
{
|
||||
// Get preempt in seconds
|
||||
preempt /= 1000;
|
||||
if (preempt < 0.375) // We have stop in the point of AR10.5, the value here = 0.396875, derivative = -10.5833,
|
||||
return 0.63 * Math.Pow(8 - 20 * preempt, 2.0 / 3); // This function is matching live high AR bonus
|
||||
else
|
||||
return Math.Exp(9.07583 - 80.0 * preempt / 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,135 +0,0 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
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
|
||||
{
|
||||
// Main class with some util functions
|
||||
public static class ReadingHighAREvaluator
|
||||
{
|
||||
public static double EvaluateDifficultyOf(DifficultyHitObject current, bool applyAdjust = false)
|
||||
{
|
||||
var currObj = (OsuDifficultyHitObject)current;
|
||||
|
||||
double result = GetDifficulty(currObj.Preempt);
|
||||
|
||||
if (applyAdjust)
|
||||
{
|
||||
double inpredictability = ReadingEvaluator.EvaluateInpredictabilityOf(current);
|
||||
|
||||
// follow lines make high AR easier, so apply nerf if object isn't new combo
|
||||
inpredictability *= 1 + 0.1 * (800 - currObj.FollowLineTime) / 800;
|
||||
|
||||
result *= 0.9 + 1 * inpredictability;
|
||||
result *= 1.05 - 0.4 * EvaluateFieryAnglePunishmentOf(current);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Explicitely nerfs edgecased fiery-type jumps for high AR. The difference from Inpredictability is that this is not used in HD calc
|
||||
public static double EvaluateFieryAnglePunishmentOf(DifficultyHitObject current)
|
||||
{
|
||||
if (current.Index <= 2)
|
||||
return 0;
|
||||
|
||||
var currObj = (OsuDifficultyHitObject)current;
|
||||
var lastObj0 = (OsuDifficultyHitObject)current.Previous(0);
|
||||
var lastObj1 = (OsuDifficultyHitObject)current.Previous(1);
|
||||
var lastObj2 = (OsuDifficultyHitObject)current.Previous(2);
|
||||
|
||||
if (currObj.Angle.IsNull() || lastObj0.Angle.IsNull() || lastObj1.Angle.IsNull() || lastObj2.Angle.IsNull())
|
||||
return 0;
|
||||
|
||||
// Punishment will be reduced if velocity is changing
|
||||
double velocityChangeFactor = getVelocityChangeFactor(currObj, lastObj0);
|
||||
velocityChangeFactor = 1 - Math.Pow(velocityChangeFactor, 2);
|
||||
|
||||
double a1 = currObj.Angle.Value / Math.PI;
|
||||
double a2 = lastObj0.Angle.Value / Math.PI;
|
||||
double a3 = lastObj1.Angle.Value / Math.PI;
|
||||
double a4 = lastObj2.Angle.Value / Math.PI;
|
||||
|
||||
// - 4 same sharp angles in a row: (0.3 0.3 0.3 0.3) -> max punishment
|
||||
|
||||
// Normalized difference
|
||||
double angleDifference1 = Math.Abs(a1 - a2);
|
||||
double angleDifference2 = Math.Abs(a1 - a3);
|
||||
double angleDifference3 = Math.Abs(a1 - a4);
|
||||
|
||||
// Will be close to 1 if angleDifference1 and angleDifference2 was both close to 0
|
||||
double sameAnglePunishment = Math.Pow((1 - angleDifference1) * (1 - angleDifference2) * (1 - angleDifference3), 3);
|
||||
|
||||
// Starting from 60 degrees - reduce same angle punishment
|
||||
double angleSharpnessFactor = Math.Max(0, a1 - 1.0 / 3);
|
||||
angleSharpnessFactor = 1 - angleSharpnessFactor;
|
||||
|
||||
sameAnglePunishment *= angleSharpnessFactor;
|
||||
sameAnglePunishment *= velocityChangeFactor;
|
||||
sameAnglePunishment *= 0.75;
|
||||
|
||||
// - Alternating angles with 0: (0.3 0 0.3 0) or (0 0.3 0 0.3) -> max punishment, (0.3 0 0.1 0) -> some punishment
|
||||
|
||||
double alternateWithZeroAnglePunishment = Math.Max(
|
||||
getAlternateWithZeroAnglePunishment(a1, a2, a3, a4),
|
||||
getAlternateWithZeroAnglePunishment(a2, a1, a4, a3));
|
||||
alternateWithZeroAnglePunishment *= velocityChangeFactor;
|
||||
|
||||
return Math.Min(1, sameAnglePunishment + alternateWithZeroAnglePunishment);
|
||||
}
|
||||
|
||||
private static double getVelocityChangeFactor(OsuDifficultyHitObject osuCurrObj, OsuDifficultyHitObject osuLastObj)
|
||||
{
|
||||
double currVelocity = osuCurrObj.LazyJumpDistance / osuCurrObj.StrainTime;
|
||||
double prevVelocity = osuLastObj.LazyJumpDistance / osuLastObj.StrainTime;
|
||||
|
||||
double velocityChangeFactor = 0;
|
||||
|
||||
// https://www.desmos.com/calculator/kqxmqc8pkg
|
||||
if (currVelocity > 0 || prevVelocity > 0)
|
||||
{
|
||||
double velocityChange = Math.Max(0,
|
||||
Math.Min(
|
||||
Math.Abs(prevVelocity - currVelocity) - 0.5 * Math.Min(currVelocity, prevVelocity),
|
||||
Math.Max(((OsuHitObject)osuCurrObj.BaseObject).Radius / Math.Max(osuCurrObj.StrainTime, osuLastObj.StrainTime), Math.Min(currVelocity, prevVelocity))
|
||||
)); // Stealed from xexxar
|
||||
velocityChangeFactor = velocityChange / Math.Max(currVelocity, prevVelocity); // maxiumum is 0.4
|
||||
velocityChangeFactor /= 0.4;
|
||||
}
|
||||
|
||||
return velocityChangeFactor;
|
||||
}
|
||||
|
||||
private static double getAlternateWithZeroAnglePunishment(double a1, double a2, double a3, double a4)
|
||||
{
|
||||
// We assume that a1 and a3 are 0
|
||||
double zeroFactor = Math.Pow((1 - a1) * (1 - a3), 8);
|
||||
zeroFactor *= Math.Pow(1 - Math.Abs(a1 - a3), 2);
|
||||
|
||||
double angleSimilarityFactor = 1 - Math.Abs(a2 - a4);
|
||||
double angleSharpnessFactor = Math.Min(1 - Math.Max(0, a2 - 1.0 / 3), 1 - Math.Max(0, a4 - 1.0 / 3));
|
||||
|
||||
return zeroFactor * angleSimilarityFactor * angleSharpnessFactor;
|
||||
}
|
||||
|
||||
// High AR curve
|
||||
// https://www.desmos.com/calculator/hbj7swzlth
|
||||
public static double GetDifficulty(double preempt)
|
||||
{
|
||||
double value = Math.Pow(4, 3 - 0.01 * preempt); // 1 for 300ms, 0.25 for 400ms, 0.0625 for 500ms
|
||||
value = softmin(value, 2, 1.7); // use softmin to achieve full-memory cap, 2 times more than AR11 (300ms)
|
||||
return value;
|
||||
}
|
||||
|
||||
// We are using mutiply and divide instead of add and subtract, so values won't be negative
|
||||
// https://www.desmos.com/calculator/fv5xerwpd2
|
||||
private static double softmin(double a, double b, double power = Math.E) => a * b / Math.Log(Math.Pow(power, a) + Math.Pow(power, b), power);
|
||||
}
|
||||
}
|
@ -83,7 +83,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
||||
|
||||
double lowARValue = computeReadingLowARValue(score, osuAttributes);
|
||||
double readingHDValue = computeReadingHiddenValue(score, osuAttributes);
|
||||
double readingSlidersValue = 0;
|
||||
|
||||
double highARValue = computeReadingHighARValue(score, osuAttributes);
|
||||
|
||||
@ -95,8 +94,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
||||
double flPower = OsuDifficultyCalculator.FL_SUM_POWER;
|
||||
double flashlightARValue = Math.Pow(Math.Pow(flashlightValue, flPower) + Math.Pow(readingARValue, flPower), 1.0 / flPower);
|
||||
|
||||
double readingNonARValue = readingHDValue + readingSlidersValue;
|
||||
double cognitionValue = Math.Pow(Math.Pow(flashlightARValue, power) + Math.Pow(readingNonARValue, power), 1.0 / power);
|
||||
double cognitionValue = flashlightARValue + readingHDValue;
|
||||
cognitionValue = AdjustCognitionPerformance(cognitionValue, mechanicalValue, potentialHiddenFlashlightValue);
|
||||
|
||||
double accuracyValue = computeAccuracyValue(score, osuAttributes);
|
||||
@ -104,9 +102,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
||||
double totalValue =
|
||||
Math.Pow(
|
||||
Math.Pow(mechanicalValue, power) +
|
||||
Math.Pow(cognitionValue, power) +
|
||||
Math.Pow(accuracyValue, power), 1.0 / power
|
||||
) * multiplier;
|
||||
totalValue += cognitionValue * multiplier;
|
||||
|
||||
return new OsuPerformanceAttributes
|
||||
{
|
||||
|
@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
||||
public class ReadingLowAR : GraphSkill
|
||||
{
|
||||
private readonly List<double> difficulties = new List<double>();
|
||||
private double skillMultiplier => 1.08;
|
||||
private double skillMultiplier => 1.04;
|
||||
private double aimComponentMultiplier => 0.7;
|
||||
|
||||
public ReadingLowAR(Mod[] mods)
|
||||
@ -94,7 +94,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
||||
}
|
||||
|
||||
private double currentStrain;
|
||||
private double skillMultiplier => 4.9;
|
||||
private double skillMultiplier => 4.8;
|
||||
|
||||
protected override double CalculateInitialStrain(double time, DifficultyHitObject current) => currentStrain * StrainDecay(time - current.Previous(0).StartTime);
|
||||
|
||||
|
@ -73,8 +73,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
||||
double adjustedDifficulty = OsuStrainSkill.PerformanceToDifficulty(totalPerformance);
|
||||
double difficultyValue = Math.Pow(adjustedDifficulty / OsuDifficultyCalculator.DIFFICULTY_MULTIPLIER, 2.0);
|
||||
|
||||
// have the same value as difficultyValue at 500pp point
|
||||
return 75 * Math.Sqrt(difficultyValue);
|
||||
return 54 * Math.Sqrt(difficultyValue);
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,7 +88,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
||||
private bool adjustHighAR;
|
||||
private double currentStrain;
|
||||
|
||||
private double skillMultiplier => 17;
|
||||
private double skillMultiplier => 6.85;
|
||||
private double defaultValueMultiplier => 25;
|
||||
|
||||
protected override double CalculateInitialStrain(double time, DifficultyHitObject current) => currentStrain * StrainDecay(time - current.Previous(0).StartTime);
|
||||
@ -109,7 +108,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
||||
|
||||
public class HighARSpeedComponent : OsuStrainSkill
|
||||
{
|
||||
private double skillMultiplier => 670;
|
||||
private double skillMultiplier => 400;
|
||||
protected override double StrainDecayBase => 0.3;
|
||||
|
||||
private double currentStrain;
|
||||
|
Loading…
x
Reference in New Issue
Block a user