osu/osu.Game.Rulesets.Taiko/Difficulty/Skills/Strain.cs
2019-02-18 14:55:39 +09:00

96 lines
3.2 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.Difficulty.Preprocessing;
using osu.Game.Rulesets.Difficulty.Skills;
using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing;
using osu.Game.Rulesets.Taiko.Objects;
namespace osu.Game.Rulesets.Taiko.Difficulty.Skills
{
public class Strain : Skill
{
private const double rhythm_change_base_threshold = 0.2;
private const double rhythm_change_base = 2.0;
protected override double SkillMultiplier => 1;
protected override double StrainDecayBase => 0.3;
private ColourSwitch lastColourSwitch = ColourSwitch.None;
private int sameColourCount = 1;
protected override double StrainValueOf(DifficultyHitObject current)
{
double addition = 1;
// We get an extra addition if we are not a slider or spinner
if (current.LastObject is Hit && current.BaseObject is Hit && current.DeltaTime < 1000)
{
if (hasColourChange(current))
addition += 0.75;
if (hasRhythmChange(current))
addition += 1;
}
else
{
lastColourSwitch = ColourSwitch.None;
sameColourCount = 1;
}
double additionFactor = 1;
// Scale the addition factor linearly from 0.4 to 1 for DeltaTime from 0 to 50
if (current.DeltaTime < 50)
additionFactor = 0.4 + 0.6 * current.DeltaTime / 50;
return additionFactor * addition;
}
private bool hasRhythmChange(DifficultyHitObject current)
{
// We don't want a division by zero if some random mapper decides to put two HitObjects at the same time.
if (current.DeltaTime == 0 || Previous.Count == 0 || Previous[0].DeltaTime == 0)
return false;
double timeElapsedRatio = Math.Max(Previous[0].DeltaTime / current.DeltaTime, current.DeltaTime / Previous[0].DeltaTime);
if (timeElapsedRatio >= 8)
return false;
double difference = Math.Log(timeElapsedRatio, rhythm_change_base) % 1.0;
return difference > rhythm_change_base_threshold && difference < 1 - rhythm_change_base_threshold;
}
private bool hasColourChange(DifficultyHitObject current)
{
var taikoCurrent = (TaikoDifficultyHitObject)current;
if (!taikoCurrent.HasTypeChange)
{
sameColourCount++;
return false;
}
var oldColourSwitch = lastColourSwitch;
var newColourSwitch = sameColourCount % 2 == 0 ? ColourSwitch.Even : ColourSwitch.Odd;
lastColourSwitch = newColourSwitch;
sameColourCount = 1;
// We only want a bonus if the parity of the color switch changes
return oldColourSwitch != ColourSwitch.None && oldColourSwitch != newColourSwitch;
}
private enum ColourSwitch
{
None,
Even,
Odd
}
}
}