mirror of
https://github.com/ppy/osu.git
synced 2025-01-12 17:35:10 +08:00
Merge branch 'master' into less-basic-touchscreen-detection
This commit is contained in:
commit
febd004bda
@ -41,11 +41,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
switch (hitObject)
|
switch (hitObject)
|
||||||
{
|
{
|
||||||
case Slider slider:
|
case Slider slider:
|
||||||
slider.OnlyJudgeNestedObjects = !NoSliderHeadAccuracy.Value;
|
slider.ClassicSliderBehaviour = NoSliderHeadAccuracy.Value;
|
||||||
|
|
||||||
foreach (var head in slider.NestedHitObjects.OfType<SliderHeadCircle>())
|
|
||||||
head.JudgeAsNormalHitCircle = !NoSliderHeadAccuracy.Value;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Container OverlayElementContainer { get; private set; }
|
public Container OverlayElementContainer { get; private set; }
|
||||||
|
|
||||||
public override bool DisplayResult => !HitObject.OnlyJudgeNestedObjects;
|
public override bool DisplayResult => HitObject.ClassicSliderBehaviour;
|
||||||
|
|
||||||
[CanBeNull]
|
[CanBeNull]
|
||||||
public PlaySliderBody SliderBody => Body.Drawable as PlaySliderBody;
|
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)
|
if (userTriggered || !TailCircle.Judged || Time.Current < HitObject.EndTime)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// If only the nested hitobjects are judged, then the slider's own judgement is ignored for scoring purposes.
|
if (HitObject.ClassicSliderBehaviour)
|
||||||
// But the slider needs to still be judged with a reasonable hit/miss result for visual purposes (hit/miss transforms, etc).
|
|
||||||
if (HitObject.OnlyJudgeNestedObjects)
|
|
||||||
{
|
{
|
||||||
ApplyResult(r => r.Type = NestedHitObjects.Any(h => h.Result.IsHit) ? r.Judgement.MaxResult : r.Judgement.MinResult);
|
// Classic behaviour means a slider is judged proportionally to the number of nested hitobjects hit. This is the classic osu!stable scoring.
|
||||||
return;
|
ApplyResult(r =>
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
{
|
{
|
||||||
double hitFraction = (double)hitTicks / totalTicks;
|
int totalTicks = NestedHitObjects.Count;
|
||||||
r.Type = hitFraction >= 0.5 ? HitResult.Ok : HitResult.Meh;
|
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()
|
public override void PlaySamples()
|
||||||
|
@ -16,7 +16,16 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
|
|
||||||
public DrawableSlider DrawableSlider => (DrawableSlider)ParentHitObject;
|
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>();
|
private readonly IBindable<int> pathVersion = new Bindable<int>();
|
||||||
|
|
||||||
@ -56,12 +65,16 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
{
|
{
|
||||||
Debug.Assert(HitObject != null);
|
Debug.Assert(HitObject != null);
|
||||||
|
|
||||||
if (HitObject.JudgeAsNormalHitCircle)
|
if (HitObject.ClassicSliderBehaviour)
|
||||||
return base.ResultFor(timeOffset);
|
{
|
||||||
|
// 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.
|
return base.ResultFor(timeOffset);
|
||||||
var result = base.ResultFor(timeOffset);
|
|
||||||
return result.IsHit() ? HitResult.LargeTickHit : HitResult.LargeTickMiss;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Shake()
|
public override void Shake()
|
||||||
|
@ -124,10 +124,21 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
public double TickDistanceMultiplier = 1;
|
public double TickDistanceMultiplier = 1;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether this <see cref="Slider"/>'s judgement is fully handled by its nested <see cref="HitObject"/>s.
|
/// If <see langword="false"/>, <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="true"/>, this <see cref="Slider"/> will be judged proportionally to the number of nested <see cref="HitObject"/>s hit.
|
||||||
/// </summary>
|
/// </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)
|
public BindableNumber<double> SliderVelocityMultiplierBindable { get; } = new BindableDouble(1)
|
||||||
{
|
{
|
||||||
@ -187,7 +198,6 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
StartTime = e.Time,
|
StartTime = e.Time,
|
||||||
Position = Position + Path.PositionAt(e.PathProgress),
|
Position = Position + Path.PositionAt(e.PathProgress),
|
||||||
StackHeight = StackHeight,
|
StackHeight = StackHeight,
|
||||||
Scale = Scale,
|
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -197,6 +207,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
StartTime = e.Time,
|
StartTime = e.Time,
|
||||||
Position = Position,
|
Position = Position,
|
||||||
StackHeight = StackHeight,
|
StackHeight = StackHeight,
|
||||||
|
ClassicSliderBehaviour = ClassicSliderBehaviour,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -206,7 +217,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
RepeatIndex = e.SpanIndex,
|
RepeatIndex = e.SpanIndex,
|
||||||
StartTime = e.Time,
|
StartTime = e.Time,
|
||||||
Position = EndPosition,
|
Position = EndPosition,
|
||||||
StackHeight = StackHeight
|
StackHeight = StackHeight,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -217,7 +228,6 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
StartTime = StartTime + (e.SpanIndex + 1) * SpanDuration,
|
StartTime = StartTime + (e.SpanIndex + 1) * SpanDuration,
|
||||||
Position = Position + Path.PositionAt(e.PathProgress),
|
Position = Position + Path.PositionAt(e.PathProgress),
|
||||||
StackHeight = StackHeight,
|
StackHeight = StackHeight,
|
||||||
Scale = Scale,
|
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -262,7 +272,11 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
TailSamples = this.GetNodeSamples(repeatCount + 1);
|
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;
|
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
|
||||||
}
|
}
|
||||||
|
@ -9,11 +9,11 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
public class SliderHeadCircle : HitCircle
|
public class SliderHeadCircle : HitCircle
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether to treat this <see cref="SliderHeadCircle"/> as a normal <see cref="HitCircle"/> for judgement purposes.
|
/// If <see langword="false"/>, 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="true"/>, this <see cref="SliderHeadCircle"/> will be judged as a <see cref="SliderTick"/> instead.
|
||||||
/// </summary>
|
/// </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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user