1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-11 09:17:51 +08:00

Merge branch 'master' into less-basic-touchscreen-detection

This commit is contained in:
Bartłomiej Dach 2023-11-06 07:41:35 +01:00
commit febd004bda
No known key found for this signature in database
5 changed files with 69 additions and 45 deletions

View File

@ -41,11 +41,7 @@ namespace osu.Game.Rulesets.Osu.Mods
switch (hitObject)
{
case Slider slider:
slider.OnlyJudgeNestedObjects = !NoSliderHeadAccuracy.Value;
foreach (var head in slider.NestedHitObjects.OfType<SliderHeadCircle>())
head.JudgeAsNormalHitCircle = !NoSliderHeadAccuracy.Value;
slider.ClassicSliderBehaviour = NoSliderHeadAccuracy.Value;
break;
}
}

View File

@ -50,7 +50,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
/// </summary>
public Container OverlayElementContainer { get; private set; }
public override bool DisplayResult => !HitObject.OnlyJudgeNestedObjects;
public override bool DisplayResult => HitObject.ClassicSliderBehaviour;
[CanBeNull]
public PlaySliderBody SliderBody => Body.Drawable as PlaySliderBody;
@ -272,30 +272,31 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
if (userTriggered || !TailCircle.Judged || Time.Current < HitObject.EndTime)
return;
// If only the nested hitobjects are judged, then the slider's own judgement is ignored for scoring purposes.
// But the slider needs to still be judged with a reasonable hit/miss result for visual purposes (hit/miss transforms, etc).
if (HitObject.OnlyJudgeNestedObjects)
if (HitObject.ClassicSliderBehaviour)
{
ApplyResult(r => r.Type = NestedHitObjects.Any(h => h.Result.IsHit) ? r.Judgement.MaxResult : r.Judgement.MinResult);
return;
}
// Otherwise, if this slider also needs to be judged, apply judgement proportionally to the number of nested hitobjects hit. This is the classic osu!stable scoring.
ApplyResult(r =>
{
int totalTicks = NestedHitObjects.Count;
int hitTicks = NestedHitObjects.Count(h => h.IsHit);
if (hitTicks == totalTicks)
r.Type = HitResult.Great;
else if (hitTicks == 0)
r.Type = HitResult.Miss;
else
// Classic behaviour means a slider is judged proportionally to the number of nested hitobjects hit. This is the classic osu!stable scoring.
ApplyResult(r =>
{
double hitFraction = (double)hitTicks / totalTicks;
r.Type = hitFraction >= 0.5 ? HitResult.Ok : HitResult.Meh;
}
});
int totalTicks = NestedHitObjects.Count;
int hitTicks = NestedHitObjects.Count(h => h.IsHit);
if (hitTicks == totalTicks)
r.Type = HitResult.Great;
else if (hitTicks == 0)
r.Type = HitResult.Miss;
else
{
double hitFraction = (double)hitTicks / totalTicks;
r.Type = hitFraction >= 0.5 ? HitResult.Ok : HitResult.Meh;
}
});
}
else
{
// If only the nested hitobjects are judged, then the slider's own judgement is ignored for scoring purposes.
// But the slider needs to still be judged with a reasonable hit/miss result for visual purposes (hit/miss transforms, etc).
ApplyResult(r => r.Type = NestedHitObjects.Any(h => h.Result.IsHit) ? r.Judgement.MaxResult : r.Judgement.MinResult);
}
}
public override void PlaySamples()

View File

@ -16,7 +16,16 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
public DrawableSlider DrawableSlider => (DrawableSlider)ParentHitObject;
public override bool DisplayResult => HitObject?.JudgeAsNormalHitCircle ?? base.DisplayResult;
public override bool DisplayResult
{
get
{
if (HitObject?.ClassicSliderBehaviour == true)
return false;
return base.DisplayResult;
}
}
private readonly IBindable<int> pathVersion = new Bindable<int>();
@ -56,12 +65,16 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
Debug.Assert(HitObject != null);
if (HitObject.JudgeAsNormalHitCircle)
return base.ResultFor(timeOffset);
if (HitObject.ClassicSliderBehaviour)
{
// With classic slider behaviour, heads are considered fully hit if in the largest hit window.
// We can't award a full Great because the true Great judgement is awarded on the Slider itself,
// reduced based on number of ticks hit,
// so we use the most suitable LargeTick judgement here instead.
return base.ResultFor(timeOffset).IsHit() ? HitResult.LargeTickHit : HitResult.LargeTickMiss;
}
// If not judged as a normal hitcircle, judge as a slider tick instead. This is the classic osu!stable scoring.
var result = base.ResultFor(timeOffset);
return result.IsHit() ? HitResult.LargeTickHit : HitResult.LargeTickMiss;
return base.ResultFor(timeOffset);
}
public override void Shake()

