2019-02-18 05:46:32 +00:00
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
2019-01-24 08:43:03 +00:00
// See the LICENCE file in the repository root for full licence text.
2018-04-13 09:19:50 +00:00
2018-05-21 01:49:23 +00:00
using System ;
2018-06-21 03:26:15 +00:00
using System.Collections.Generic ;
2018-06-21 04:12:22 +00:00
using System.Linq ;
2018-05-15 08:40:19 +00:00
using osu.Game.Beatmaps ;
2019-02-18 05:46:32 +00:00
using osu.Game.Rulesets.Catch.Difficulty.Preprocessing ;
using osu.Game.Rulesets.Catch.Difficulty.Skills ;
2018-05-21 01:49:23 +00:00
using osu.Game.Rulesets.Catch.Objects ;
using osu.Game.Rulesets.Catch.UI ;
2019-02-18 05:46:32 +00:00
using osu.Game.Rulesets.Difficulty ;
using osu.Game.Rulesets.Difficulty.Preprocessing ;
using osu.Game.Rulesets.Difficulty.Skills ;
2019-02-19 08:42:24 +00:00
using osu.Game.Rulesets.Mods ;
2018-04-13 09:19:50 +00:00
2018-05-15 08:40:19 +00:00
namespace osu.Game.Rulesets.Catch.Difficulty
2018-04-13 09:19:50 +00:00
{
2018-04-19 13:04:12 +00:00
public class CatchDifficultyCalculator : DifficultyCalculator
2018-04-13 09:19:50 +00:00
{
2019-02-18 05:46:32 +00:00
private const double star_scaling_factor = 0.145 ;
2018-05-21 01:49:23 +00:00
2019-02-18 05:46:32 +00:00
protected override int SectionLength = > 750 ;
2018-05-21 01:49:23 +00:00
2019-02-18 05:46:32 +00:00
private readonly float halfCatchWidth ;
2018-06-21 03:26:15 +00:00
public CatchDifficultyCalculator ( Ruleset ruleset , WorkingBeatmap beatmap )
: base ( ruleset , beatmap )
2018-04-13 09:19:50 +00:00
{
2018-06-21 03:57:59 +00:00
var catcher = new CatcherArea . Catcher ( beatmap . BeatmapInfo . BaseDifficulty ) ;
2019-02-18 05:46:32 +00:00
halfCatchWidth = catcher . CatchWidth * 0.5f ;
2018-05-21 01:49:23 +00:00
2019-02-01 12:06:36 +00:00
// We're only using 80% of the catcher's width to simulate imperfect gameplay.
2019-01-31 16:57:59 +00:00
halfCatchWidth * = 0.8f ;
2019-02-18 05:46:32 +00:00
}
2019-01-31 16:57:59 +00:00
2019-02-19 08:42:24 +00:00
protected override DifficultyAttributes CreateDifficultyAttributes ( IBeatmap beatmap , Mod [ ] mods , Skill [ ] skills , double clockRate )
2019-02-18 05:46:32 +00:00
{
2019-02-19 08:42:24 +00:00
if ( beatmap . HitObjects . Count = = 0 )
2019-02-19 08:45:52 +00:00
return new CatchDifficultyAttributes { Mods = mods } ;
2018-05-21 01:49:23 +00:00
2018-06-21 08:32:10 +00:00
// this is the same as osu!, so there's potential to share the implementation... maybe
2019-02-19 08:42:24 +00:00
double preempt = BeatmapDifficulty . DifficultyRange ( beatmap . BeatmapInfo . BaseDifficulty . ApproachRate , 1800 , 1200 , 450 ) / clockRate ;
2018-05-21 01:49:23 +00:00
2019-02-19 08:42:24 +00:00
return new CatchDifficultyAttributes
2018-06-21 03:26:15 +00:00
{
2019-02-19 08:42:24 +00:00
StarRating = Math . Sqrt ( skills [ 0 ] . DifficultyValue ( ) ) * star_scaling_factor ,
2019-02-19 08:45:52 +00:00
Mods = mods ,
2018-07-05 02:32:09 +00:00
ApproachRate = preempt > 1200.0 ? - ( preempt - 1800.0 ) / 120.0 : - ( preempt - 1200.0 ) / 150.0 + 5.0 ,
2019-02-19 08:42:24 +00:00
MaxCombo = beatmap . HitObjects . Count ( h = > h is Fruit ) + beatmap . HitObjects . OfType < JuiceStream > ( ) . SelectMany ( j = > j . NestedHitObjects ) . Count ( h = > ! ( h is TinyDroplet ) )
2018-06-21 03:26:15 +00:00
} ;
2018-05-21 01:49:23 +00:00
}
2019-02-19 08:42:24 +00:00
protected override IEnumerable < DifficultyHitObject > CreateDifficultyHitObjects ( IBeatmap beatmap , double clockRate )
2018-05-21 01:49:23 +00:00
{
2019-02-18 05:46:32 +00:00
CatchHitObject lastObject = null ;
2018-05-21 01:49:23 +00:00
2019-02-18 05:46:32 +00:00
foreach ( var hitObject in beatmap . HitObjects . OfType < CatchHitObject > ( ) )
2018-06-21 07:21:08 +00:00
{
2019-02-18 05:46:32 +00:00
if ( lastObject = = null )
2018-05-21 01:49:23 +00:00
{
2019-02-18 05:46:32 +00:00
lastObject = hitObject ;
continue ;
2018-05-21 01:49:23 +00:00
}
2019-02-18 05:46:32 +00:00
switch ( hitObject )
{
// We want to only consider fruits that contribute to the combo. Droplets are addressed as accuracy and spinners are not relevant for "skill" calculations.
case Fruit fruit :
2019-02-19 08:42:24 +00:00
yield return new CatchDifficultyHitObject ( fruit , lastObject , clockRate , halfCatchWidth ) ;
2019-02-28 04:31:40 +00:00
2019-02-18 05:48:19 +00:00
lastObject = hitObject ;
2019-02-18 05:46:32 +00:00
break ;
case JuiceStream _ :
foreach ( var nested in hitObject . NestedHitObjects . OfType < CatchHitObject > ( ) . Where ( o = > ! ( o is TinyDroplet ) ) )
2019-02-18 05:48:19 +00:00
{
2019-02-19 08:42:24 +00:00
yield return new CatchDifficultyHitObject ( nested , lastObject , clockRate , halfCatchWidth ) ;
2019-02-28 04:31:40 +00:00
2019-02-18 05:48:19 +00:00
lastObject = nested ;
}
2019-02-28 04:31:40 +00:00
2019-02-18 05:46:32 +00:00
break ;
}
2018-06-21 03:26:15 +00:00
}
2018-05-21 01:49:23 +00:00
}
2019-02-18 05:46:32 +00:00
2019-02-19 08:54:00 +00:00
protected override Skill [ ] CreateSkills ( IBeatmap beatmap ) = > new Skill [ ]
2019-02-18 05:46:32 +00:00
{
new Movement ( ) ,
} ;
2018-04-13 09:19:50 +00:00
}
}