1
0
mirror of https://github.com/ppy/osu.git synced 2025-02-07 20:12:54 +08:00

Merge branch 'master' into user-registration

This commit is contained in:
Dean Herbert 2018-12-17 05:05:06 +09:00 committed by GitHub
commit e9f661bbf5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 204 additions and 151 deletions

View File

@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Catch.Judgements
} }
} }
protected override float HealthIncreaseFor(HitResult result) protected override double HealthIncreaseFor(HitResult result)
{ {
switch (result) switch (result)
{ {

View File

@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Catch.Judgements
} }
} }
protected override float HealthIncreaseFor(HitResult result) protected override double HealthIncreaseFor(HitResult result)
{ {
switch (result) switch (result)
{ {

View File

@ -22,29 +22,17 @@ namespace osu.Game.Rulesets.Catch.Judgements
} }
} }
/// <summary> protected override double HealthIncreaseFor(HitResult result)
/// Retrieves the numeric health increase of a <see cref="HitResult"/>.
/// </summary>
/// <param name="result">The <see cref="HitResult"/> to find the numeric health increase for.</param>
/// <returns>The numeric health increase of <paramref name="result"/>.</returns>
protected virtual float HealthIncreaseFor(HitResult result)
{ {
switch (result) switch (result)
{ {
default: default:
return 0; return 0;
case HitResult.Perfect: case HitResult.Perfect:
return 10.2f; return 10.2;
} }
} }
/// <summary>
/// Retrieves the numeric health increase of a <see cref="JudgementResult"/>.
/// </summary>
/// <param name="result">The <see cref="JudgementResult"/> to find the numeric health increase for.</param>
/// <returns>The numeric health increase of <paramref name="result"/>.</returns>
public float HealthIncreaseFor(JudgementResult result) => HealthIncreaseFor(result.Type);
/// <summary> /// <summary>
/// Whether fruit on the platter should explode or drop. /// Whether fruit on the platter should explode or drop.
/// Note that this is only checked if the owning object is also <see cref="IHasComboInformation.LastInCombo" /> /// Note that this is only checked if the owning object is also <see cref="IHasComboInformation.LastInCombo" />

View File

@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Catch.Judgements
} }
} }
protected override float HealthIncreaseFor(HitResult result) protected override double HealthIncreaseFor(HitResult result)
{ {
switch (result) switch (result)
{ {

View File

@ -3,7 +3,6 @@
using System; using System;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Judgements;
using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
@ -40,8 +39,7 @@ namespace osu.Game.Rulesets.Catch.Scoring
return; return;
} }
if (result.Judgement is CatchJudgement catchJudgement) Health.Value += Math.Max(result.Judgement.HealthIncreaseFor(result) - hpDrainRate, 0) * harshness;
Health.Value += Math.Max(catchJudgement.HealthIncreaseFor(result) - hpDrainRate, 0) * harshness;
} }
} }
} }

View File

@ -20,11 +20,10 @@ namespace osu.Game.Rulesets.Mania.Objects
{ HitResult.Miss, (376, 346, 316) }, { HitResult.Miss, (376, 346, 316) },
}; };
public override bool IsHitResultAllowed(HitResult result) => true;
public override void SetDifficulty(double difficulty) public override void SetDifficulty(double difficulty)
{ {
AllowsPerfect = true;
AllowsOk = true;
Perfect = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Perfect]); Perfect = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Perfect]);
Great = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Great]); Great = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Great]);
Good = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Good]); Good = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Good]);

View File

@ -0,0 +1,24 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Taiko.Judgements
{
public class TaikoDrumRollJudgement : TaikoJudgement
{
public override bool AffectsCombo => false;
protected override double HealthIncreaseFor(HitResult result)
{
// Drum rolls can be ignored with no health penalty
switch (result)
{
case HitResult.Miss:
return 0;
default:
return base.HealthIncreaseFor(result);
}
}
}
}

View File

@ -13,10 +13,21 @@ namespace osu.Game.Rulesets.Taiko.Judgements
{ {
switch (result) switch (result)
{ {
default:
return 0;
case HitResult.Great: case HitResult.Great:
return 200; return 200;
default:
return 0;
}
}
protected override double HealthIncreaseFor(HitResult result)
{
switch (result)
{
case HitResult.Great:
return 0.15;
default:
return 0;
} }
} }
} }

View File

