2019-01-24 08:43:03 +00: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.
2018-05-17 08:40:46 +00:00
2022-06-17 07:37:17 +00:00
#nullable disable
2018-05-17 08:40:46 +00:00
using System ;
using System.Collections.Generic ;
using System.Linq ;
using osu.Game.Rulesets.Difficulty ;
using osu.Game.Rulesets.Mods ;
using osu.Game.Rulesets.Scoring ;
2018-11-11 17:38:12 +00:00
using osu.Game.Rulesets.Taiko.Objects ;
2018-11-28 07:12:57 +00:00
using osu.Game.Scoring ;
2018-05-17 08:40:46 +00:00
namespace osu.Game.Rulesets.Taiko.Difficulty
{
public class TaikoPerformanceCalculator : PerformanceCalculator
{
private int countGreat ;
2020-09-29 08:16:55 +00:00
private int countOk ;
2018-05-17 08:40:46 +00:00
private int countMeh ;
private int countMiss ;
2022-08-19 12:57:28 +00:00
private double effectiveMissCount ;
2022-03-15 03:37:39 +00:00
public TaikoPerformanceCalculator ( )
: base ( new TaikoRuleset ( ) )
2018-05-17 08:40:46 +00:00
{
}
2022-03-14 05:25:26 +00:00
protected override PerformanceAttributes CreatePerformanceAttributes ( ScoreInfo score , DifficultyAttributes attributes )
2018-05-17 08:40:46 +00:00
{
2022-03-14 05:25:26 +00:00
var taikoAttributes = ( TaikoDifficultyAttributes ) attributes ;
countGreat = score . Statistics . GetValueOrDefault ( HitResult . Great ) ;
countOk = score . Statistics . GetValueOrDefault ( HitResult . Ok ) ;
countMeh = score . Statistics . GetValueOrDefault ( HitResult . Meh ) ;
countMiss = score . Statistics . GetValueOrDefault ( HitResult . Miss ) ;
2018-05-17 08:40:46 +00:00
2022-08-19 13:15:38 +00:00
// The effectiveMissCount is calculated by gaining a ratio for totalSuccessfulHits and increasing the miss penalty for shorter object counts lower than 1000.
2022-08-25 05:02:10 +00:00
if ( totalSuccessfulHits > 0 )
effectiveMissCount = Math . Max ( 1.0 , 1000.0 / totalSuccessfulHits ) * countMiss ;
2022-08-19 12:57:28 +00:00
2022-09-30 12:56:16 +00:00
// We are disabling some HD and/or FL Bonus for converts for now due to them having low pattern difficulty, and thus being easy to memorize.
bool readingBonusEnabled = score . BeatmapInfo . Ruleset . OnlineID = = 1 ;
2022-08-19 12:57:28 +00:00
double multiplier = 1.13 ;
2018-05-17 08:40:46 +00:00
2022-03-14 05:25:26 +00:00
if ( score . Mods . Any ( m = > m is ModHidden ) )
2022-07-17 04:10:49 +00:00
multiplier * = 1.075 ;
if ( score . Mods . Any ( m = > m is ModEasy ) )
multiplier * = 0.975 ;
2018-05-17 08:40:46 +00:00
2022-09-30 12:56:16 +00:00
double difficultyValue = computeDifficultyValue ( score , taikoAttributes , readingBonusEnabled ) ;
double accuracyValue = computeAccuracyValue ( score , taikoAttributes , readingBonusEnabled ) ;
2018-05-17 08:40:46 +00:00
double totalValue =
Math . Pow (
2021-12-17 20:39:03 +00:00
Math . Pow ( difficultyValue , 1.1 ) +
2018-05-17 08:40:46 +00:00
Math . Pow ( accuracyValue , 1.1 ) , 1.0 / 1.1
) * multiplier ;
2021-12-21 10:08:31 +00:00
return new TaikoPerformanceAttributes
2018-05-17 08:40:46 +00:00
{
2021-12-21 10:08:31 +00:00
Difficulty = difficultyValue ,
Accuracy = accuracyValue ,
2022-08-19 12:57:28 +00:00
EffectiveMissCount = effectiveMissCount ,
2021-12-21 10:08:31 +00:00
Total = totalValue
} ;
2018-05-17 08:40:46 +00:00
}
2022-09-30 12:56:16 +00:00
private double computeDifficultyValue ( ScoreInfo score , TaikoDifficultyAttributes attributes , bool readingBonusEnabled )
2018-05-17 08:40:46 +00:00
{
2022-07-17 04:10:49 +00:00
double difficultyValue = Math . Pow ( 5 * Math . Max ( 1.0 , attributes . StarRating / 0.115 ) - 4.0 , 2.25 ) / 1150.0 ;
2018-05-17 08:40:46 +00:00
2020-07-29 11:53:14 +00:00
double lengthBonus = 1 + 0.1 * Math . Min ( 1.0 , totalHits / 1500.0 ) ;
2021-12-17 20:39:03 +00:00
difficultyValue * = lengthBonus ;
2018-05-17 08:40:46 +00:00
2022-08-19 12:57:28 +00:00
difficultyValue * = Math . Pow ( 0.986 , effectiveMissCount ) ;
2022-07-17 04:10:49 +00:00
if ( score . Mods . Any ( m = > m is ModEasy ) )
2022-08-19 12:57:28 +00:00
difficultyValue * = 0.985 ;
2018-05-17 08:40:46 +00:00
2022-09-30 12:56:16 +00:00
if ( score . Mods . Any ( m = > m is ModHidden ) & & readingBonusEnabled )
2021-12-17 20:39:03 +00:00
difficultyValue * = 1.025 ;
2018-05-17 08:40:46 +00:00
2022-08-19 12:57:28 +00:00
if ( score . Mods . Any ( m = > m is ModHardRock ) )
difficultyValue * = 1.050 ;
2022-09-30 12:56:16 +00:00
if ( score . Mods . Any ( m = > m is ModFlashlight < TaikoHitObject > ) & & readingBonusEnabled )
2022-08-19 13:23:40 +00:00
difficultyValue * = 1.050 * lengthBonus ;
2018-05-17 08:40:46 +00:00
2022-08-19 12:57:28 +00:00
return difficultyValue * Math . Pow ( score . Accuracy , 2.0 ) ;
2018-05-17 08:40:46 +00:00
}
2022-09-30 12:56:16 +00:00
private double computeAccuracyValue ( ScoreInfo score , TaikoDifficultyAttributes attributes , bool readingBonusEnabled )
2018-05-17 08:40:46 +00:00
{
2022-03-14 05:25:26 +00:00
if ( attributes . GreatHitWindow < = 0 )
2018-05-17 08:40:46 +00:00
return 0 ;
2022-08-19 12:57:28 +00:00
double accuracyValue = Math . Pow ( 60.0 / attributes . GreatHitWindow , 1.1 ) * Math . Pow ( score . Accuracy , 8.0 ) * Math . Pow ( attributes . StarRating , 0.4 ) * 27.0 ;
2022-07-17 04:10:49 +00:00
double lengthBonus = Math . Min ( 1.15 , Math . Pow ( totalHits / 1500.0 , 0.3 ) ) ;
accuracyValue * = lengthBonus ;
2022-09-30 12:56:16 +00:00
// Slight HDFL Bonus for accuracy. A clamp is used to prevent against negative values.
if ( score . Mods . Any ( m = > m is ModFlashlight < TaikoHitObject > ) & & score . Mods . Any ( m = > m is ModHidden ) & & readingBonusEnabled )
2022-08-19 12:57:28 +00:00
accuracyValue * = Math . Max ( 1.050 , 1.075 * lengthBonus ) ;
2018-05-17 08:40:46 +00:00
2022-07-17 04:10:49 +00:00
return accuracyValue ;
2018-05-17 08:40:46 +00:00
}
2020-09-29 08:16:55 +00:00
private int totalHits = > countGreat + countOk + countMeh + countMiss ;
2022-08-19 12:57:28 +00:00
private int totalSuccessfulHits = > countGreat + countOk + countMeh ;
2018-05-17 08:40:46 +00:00
}
}