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 ;
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-04-01 10:00:26 +08:00
private const double direction_change_bonus = 21.0 ;
2019-02-18 13:46:32 +08:00
2019-04-01 10:00:26 +08:00
protected override double SkillMultiplier = > 900 ;
2019-02-18 13:46:32 +08:00
protected override double StrainDecayBase = > 0.2 ;
protected override double DecayWeight = > 0.94 ;
2020-03-13 11:43:01 +08:00
protected readonly float HalfCatcherWidth ;
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
2020-03-13 11:43:01 +08:00
public Movement ( float halfCatcherWidth )
{
HalfCatcherWidth = halfCatcherWidth ;
}
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-11-20 20:19:49 +08:00
float playerPosition = Math . 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
2020-04-08 11:20:46 +08:00
double weightedStrainTime = catchCurrent . StrainTime + 13 + ( 3 / catchCurrent . ClockRate ) ;
2019-03-06 13:36:30 +08:00
2019-04-01 10:00:26 +08:00
double distanceAddition = ( Math . Pow ( Math . Abs ( distanceMoved ) , 1.3 ) / 510 ) ;
2019-03-06 13:36:30 +08:00
double sqrtStrain = Math . Sqrt ( weightedStrainTime ) ;
2019-02-18 13:46:32 +08:00
2019-04-02 06:28:04 +08:00
double edgeDashBonus = 0 ;
2019-02-18 13:46:32 +08:00
2020-04-08 11:20:46 +08:00
// Direction change bonus.
2019-02-16 10:11:31 +08:00
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-04-02 06:28:04 +08:00
double bonusFactor = Math . Min ( 50 , Math . Abs ( distanceMoved ) ) / 50 ;
2020-04-08 11:20:46 +08:00
double antiflowFactor = Math . Max ( Math . Min ( 70 , Math . Abs ( lastDistanceMoved ) ) / 70 , 0.38 ) ;
2019-02-18 13:46:32 +08:00
2020-04-08 11:20:46 +08:00
distanceAddition + = direction_change_bonus / Math . Sqrt ( lastStrainTime + 16 ) * bonusFactor * antiflowFactor * Math . Max ( 1 - Math . Pow ( weightedStrainTime / 1000 , 3 ) , 0 ) ;
2019-02-18 13:46:32 +08:00
}
// Base bonus for every movement, giving some weight to streams.
2019-04-01 10:00:26 +08:00
distanceAddition + = 12.5 * Math . Min ( Math . Abs ( distanceMoved ) , normalized_hitobject_radius * 2 ) / ( normalized_hitobject_radius * 6 ) / sqrtStrain ;
2019-02-18 13:46:32 +08:00
}
2020-04-08 11:20:46 +08:00
// Bonus for edge dashes.
2019-04-01 09:58:26 +08:00
if ( catchCurrent . LastObject . DistanceToHyperDash < = 20.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-04-02 06:28:04 +08:00
edgeDashBonus + = 5.7 ;
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-04-02 06:28:04 +08:00
distanceAddition * = 1.0 + edgeDashBonus * ( ( 20 - catchCurrent . LastObject . DistanceToHyperDash * CatchPlayfield . BASE_WIDTH ) / 20 ) * Math . Pow ( ( Math . Min ( catchCurrent . StrainTime * catchCurrent . ClockRate , 265 ) / 265 ) , 1.5 ) ; // Edge Dashes are easier at lower ms values
2019-03-06 13:36:30 +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
}
}
}