@ -1,21 +0,0 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Taiko.Judgements
{
public class TaikoIntermediateSwellJudgement : TaikoJudgement
{
public override HitResult MaxResult => HitResult.Great;
public override bool AffectsCombo => false;
/// <summary>
/// Computes the numeric result value for the combo portion of the score.
/// </summary>
/// <param name="result">The result to compute the value for.</param>
/// <returns>The numeric result value.</returns>
protected override int NumericResultFor(HitResult result) => 0;
}
}

View File

@ -10,21 +10,31 @@ namespace osu.Game.Rulesets.Taiko.Judgements
{ {
public override HitResult MaxResult => HitResult.Great; public override HitResult MaxResult => HitResult.Great;
/// <summary>
/// Computes the numeric result value for the combo portion of the score.
/// </summary>
/// <param name="result">The result to compute the value for.</param>
/// <returns>The numeric result value.</returns>
protected override int NumericResultFor(HitResult result) protected override int NumericResultFor(HitResult result)
{ {
switch (result) switch (result)
{ {
default:
return 0;
case HitResult.Good: case HitResult.Good:
return 100; return 100;
case HitResult.Great: case HitResult.Great:
return 300; return 300;
default:
return 0;
}
}
protected override double HealthIncreaseFor(HitResult result)
{
switch (result)
{
case HitResult.Miss:
return -1.0;
case HitResult.Good:
return 1.1;
case HitResult.Great:
return 3.0;
default:
return 0;
} }
} }
} }

View File

@ -1,10 +1,15 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Taiko.Judgements namespace osu.Game.Rulesets.Taiko.Judgements
{ {
public class TaikoStrongJudgement : TaikoJudgement public class TaikoStrongJudgement : TaikoJudgement
{ {
// MainObject already changes the HP
protected override double HealthIncreaseFor(HitResult result) => 0;
public override bool AffectsCombo => false; public override bool AffectsCombo => false;
} }
} }

View File

@ -0,0 +1,23 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Taiko.Judgements
{
public class TaikoSwellJudgement : TaikoJudgement
{
public override bool AffectsCombo => false;
protected override double HealthIncreaseFor(HitResult result)
{
switch (result)
{
case HitResult.Miss:
return -0.65;
default:
return 0;
}
}
}
}

View File

@ -0,0 +1,16 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Taiko.Judgements
{
public class TaikoSwellTickJudgement : TaikoJudgement
{
public override bool AffectsCombo => false;
protected override int NumericResultFor(HitResult result) => 0;
protected override double HealthIncreaseFor(HitResult result) => 0;
}
}

View File

@ -173,13 +173,13 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
if (!userTriggered) if (!userTriggered)
{ {
if (timeOffset > second_hit_window) if (timeOffset - MainObject.Result.TimeOffset > second_hit_window)
ApplyResult(r => r.Type = HitResult.Miss); ApplyResult(r => r.Type = HitResult.Miss);
return; return;
} }
if (Math.Abs(MainObject.Result.TimeOffset - timeOffset) < second_hit_window) if (Math.Abs(timeOffset - MainObject.Result.TimeOffset) <= second_hit_window)
ApplyResult(r => r.Type = HitResult.Great); ApplyResult(r => r.Type = MainObject.Result.Type);
} }
public override bool OnPressed(TaikoAction action) public override bool OnPressed(TaikoAction action)

View File

@ -6,11 +6,11 @@ using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Taiko.Objects.Drawables namespace osu.Game.Rulesets.Taiko.Objects.Drawables
{ {
public class DrawableSwellTick : DrawableTaikoHitObject public class DrawableSwellTick : DrawableTaikoHitObject<SwellTick>
{ {
public override bool DisplayResult => false; public override bool DisplayResult => false;
public DrawableSwellTick(TaikoHitObject hitObject) public DrawableSwellTick(SwellTick hitObject)
: base(hitObject) : base(hitObject)
{ {
} }

View File

@ -5,6 +5,8 @@ using osu.Game.Rulesets.Objects.Types;
using System; using System;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Taiko.Judgements;
namespace osu.Game.Rulesets.Taiko.Objects namespace osu.Game.Rulesets.Taiko.Objects
{ {
@ -81,5 +83,7 @@ namespace osu.Game.Rulesets.Taiko.Objects
first = false; first = false;
} }
} }
public override Judgement CreateJudgement() => new TaikoDrumRollJudgement();
} }
} }

View File