View File

@ -124,10 +124,21 @@ namespace osu.Game.Rulesets.Osu.Objects
public double TickDistanceMultiplier = 1;
/// <summary>
/// Whether this <see cref="Slider"/>'s judgement is fully handled by its nested <see cref="HitObject"/>s.
/// If <c>false</c>, this <see cref="Slider"/> will be judged proportionally to the number of nested <see cref="HitObject"/>s hit.
/// If <see langword="false"/>, <see cref="Slider"/>'s judgement is fully handled by its nested <see cref="HitObject"/>s.
/// If <see langword="true"/>, this <see cref="Slider"/> will be judged proportionally to the number of nested <see cref="HitObject"/>s hit.
/// </summary>
public bool OnlyJudgeNestedObjects = true;
public bool ClassicSliderBehaviour
{
get => classicSliderBehaviour;
set
{
classicSliderBehaviour = value;
if (HeadCircle != null)
HeadCircle.ClassicSliderBehaviour = value;
}
}
private bool classicSliderBehaviour;
public BindableNumber<double> SliderVelocityMultiplierBindable { get; } = new BindableDouble(1)
{
@ -187,7 +198,6 @@ namespace osu.Game.Rulesets.Osu.Objects
StartTime = e.Time,
Position = Position + Path.PositionAt(e.PathProgress),
StackHeight = StackHeight,
Scale = Scale,
});
break;
@ -197,6 +207,7 @@ namespace osu.Game.Rulesets.Osu.Objects
StartTime = e.Time,
Position = Position,
StackHeight = StackHeight,
ClassicSliderBehaviour = ClassicSliderBehaviour,
});
break;
@ -206,7 +217,7 @@ namespace osu.Game.Rulesets.Osu.Objects
RepeatIndex = e.SpanIndex,
StartTime = e.Time,
Position = EndPosition,
StackHeight = StackHeight
StackHeight = StackHeight,
});
break;
@ -217,7 +228,6 @@ namespace osu.Game.Rulesets.Osu.Objects
StartTime = StartTime + (e.SpanIndex + 1) * SpanDuration,
Position = Position + Path.PositionAt(e.PathProgress),
StackHeight = StackHeight,
Scale = Scale,
});
break;
}
@ -262,7 +272,11 @@ namespace osu.Game.Rulesets.Osu.Objects
TailSamples = this.GetNodeSamples(repeatCount + 1);
}
public override Judgement CreateJudgement() => OnlyJudgeNestedObjects ? new OsuIgnoreJudgement() : new OsuJudgement();
public override Judgement CreateJudgement() => ClassicSliderBehaviour
// See logic in `DrawableSlider.CheckForResult()`
? new OsuJudgement()
// Of note, this creates a combo discrepancy for non-classic-mod sliders (there is no combo increase for tail or slider judgement).
: new OsuIgnoreJudgement();
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}

View File

@ -9,11 +9,11 @@ namespace osu.Game.Rulesets.Osu.Objects
public class SliderHeadCircle : HitCircle
{
/// <summary>
/// Whether to treat this <see cref="SliderHeadCircle"/> as a normal <see cref="HitCircle"/> for judgement purposes.
/// If <c>false</c>, this <see cref="SliderHeadCircle"/> will be judged as a <see cref="SliderTick"/> instead.
/// If <see langword="false"/>, treat this <see cref="SliderHeadCircle"/> as a normal <see cref="HitCircle"/> for judgement purposes.
/// If <see langword="true"/>, this <see cref="SliderHeadCircle"/> will be judged as a <see cref="SliderTick"/> instead.
/// </summary>
public bool JudgeAsNormalHitCircle = true;
public bool ClassicSliderBehaviour;
public override Judgement CreateJudgement() => JudgeAsNormalHitCircle ? base.CreateJudgement() : new SliderTickJudgement();
public override Judgement CreateJudgement() => ClassicSliderBehaviour ? new SliderTickJudgement() : base.CreateJudgement();
}
}