mirror of
https://github.com/ppy/osu.git
synced 2024-11-06 16:57:25 +08:00
66643a97b0
Although this isn't necessary for existing official rulesets and calculators, custom calculators can have use cases for accessing mods in difficulty calculation. For example, accounting for the effects of visual mods.
93 lines
3.8 KiB
C#
93 lines
3.8 KiB
C#
// 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 osu.Game.Rulesets.Catch.Difficulty.Preprocessing;
|
|
using osu.Game.Rulesets.Difficulty.Preprocessing;
|
|
using osu.Game.Rulesets.Difficulty.Skills;
|
|
using osu.Game.Rulesets.Mods;
|
|
|
|
namespace osu.Game.Rulesets.Catch.Difficulty.Skills
|
|
{
|
|
public class Movement : Skill
|
|
{
|
|
private const float absolute_player_positioning_error = 16f;
|
|
private const float normalized_hitobject_radius = 41.0f;
|
|
private const double direction_change_bonus = 21.0;
|
|
|
|
protected override double SkillMultiplier => 900;
|
|
protected override double StrainDecayBase => 0.2;
|
|
|
|
protected override double DecayWeight => 0.94;
|
|
|
|
protected readonly float HalfCatcherWidth;
|
|
|
|
private float? lastPlayerPosition;
|
|
private float lastDistanceMoved;
|
|
private double lastStrainTime;
|
|
|
|
public Movement(Mod[] mods, float halfCatcherWidth)
|
|
: base(mods)
|
|
{
|
|
HalfCatcherWidth = halfCatcherWidth;
|
|
}
|
|
|
|
protected override double StrainValueOf(DifficultyHitObject current)
|
|
{
|
|
var catchCurrent = (CatchDifficultyHitObject)current;
|
|
|
|
lastPlayerPosition ??= catchCurrent.LastNormalizedPosition;
|
|
|
|
float playerPosition = Math.Clamp(
|
|
lastPlayerPosition.Value,
|
|
catchCurrent.NormalizedPosition - (normalized_hitobject_radius - absolute_player_positioning_error),
|
|
catchCurrent.NormalizedPosition + (normalized_hitobject_radius - absolute_player_positioning_error)
|
|
);
|
|
|
|
float distanceMoved = playerPosition - lastPlayerPosition.Value;
|
|
|
|
double weightedStrainTime = catchCurrent.StrainTime + 13 + (3 / catchCurrent.ClockRate);
|
|
|
|
double distanceAddition = (Math.Pow(Math.Abs(distanceMoved), 1.3) / 510);
|
|
double sqrtStrain = Math.Sqrt(weightedStrainTime);
|
|
|
|
double edgeDashBonus = 0;
|
|
|
|
// Direction change bonus.
|
|
if (Math.Abs(distanceMoved) > 0.1)
|
|
{
|
|
if (Math.Abs(lastDistanceMoved) > 0.1 && Math.Sign(distanceMoved) != Math.Sign(lastDistanceMoved))
|
|
{
|
|
double bonusFactor = Math.Min(50, Math.Abs(distanceMoved)) / 50;
|
|
double antiflowFactor = Math.Max(Math.Min(70, Math.Abs(lastDistanceMoved)) / 70, 0.38);
|
|
|
|
distanceAddition += direction_change_bonus / Math.Sqrt(lastStrainTime + 16) * bonusFactor * antiflowFactor * Math.Max(1 - Math.Pow(weightedStrainTime / 1000, 3), 0);
|
|
}
|
|
|
|
// Base bonus for every movement, giving some weight to streams.
|
|
distanceAddition += 12.5 * Math.Min(Math.Abs(distanceMoved), normalized_hitobject_radius * 2) / (normalized_hitobject_radius * 6) / sqrtStrain;
|
|
}
|
|
|
|
// Bonus for edge dashes.
|
|
if (catchCurrent.LastObject.DistanceToHyperDash <= 20.0f)
|
|
{
|
|
if (!catchCurrent.LastObject.HyperDash)
|
|
edgeDashBonus += 5.7;
|
|
else
|
|
{
|
|
// After a hyperdash we ARE in the correct position. Always!
|
|
playerPosition = catchCurrent.NormalizedPosition;
|
|
}
|
|
|
|
distanceAddition *= 1.0 + edgeDashBonus * ((20 - catchCurrent.LastObject.DistanceToHyperDash) / 20) * Math.Pow((Math.Min(catchCurrent.StrainTime * catchCurrent.ClockRate, 265) / 265), 1.5); // Edge Dashes are easier at lower ms values
|
|
}
|
|
|
|
lastPlayerPosition = playerPosition;
|
|
lastDistanceMoved = distanceMoved;
|
|
lastStrainTime = catchCurrent.StrainTime;
|
|
|
|
return distanceAddition / weightedStrainTime;
|
|
}
|
|
}
|
|
}
|