@ -3,6 +3,8 @@
using System; using System;
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Taiko.Judgements;
namespace osu.Game.Rulesets.Taiko.Objects namespace osu.Game.Rulesets.Taiko.Objects
{ {
@ -26,5 +28,7 @@ namespace osu.Game.Rulesets.Taiko.Objects
for (int i = 0; i < RequiredHits; i++) for (int i = 0; i < RequiredHits; i++)
AddNested(new SwellTick()); AddNested(new SwellTick());
} }
public override Judgement CreateJudgement() => new TaikoSwellJudgement();
} }
} }

View File

@ -1,9 +1,13 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Taiko.Judgements;
namespace osu.Game.Rulesets.Taiko.Objects namespace osu.Game.Rulesets.Taiko.Objects
{ {
public class SwellTick : TaikoHitObject public class SwellTick : TaikoHitObject
{ {
public override Judgement CreateJudgement() => new TaikoSwellTickJudgement();
} }
} }

View File

@ -14,15 +14,26 @@ namespace osu.Game.Rulesets.Taiko.Objects
{ {
{ HitResult.Great, (100, 70, 40) }, { HitResult.Great, (100, 70, 40) },
{ HitResult.Good, (240, 160, 100) }, { HitResult.Good, (240, 160, 100) },
{ HitResult.Meh, (270, 190, 140) }, { HitResult.Miss, (270, 190, 140) },
{ HitResult.Miss, (400, 400, 400) },
}; };
public override bool IsHitResultAllowed(HitResult result)
{
switch (result)
{
case HitResult.Great:
case HitResult.Good:
case HitResult.Miss:
return true;
default:
return false;
}
}
public override void SetDifficulty(double difficulty) public override void SetDifficulty(double difficulty)
{ {
Great = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Great]); Great = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Great]);
Good = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Good]); Good = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Good]);
Meh = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Meh]);
Miss = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Miss]); Miss = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Miss]);
} }
} }

View File

@ -4,7 +4,6 @@
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Taiko.Judgements;
using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Rulesets.Taiko.Objects;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
@ -13,51 +12,24 @@ namespace osu.Game.Rulesets.Taiko.Scoring
internal class TaikoScoreProcessor : ScoreProcessor<TaikoHitObject> internal class TaikoScoreProcessor : ScoreProcessor<TaikoHitObject>
{ {
/// <summary> /// <summary>
/// The HP awarded by a <see cref="HitResult.Great"/> hit. /// A value used for calculating <see cref="hpMultiplier"/>.
/// </summary> /// </summary>
private const double hp_hit_great = 0.03; private const double object_count_factor = 3;
/// <summary>
/// The HP awarded for a <see cref="HitResult.Good"/> hit.
/// </summary>
private const double hp_hit_good = 0.011;
/// <summary>
/// The minimum HP deducted for a <see cref="HitResult.Miss"/>.
/// This occurs when HP Drain = 0.
/// </summary>
private const double hp_miss_min = -0.0018;
/// <summary>
/// The median HP deducted for a <see cref="HitResult.Miss"/>.
/// This occurs when HP Drain = 5.
/// </summary>
private const double hp_miss_mid = -0.0075;
/// <summary>
/// The maximum HP deducted for a <see cref="HitResult.Miss"/>.
/// This occurs when HP Drain = 10.
/// </summary>
private const double hp_miss_max = -0.12;
/// <summary>
/// The HP awarded for a <see cref="DrumRollTick"/> hit.
/// <para>
/// <see cref="DrumRollTick"/> hits award less HP as they're more spammable, although in hindsight
/// this probably awards too little HP and is kept at this value for now for compatibility.
/// </para>
/// </summary>
private const double hp_hit_tick = 0.00000003;
/// <summary> /// <summary>
/// Taiko fails at the end of the map if the player has not half-filled their HP bar. /// Taiko fails at the end of the map if the player has not half-filled their HP bar.
/// </summary> /// </summary>
protected override bool DefaultFailCondition => JudgedHits == MaxHits && Health.Value <= 0.5; protected override bool DefaultFailCondition => JudgedHits == MaxHits && Health.Value <= 0.5;
private double hpIncreaseTick; /// <summary>
private double hpIncreaseGreat; /// HP multiplier for a successful <see cref="HitResult"/>.
private double hpIncreaseGood; /// </summary>
private double hpIncreaseMiss; private double hpMultiplier;
/// <summary>
/// HP multiplier for a <see cref="HitResult.Miss"/>.
/// </summary>
private double hpMissMultiplier;
public TaikoScoreProcessor(RulesetContainer<TaikoHitObject> rulesetContainer) public TaikoScoreProcessor(RulesetContainer<TaikoHitObject> rulesetContainer)
: base(rulesetContainer) : base(rulesetContainer)
@ -68,38 +40,23 @@ namespace osu.Game.Rulesets.Taiko.Scoring
{ {
base.ApplyBeatmap(beatmap); base.ApplyBeatmap(beatmap);
double hpMultiplierNormal = 1 / (hp_hit_great * beatmap.HitObjects.FindAll(o => o is Hit).Count * BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.5, 0.75, 0.98)); hpMultiplier = 1 / (object_count_factor * beatmap.HitObjects.FindAll(o => o is Hit).Count * BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.5, 0.75, 0.98));
hpIncreaseTick = hp_hit_tick; hpMissMultiplier = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.0018, 0.0075, 0.0120);
hpIncreaseGreat = hpMultiplierNormal * hp_hit_great;
hpIncreaseGood = hpMultiplierNormal * hp_hit_good;
hpIncreaseMiss = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, hp_miss_min, hp_miss_mid, hp_miss_max);
} }
protected override void ApplyResult(JudgementResult result) protected override void ApplyResult(JudgementResult result)
{ {
base.ApplyResult(result); base.ApplyResult(result);
bool isTick = result.Judgement is TaikoDrumRollTickJudgement; double hpIncrease = result.Judgement.HealthIncreaseFor(result);
// Apply HP changes if (result.Type == HitResult.Miss)
switch (result.Type) hpIncrease *= hpMissMultiplier;
{
case HitResult.Miss:
// Missing ticks shouldn't drop HP
if (!isTick)
Health.Value += hpIncreaseMiss;
break;
case HitResult.Good:
Health.Value += hpIncreaseGood;
break;
case HitResult.Great:
if (isTick)
Health.Value += hpIncreaseTick;
else else
Health.Value += hpIncreaseGreat; hpIncrease *= hpMultiplier;
break;
} Health.Value += hpIncrease;
} }
protected override void Reset(bool storeResults) protected override void Reset(bool storeResults)

