protected override void CheckForResult(bool userTriggered, double timeOffset) { if (userTriggered || Time.Current < slider.EndTime) { return; } ApplyResult(r => { var judgementsCount = NestedHitObjects.Count(); var judgementsHit = NestedHitObjects.Count(h => h.IsHit); var hitFraction = (double)judgementsHit / judgementsCount; if (hitFraction == 1 && HeadCircle.Result.Type == HitResult.Great) { r.Type = HitResult.Great; } else if (hitFraction >= 0.5 && HeadCircle.Result.Type >= HitResult.Good) { r.Type = HitResult.Good; } else if (hitFraction > 0) { r.Type = HitResult.Meh; } else { r.Type = HitResult.Miss; } }); }
protected override void CheckForJudgements(bool userTriggered, double timeOffset) { if (!userTriggered && Time.Current >= slider.EndTime) { var judgementsCount = NestedHitObjects.Count; var judgementsHit = NestedHitObjects.Count(h => h.IsHit); var hitFraction = (double)judgementsHit / judgementsCount; if (hitFraction == 1 && HeadCircle.Judgements.Any(j => j.Result == HitResult.Great)) { AddJudgement(new OsuJudgement { Result = HitResult.Great }); } else if (hitFraction >= 0.5 && HeadCircle.Judgements.Any(j => j.Result >= HitResult.Good)) { AddJudgement(new OsuJudgement { Result = HitResult.Good }); } else if (hitFraction > 0) { AddJudgement(new OsuJudgement { Result = HitResult.Meh }); } else { AddJudgement(new OsuJudgement { Result = HitResult.Miss }); } } }
protected override void CheckForJudgements(bool userTriggered, double timeOffset) { if (userTriggered) { return; } if (timeOffset < 0) { return; } int countHit = NestedHitObjects.Count(o => o.AllJudged); if (countHit > HitObject.RequiredGoodHits) { AddJudgement(new TaikoJudgement { Result = countHit >= HitObject.RequiredGreatHits ? HitResult.Great : HitResult.Good }); if (HitObject.IsStrong) { AddJudgement(new TaikoStrongHitJudgement()); } } else { AddJudgement(new TaikoJudgement { Result = HitResult.Miss }); } }
protected override void LoadAsyncComplete() { base.LoadAsyncComplete(); var nestedStrongHit = (DrawableStrongNestedHit)NestedHitObjects.Single(); nestedStrongHit.Result.Type = hitBoth ? Type : HitResult.Miss; }
protected override void CheckForResult(bool userTriggered, double timeOffset) { // We also make sure all transforms have finished to avoid jank if (NestedHitObjects.All(n => n.Result.HasResult && Time.Current >= n.LatestTransformEndTime)) { ApplyResult(Result.Judgement.MaxResult); } }
protected override void CheckForJudgements(bool userTriggered, double timeOffset) { if (timeOffset >= 0) { AddJudgement(new Judgement { Result = NestedHitObjects.Cast <DrawableCatchHitObject>().Any(n => n.Judgements.Any(j => j.IsHit)) ? HitResult.Perfect : HitResult.Miss }); } }
protected override void CheckForResult(bool userTriggered, double timeOffset) { if (userTriggered || Time.Current < HitObject.EndTime) { return; } ApplyResult(r => r.Type = NestedHitObjects.Any(h => h.Result.IsHit) ? r.Judgement.MaxResult : r.Judgement.MinResult); }
protected override void CheckForResult(bool userTriggered, double timeOffset) { if (userTriggered) return; if (timeOffset < 0) return; int countHit = NestedHitObjects.Count(o => o.IsHit); if (countHit >= HitObject.RequiredGoodHits) ApplyResult(r => r.Type = countHit >= HitObject.RequiredGreatHits ? HitResult.Great : HitResult.Good); else ApplyResult(r => r.Type = HitResult.Miss); }
protected override void CheckForResult(bool userTriggered, double timeOffset) { if (userTriggered) { return; } if (timeOffset < 0) { return; } int countHit = NestedHitObjects.Count(o => o.IsHit); if (countHit >= HitObject.RequiredGoodHits) { ApplyResult(r => r.Type = countHit >= HitObject.RequiredGreatHits ? HitResult.Great : HitResult.Ok); } else { ApplyResult(r => r.Type = r.Judgement.MinResult); } }
protected override void CheckJudgement(bool userTriggered) { if (userTriggered) { return; } if (Judgement.TimeOffset < 0) { return; } int countHit = NestedHitObjects.Count(o => o.Judgement.Result == HitResult.Hit); if (countHit > HitObject.RequiredGoodHits) { Judgement.Result = HitResult.Hit; Judgement.TaikoResult = countHit >= HitObject.RequiredGreatHits ? TaikoHitResult.Great : TaikoHitResult.Good; } else { Judgement.Result = HitResult.Miss; } }
protected override void CheckForResult(bool userTriggered, double timeOffset) { if (userTriggered || 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) { 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 { double hitFraction = (double)hitTicks / totalTicks; r.Type = hitFraction >= 0.5 ? HitResult.Ok : HitResult.Meh; } }); }
private void createTicks() { if (TickDistance == 0) { return; } var length = Curve.Distance; var tickDistance = Math.Min(TickDistance, length); var spanDuration = length / Velocity; var minDistanceFromEnd = Velocity * 0.01; AddNested(new Fruit { Samples = Samples, StartTime = StartTime, X = X }); double lastDropletTime = StartTime; for (int span = 0; span < this.SpanCount(); span++) { var spanStartTime = StartTime + span * spanDuration; var reversed = span % 2 == 1; for (double d = 0; d <= length; d += tickDistance) { var timeProgress = d / length; var distanceProgress = reversed ? 1 - timeProgress : timeProgress; double time = spanStartTime + timeProgress * spanDuration; double tinyTickInterval = time - lastDropletTime; while (tinyTickInterval > 100) { tinyTickInterval /= 2; } for (double t = lastDropletTime + tinyTickInterval; t < time; t += tinyTickInterval) { double progress = reversed ? 1 - (t - spanStartTime) / spanDuration : (t - spanStartTime) / spanDuration; AddNested(new TinyDroplet { StartTime = t, X = X + Curve.PositionAt(progress).X / CatchPlayfield.BASE_WIDTH, Samples = new List <SampleInfo>(Samples.Select(s => new SampleInfo { Bank = s.Bank, Name = @"slidertick", Volume = s.Volume })) }); } if (d > minDistanceFromEnd && Math.Abs(d - length) > minDistanceFromEnd) { AddNested(new Droplet { StartTime = time, X = X + Curve.PositionAt(distanceProgress).X / CatchPlayfield.BASE_WIDTH, Samples = new List <SampleInfo>(Samples.Select(s => new SampleInfo { Bank = s.Bank, Name = @"slidertick", Volume = s.Volume })) }); } lastDropletTime = time; } AddNested(new Fruit { Samples = Samples, StartTime = spanStartTime + spanDuration, X = X + Curve.PositionAt(reversed ? 0 : 1).X / CatchPlayfield.BASE_WIDTH }); } if (NestedHitObjects.LastOrDefault() is IHasComboInformation lastNested) { lastNested.LastInCombo = LastInCombo; } }