// Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; using osu.Game.Beatmaps; using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Objects { public class HitWindows { #region Constants /// /// PERFECT hit window at OD = 10. /// private const double perfect_min = 27.8; /// /// PERFECT hit window at OD = 5. /// private const double perfect_mid = 38.8; /// /// PERFECT hit window at OD = 0. /// private const double perfect_max = 44.8; /// /// GREAT hit window at OD = 10. /// private const double great_min = 68; /// /// GREAT hit window at OD = 5. /// private const double great_mid = 98; /// /// GREAT hit window at OD = 0. /// private const double great_max = 128; /// /// GOOD hit window at OD = 10. /// private const double good_min = 134; /// /// GOOD hit window at OD = 5. /// private const double good_mid = 164; /// /// GOOD hit window at OD = 0. /// private const double good_max = 194; /// /// OK hit window at OD = 10. /// private const double ok_min = 194; /// /// OK hit window at OD = 5. /// private const double ok_mid = 224; /// /// OK hit window at OD = 0. /// private const double ok_max = 254; /// /// MEH hit window at OD = 10. /// private const double meh_min = 242; /// /// MEH hit window at OD = 5. /// private const double meh_mid = 272; /// /// MEH hit window at OD = 0. /// private const double meh_max = 302; /// /// MISS hit window at OD = 10. /// private const double miss_min = 316; /// /// MISS hit window at OD = 5. /// private const double miss_mid = 346; /// /// MISS hit window at OD = 0. /// private const double miss_max = 376; #endregion /// /// Hit window for a PERFECT hit. /// public double Perfect = perfect_mid; /// /// Hit window for a GREAT hit. /// public double Great = great_mid; /// /// Hit window for a GOOD hit. /// public double Good = good_mid; /// /// Hit window for an OK hit. /// public double Ok = ok_mid; /// /// Hit window for a MEH hit. /// public double Meh = meh_mid; /// /// Hit window for a MISS hit. /// public double Miss = miss_mid; /// /// Constructs default hit windows. /// public HitWindows() { } /// /// Constructs hit windows by fitting a parameter to a 2-part piecewise linear function for each hit window. /// /// The parameter. public HitWindows(double difficulty) { Perfect = BeatmapDifficulty.DifficultyRange(difficulty, perfect_max, perfect_mid, perfect_min); Great = BeatmapDifficulty.DifficultyRange(difficulty, great_max, great_mid, great_min); Good = BeatmapDifficulty.DifficultyRange(difficulty, good_max, good_mid, good_min); Ok = BeatmapDifficulty.DifficultyRange(difficulty, ok_max, ok_mid, ok_min); Meh = BeatmapDifficulty.DifficultyRange(difficulty, meh_max, meh_mid, meh_min); Miss = BeatmapDifficulty.DifficultyRange(difficulty, miss_max, miss_mid, miss_min); } /// /// Retrieves the hit result for a time offset. /// /// The time offset. This should always be a positive value indicating the absolute time offset. /// The hit result, or null if doesn't result in a judgement. public HitResult? ResultFor(double timeOffset) { timeOffset = Math.Abs(timeOffset); if (timeOffset <= Perfect / 2) return HitResult.Perfect; if (timeOffset <= Great / 2) return HitResult.Great; if (timeOffset <= Good / 2) return HitResult.Good; if (timeOffset <= Ok / 2) return HitResult.Ok; if (timeOffset <= Meh / 2) return HitResult.Meh; if (timeOffset <= Miss / 2) return HitResult.Miss; return null; } /// /// Given a time offset, whether the can ever be hit in the future. /// This happens if > . /// /// The time offset. /// Whether the can be hit at any point in the future from this time offset. public bool CanBeHit(double timeOffset) => timeOffset <= Meh / 2; /// /// Multiplies all hit windows by a value. /// /// The hit windows to multiply. /// The value to multiply each hit window by. public static HitWindows operator *(HitWindows windows, double value) { windows.Perfect *= value; windows.Great *= value; windows.Good *= value; windows.Ok *= value; windows.Meh *= value; windows.Miss *= value; return windows; } /// /// Divides all hit windows by a value. /// /// The hit windows to divide. /// The value to divide each hit window by. public static HitWindows operator /(HitWindows windows, double value) { windows.Perfect /= value; windows.Great /= value; windows.Good /= value; windows.Ok /= value; windows.Meh /= value; windows.Miss /= value; return windows; } } }