View File

@ -25,20 +25,13 @@ namespace osu.Game.Overlays
protected override void PopIn() protected override void PopIn()
{ {
base.PopIn(); base.PopIn();
Waves.Show(); Waves.Show();
this.FadeIn();
} }
protected override void PopOut() protected override void PopOut()
{ {
base.PopOut(); base.PopOut();
Waves.Hide(); Waves.Hide();
// this is required or we will remain present even though our waves are hidden.
this.Delay(WaveContainer.DISAPPEAR_DURATION).FadeOut();
} }
} }
} }

View File

@ -44,5 +44,19 @@ namespace osu.Game.Rulesets.Judgements
/// <param name="result">The <see cref="JudgementResult"/> to find the numeric score representation for.</param> /// <param name="result">The <see cref="JudgementResult"/> to find the numeric score representation for.</param>
/// <returns>The numeric score representation of <paramref name="result"/>.</returns> /// <returns>The numeric score representation of <paramref name="result"/>.</returns>
public int NumericResultFor(JudgementResult result) => NumericResultFor(result.Type); public int NumericResultFor(JudgementResult result) => NumericResultFor(result.Type);
/// <summary>
/// Retrieves the numeric health increase of a <see cref="HitResult"/>.
/// </summary>
/// <param name="result">The <see cref="HitResult"/> to find the numeric health increase for.</param>
/// <returns>The numeric health increase of <paramref name="result"/>.</returns>
protected virtual double HealthIncreaseFor(HitResult result) => 0;
/// <summary>
/// Retrieves the numeric health increase of a <see cref="JudgementResult"/>.
/// </summary>
/// <param name="result">The <see cref="JudgementResult"/> to find the numeric health increase for.</param>
/// <returns>The numeric health increase of <paramref name="result"/>.</returns>
public double HealthIncreaseFor(JudgementResult result) => HealthIncreaseFor(result.Type);
} }
} }

View File

