2019-02-18 13:46:32 +08:00
// 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.Catch.UI ;
using osu.Game.Rulesets.Difficulty.Preprocessing ;
using osu.Game.Rulesets.Difficulty.Skills ;
2019-02-16 10:11:31 +08:00
using osuTK ;
2019-02-18 13:46:32 +08:00
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 ;
2019-03-06 13:36:30 +08:00
private const double direction_change_bonus = 9.5 ;
private const double antiflow_bonus = 25.0 ;
2019-02-18 13:46:32 +08:00
protected override double SkillMultiplier = > 850 ;
protected override double StrainDecayBase = > 0.2 ;
protected override double DecayWeight = > 0.94 ;
2019-02-20 13:13:54 +08:00
private float? lastPlayerPosition ;
2019-02-16 10:11:31 +08:00
private float lastDistanceMoved ;
2019-03-06 13:36:30 +08:00
private double lastStrainTime ;
2019-02-16 10:11:31 +08:00
2019-02-18 13:46:32 +08:00
protected override double StrainValueOf ( DifficultyHitObject current )
{
var catchCurrent = ( CatchDifficultyHitObject ) current ;
2019-02-20 13:13:54 +08:00
if ( lastPlayerPosition = = null )
lastPlayerPosition = catchCurrent . LastNormalizedPosition ;
2019-02-16 10:11:31 +08:00
float playerPosition = MathHelper . Clamp (
2019-02-20 13:13:54 +08:00
lastPlayerPosition . Value ,
2019-02-16 10:11:31 +08:00
catchCurrent . NormalizedPosition - ( normalized_hitobject_radius - absolute_player_positioning_error ) ,
catchCurrent . NormalizedPosition + ( normalized_hitobject_radius - absolute_player_positioning_error )
) ;
2019-02-20 13:13:54 +08:00
float distanceMoved = playerPosition - lastPlayerPosition . Value ;
2019-02-18 13:46:32 +08:00
2019-03-06 13:36:30 +08:00
// Reduce speed scaling
double weightedStrainTime = catchCurrent . StrainTime + 20 ;
double distanceAddition = Math . Pow ( Math . Abs ( distanceMoved ) , 1.3 ) / 600 ;
double sqrtStrain = Math . Sqrt ( weightedStrainTime ) ;
2019-02-18 13:46:32 +08:00
double bonus = 0 ;
2019-02-16 10:11:31 +08:00
// Direction changes give an extra point!
if ( Math . Abs ( distanceMoved ) > 0.1 )
2019-02-18 13:46:32 +08:00
{
2019-02-16 10:11:31 +08:00
if ( Math . Abs ( lastDistanceMoved ) > 0.1 & & Math . Sign ( distanceMoved ) ! = Math . Sign ( lastDistanceMoved ) )
2019-02-18 13:46:32 +08:00
{
2019-02-16 10:11:31 +08:00
double bonusFactor = Math . Min ( absolute_player_positioning_error , Math . Abs ( distanceMoved ) ) / absolute_player_positioning_error ;
2019-02-18 13:46:32 +08:00
distanceAddition + = direction_change_bonus / sqrtStrain * bonusFactor ;
2019-03-06 13:36:30 +08:00
// Direction changes after jumps (antiflow) are harder
double antiflowBonusFactor = Math . Min ( Math . Sqrt ( Math . Abs ( distanceMoved ) ) / 10 , 1 ) ;
distanceAddition + = ( antiflow_bonus / sqrtStrain ) * ( Math . Sqrt ( Math . Abs ( lastDistanceMoved ) ) / ( lastStrainTime / 40 + 10.0 ) ) * antiflowBonusFactor ;
2019-02-18 13:46:32 +08:00
}
// Base bonus for every movement, giving some weight to streams.
2019-03-06 13:36:30 +08:00
distanceAddition + = 10.0 * Math . Min ( Math . Abs ( distanceMoved ) , normalized_hitobject_radius * 2 ) / ( normalized_hitobject_radius * 6 ) / sqrtStrain ;
2019-02-18 13:46:32 +08:00
}
2019-03-06 13:36:30 +08:00
// Big bonus for edge hyperdashes
if ( catchCurrent . LastObject . DistanceToHyperDash < = 14.0f / CatchPlayfield . BASE_WIDTH )
2019-02-18 13:46:32 +08:00
{
2019-02-16 10:11:31 +08:00
if ( ! catchCurrent . LastObject . HyperDash )
2019-03-06 13:36:30 +08:00
bonus + = 5.0 ;
2019-02-16 10:11:31 +08:00
else
{
// After a hyperdash we ARE in the correct position. Always!
playerPosition = catchCurrent . NormalizedPosition ;
}
2019-02-18 13:46:32 +08:00
2019-03-06 13:36:30 +08:00
distanceAddition * = 1.0 + bonus * ( 14 - catchCurrent . LastObject . DistanceToHyperDash * CatchPlayfield . BASE_WIDTH ) / 14 * ( Math . Min ( catchCurrent . StrainTime , 180 ) / 180 ) ; // Edge dashes are easier at lower ms values
}
// Prevent wide, dense stacks of notes which fit on the catcher from greatly increasing SR
if ( Math . Abs ( distanceMoved ) > 0.1 )
{
if ( Math . Abs ( lastDistanceMoved ) > 0.1 & & Math . Sign ( distanceMoved ) ! = Math . Sign ( lastDistanceMoved ) )
{
if ( Math . Abs ( distanceMoved ) < = ( CatcherArea . CATCHER_SIZE ) & & Math . Abs ( lastDistanceMoved ) = = Math . Abs ( distanceMoved ) )
{
if ( catchCurrent . StrainTime < = 80 & & lastStrainTime = = catchCurrent . StrainTime )
{
distanceAddition * = Math . Max ( ( ( catchCurrent . StrainTime / 80 ) - 0.75 ) * 4 , 0 ) ;
}
}
}
2019-02-18 13:46:32 +08:00
}
2019-02-16 10:11:31 +08:00
lastPlayerPosition = playerPosition ;
lastDistanceMoved = distanceMoved ;
2019-03-06 13:36:30 +08:00
lastStrainTime = catchCurrent . StrainTime ;
2019-02-16 10:11:31 +08:00
2019-03-06 13:36:30 +08:00
return distanceAddition / weightedStrainTime ;
2019-02-18 13:46:32 +08:00
}
}
}