@ -22,7 +22,6 @@ namespace osu.Game.Rulesets.Objects
/// <summary> /// <summary>
/// Hit window for a <see cref="HitResult.Perfect"/> result. /// Hit window for a <see cref="HitResult.Perfect"/> result.
/// The user can only achieve receive this result if <see cref="AllowsPerfect"/> is true.
/// </summary> /// </summary>
public double Perfect { get; protected set; } public double Perfect { get; protected set; }
@ -38,7 +37,6 @@ namespace osu.Game.Rulesets.Objects
/// <summary> /// <summary>
/// Hit window for an <see cref="HitResult.Ok"/> result. /// Hit window for an <see cref="HitResult.Ok"/> result.
/// The user can only achieve this result if <see cref="AllowsOk"/> is true.
/// </summary> /// </summary>
public double Ok { get; protected set; } public double Ok { get; protected set; }
@ -53,14 +51,36 @@ namespace osu.Game.Rulesets.Objects
public double Miss { get; protected set; } public double Miss { get; protected set; }
/// <summary> /// <summary>
/// Whether it's possible to achieve a <see cref="HitResult.Perfect"/> result. /// Retrieves the <see cref="HitResult"/> with the largest hit window that produces a successful hit.
/// </summary> /// </summary>
public bool AllowsPerfect; /// <returns>The lowest allowed successful <see cref="HitResult"/>.</returns>
protected HitResult LowestSuccessfulHitResult()
{
for (var result = HitResult.Meh; result <= HitResult.Perfect; ++result)
{
if (IsHitResultAllowed(result))
return result;
}
return HitResult.None;
}
/// <summary> /// <summary>
/// Whether it's possible to achieve a <see cref="HitResult.Ok"/> result. /// Check whether it is possible to achieve the provided <see cref="HitResult"/>.
/// </summary> /// </summary>
public bool AllowsOk; /// <param name="result">The result type to check.</param>
/// <returns>Whether the <see cref="HitResult"/> can be achieved.</returns>
public virtual bool IsHitResultAllowed(HitResult result)
{
switch (result)
{
case HitResult.Perfect:
case HitResult.Ok:
return false;
default:
return true;
}
}
/// <summary> /// <summary>
/// Sets hit windows with values that correspond to a difficulty parameter. /// Sets hit windows with values that correspond to a difficulty parameter.
@ -85,18 +105,11 @@ namespace osu.Game.Rulesets.Objects
{ {
timeOffset = Math.Abs(timeOffset); timeOffset = Math.Abs(timeOffset);
if (AllowsPerfect && timeOffset <= HalfWindowFor(HitResult.Perfect)) for (var result = HitResult.Perfect; result >= HitResult.Miss; --result)
return HitResult.Perfect; {
if (timeOffset <= HalfWindowFor(HitResult.Great)) if (IsHitResultAllowed(result) && timeOffset <= HalfWindowFor(result))
return HitResult.Great; return result;
if (timeOffset <= HalfWindowFor(HitResult.Good)) }
return HitResult.Good;
if (AllowsOk && timeOffset <= HalfWindowFor(HitResult.Ok))
return HitResult.Ok;
if (timeOffset <= HalfWindowFor(HitResult.Meh))
return HitResult.Meh;
if (timeOffset <= HalfWindowFor(HitResult.Miss))
return HitResult.Miss;
return HitResult.None; return HitResult.None;
} }
@ -130,10 +143,10 @@ namespace osu.Game.Rulesets.Objects
/// <summary> /// <summary>
/// Given a time offset, whether the <see cref="HitObject"/> can ever be hit in the future with a non-<see cref="HitResult.Miss"/> result. /// Given a time offset, whether the <see cref="HitObject"/> can ever be hit in the future with a non-<see cref="HitResult.Miss"/> result.
/// This happens if <paramref name="timeOffset"/> is less than what is required for a <see cref="Meh"/> result. /// This happens if <paramref name="timeOffset"/> is less than what is required for a <see cref="SuccessfulHitWindow"/> result.
/// </summary> /// </summary>
/// <param name="timeOffset">The time offset.</param> /// <param name="timeOffset">The time offset.</param>
/// <returns>Whether the <see cref="HitObject"/> can be hit at any point in the future from this time offset.</returns> /// <returns>Whether the <see cref="HitObject"/> can be hit at any point in the future from this time offset.</returns>
public bool CanBeHit(double timeOffset) => timeOffset <= HalfWindowFor(HitResult.Meh); public bool CanBeHit(double timeOffset) => timeOffset <= HalfWindowFor(LowestSuccessfulHitResult());
} }
} }