mirror of
https://github.com/ppy/osu.git
synced 2025-01-14 00:42:55 +08:00
Merge branch 'master' into fix-ruleset-change
This commit is contained in:
commit
5112f9b69f
@ -1,6 +1,7 @@
|
|||||||
// 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.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Judgements
|
namespace osu.Game.Rulesets.Catch.Judgements
|
||||||
@ -9,8 +10,6 @@ namespace osu.Game.Rulesets.Catch.Judgements
|
|||||||
{
|
{
|
||||||
public override bool AffectsCombo => false;
|
public override bool AffectsCombo => false;
|
||||||
|
|
||||||
public override bool ShouldExplode => true;
|
|
||||||
|
|
||||||
protected override int NumericResultFor(HitResult result)
|
protected override int NumericResultFor(HitResult result)
|
||||||
{
|
{
|
||||||
switch (result)
|
switch (result)
|
||||||
@ -32,5 +31,7 @@ namespace osu.Game.Rulesets.Catch.Judgements
|
|||||||
return 8;
|
return 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool ShouldExplodeFor(JudgementResult result) => true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,21 +23,10 @@ namespace osu.Game.Rulesets.Catch.Judgements
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The base health increase for the result achieved.
|
/// Retrieves the numeric health increase of a <see cref="HitResult"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public float HealthIncrease => HealthIncreaseFor(Result);
|
/// <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>
|
||||||
/// <summary>
|
|
||||||
/// 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" />
|
|
||||||
/// </summary>
|
|
||||||
public virtual bool ShouldExplode => IsHit;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Convert a <see cref="HitResult"/> to a base health increase.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="result">The value to convert.</param>
|
|
||||||
/// <returns>The base health increase.</returns>
|
|
||||||
protected virtual float HealthIncreaseFor(HitResult result)
|
protected virtual float HealthIncreaseFor(HitResult result)
|
||||||
{
|
{
|
||||||
switch (result)
|
switch (result)
|
||||||
@ -48,5 +37,18 @@ namespace osu.Game.Rulesets.Catch.Judgements
|
|||||||
return 10.2f;
|
return 10.2f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <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>
|
||||||
|
/// 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" />
|
||||||
|
/// </summary>
|
||||||
|
public virtual bool ShouldExplodeFor(JudgementResult result) => result.IsHit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.Catch.Judgements;
|
||||||
|
using osu.Game.Rulesets.Judgements;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Objects
|
namespace osu.Game.Rulesets.Catch.Objects
|
||||||
{
|
{
|
||||||
public class Banana : Fruit
|
public class Banana : Fruit
|
||||||
{
|
{
|
||||||
public override FruitVisualRepresentation VisualRepresentation => FruitVisualRepresentation.Banana;
|
public override FruitVisualRepresentation VisualRepresentation => FruitVisualRepresentation.Banana;
|
||||||
|
|
||||||
|
public override Judgement CreateJudgement() => new CatchBananaJudgement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// 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.Catch.Judgements;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||||
{
|
{
|
||||||
public class DrawableBanana : DrawableFruit
|
public class DrawableBanana : DrawableFruit
|
||||||
@ -11,7 +9,5 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
|||||||
: base(h)
|
: base(h)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override CatchJudgement CreateJudgement() => new CatchBananaJudgement();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,8 +26,6 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
|||||||
AddNested(getVisualRepresentation?.Invoke(b));
|
AddNested(getVisualRepresentation?.Invoke(b));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool ProvidesJudgement => false;
|
|
||||||
|
|
||||||
protected override void AddNested(DrawableHitObject h)
|
protected override void AddNested(DrawableHitObject h)
|
||||||
{
|
{
|
||||||
((DrawableCatchHitObject)h).CheckPosition = o => CheckPosition?.Invoke(o) ?? false;
|
((DrawableCatchHitObject)h).CheckPosition = o => CheckPosition?.Invoke(o) ?? false;
|
||||||
|
@ -5,7 +5,6 @@ using System;
|
|||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Rulesets.Catch.Judgements;
|
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
@ -53,20 +52,14 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
|||||||
|
|
||||||
public Func<CatchHitObject, bool> CheckPosition;
|
public Func<CatchHitObject, bool> CheckPosition;
|
||||||
|
|
||||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||||
{
|
{
|
||||||
if (CheckPosition == null) return;
|
if (CheckPosition == null) return;
|
||||||
|
|
||||||
if (timeOffset >= 0)
|
if (timeOffset >= 0 && Result != null)
|
||||||
{
|
ApplyResult(r => r.Type = CheckPosition.Invoke(HitObject) ? HitResult.Perfect : HitResult.Miss);
|
||||||
var judgement = CreateJudgement();
|
|
||||||
judgement.Result = CheckPosition.Invoke(HitObject) ? HitResult.Perfect : HitResult.Miss;
|
|
||||||
AddJudgement(judgement);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual CatchJudgement CreateJudgement() => new CatchJudgement();
|
|
||||||
|
|
||||||
protected override void SkinChanged(ISkinSource skin, bool allowFallback)
|
protected override void SkinChanged(ISkinSource skin, bool allowFallback)
|
||||||
{
|
{
|
||||||
base.SkinChanged(skin, allowFallback);
|
base.SkinChanged(skin, allowFallback);
|
||||||
|
@ -6,7 +6,6 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Game.Rulesets.Catch.Objects.Drawable.Pieces;
|
using osu.Game.Rulesets.Catch.Objects.Drawable.Pieces;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Game.Rulesets.Catch.Judgements;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||||
{
|
{
|
||||||
@ -24,8 +23,6 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
|||||||
Masking = false;
|
Masking = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override CatchJudgement CreateJudgement() => new CatchDropletJudgement();
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
|
@ -26,8 +26,6 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
|||||||
AddNested(getVisualRepresentation?.Invoke(o));
|
AddNested(getVisualRepresentation?.Invoke(o));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool ProvidesJudgement => false;
|
|
||||||
|
|
||||||
protected override void AddNested(DrawableHitObject h)
|
protected override void AddNested(DrawableHitObject h)
|
||||||
{
|
{
|
||||||
var catchObject = (DrawableCatchHitObject)h;
|
var catchObject = (DrawableCatchHitObject)h;
|
||||||
|
@ -2,18 +2,15 @@
|
|||||||
// 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 OpenTK;
|
using OpenTK;
|
||||||
using osu.Game.Rulesets.Catch.Judgements;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||||
{
|
{
|
||||||
public class DrawableTinyDroplet : DrawableDroplet
|
public class DrawableTinyDroplet : DrawableDroplet
|
||||||
{
|
{
|
||||||
public DrawableTinyDroplet(Droplet h)
|
public DrawableTinyDroplet(TinyDroplet h)
|
||||||
: base(h)
|
: base(h)
|
||||||
{
|
{
|
||||||
Size = new Vector2((float)CatchHitObject.OBJECT_RADIUS) / 8;
|
Size = new Vector2((float)CatchHitObject.OBJECT_RADIUS) / 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override CatchJudgement CreateJudgement() => new CatchTinyDropletJudgement();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.Catch.Judgements;
|
||||||
|
using osu.Game.Rulesets.Judgements;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Objects
|
namespace osu.Game.Rulesets.Catch.Objects
|
||||||
{
|
{
|
||||||
public class Droplet : CatchHitObject
|
public class Droplet : CatchHitObject
|
||||||
{
|
{
|
||||||
|
public override Judgement CreateJudgement() => new CatchDropletJudgement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.Catch.Judgements;
|
||||||
|
using osu.Game.Rulesets.Judgements;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Objects
|
namespace osu.Game.Rulesets.Catch.Objects
|
||||||
{
|
{
|
||||||
public class Fruit : CatchHitObject
|
public class Fruit : CatchHitObject
|
||||||
{
|
{
|
||||||
|
public override Judgement CreateJudgement() => new CatchJudgement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.Catch.Judgements;
|
||||||
|
using osu.Game.Rulesets.Judgements;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Objects
|
namespace osu.Game.Rulesets.Catch.Objects
|
||||||
{
|
{
|
||||||
public class TinyDroplet : Droplet
|
public class TinyDroplet : Droplet
|
||||||
{
|
{
|
||||||
|
public override Judgement CreateJudgement() => new CatchTinyDropletJudgement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
// 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 System;
|
using System;
|
||||||
using System.Linq;
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Catch.Judgements;
|
using osu.Game.Rulesets.Catch.Judgements;
|
||||||
using osu.Game.Rulesets.Catch.Objects;
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
@ -21,55 +20,28 @@ namespace osu.Game.Rulesets.Catch.Scoring
|
|||||||
|
|
||||||
private float hpDrainRate;
|
private float hpDrainRate;
|
||||||
|
|
||||||
protected override void SimulateAutoplay(Beatmap<CatchHitObject> beatmap)
|
protected override void ApplyBeatmap(Beatmap<CatchHitObject> beatmap)
|
||||||
{
|
{
|
||||||
hpDrainRate = beatmap.BeatmapInfo.BaseDifficulty.DrainRate;
|
base.ApplyBeatmap(beatmap);
|
||||||
|
|
||||||
foreach (var obj in beatmap.HitObjects)
|
hpDrainRate = beatmap.BeatmapInfo.BaseDifficulty.DrainRate;
|
||||||
{
|
|
||||||
switch (obj)
|
|
||||||
{
|
|
||||||
case JuiceStream stream:
|
|
||||||
foreach (var nestedObject in stream.NestedHitObjects)
|
|
||||||
switch (nestedObject)
|
|
||||||
{
|
|
||||||
case TinyDroplet _:
|
|
||||||
AddJudgement(new CatchTinyDropletJudgement { Result = HitResult.Perfect });
|
|
||||||
break;
|
|
||||||
case Droplet _:
|
|
||||||
AddJudgement(new CatchDropletJudgement { Result = HitResult.Perfect });
|
|
||||||
break;
|
|
||||||
case Fruit _:
|
|
||||||
AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case BananaShower shower:
|
|
||||||
foreach (var _ in shower.NestedHitObjects.Cast<CatchHitObject>())
|
|
||||||
AddJudgement(new CatchBananaJudgement { Result = HitResult.Perfect });
|
|
||||||
break;
|
|
||||||
case Fruit _:
|
|
||||||
AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private const double harshness = 0.01;
|
private const double harshness = 0.01;
|
||||||
|
|
||||||
protected override void OnNewJudgement(Judgement judgement)
|
protected override void ApplyResult(JudgementResult result)
|
||||||
{
|
{
|
||||||
base.OnNewJudgement(judgement);
|
base.ApplyResult(result);
|
||||||
|
|
||||||
if (judgement.Result == HitResult.Miss)
|
if (result.Type == HitResult.Miss)
|
||||||
{
|
{
|
||||||
if (!judgement.IsBonus)
|
if (!result.Judgement.IsBonus)
|
||||||
Health.Value -= hpDrainRate * (harshness * 2);
|
Health.Value -= hpDrainRate * (harshness * 2);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (judgement is CatchJudgement catchJudgement)
|
if (result.Judgement is CatchJudgement catchJudgement)
|
||||||
Health.Value += Math.Max(catchJudgement.HealthIncrease - hpDrainRate, 0) * harshness;
|
Health.Value += Math.Max(catchJudgement.HealthIncreaseFor(result) - hpDrainRate, 0) * harshness;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
|
|
||||||
public override void Add(DrawableHitObject h)
|
public override void Add(DrawableHitObject h)
|
||||||
{
|
{
|
||||||
h.OnJudgement += onJudgement;
|
h.OnNewResult += onNewResult;
|
||||||
|
|
||||||
base.Add(h);
|
base.Add(h);
|
||||||
|
|
||||||
@ -67,6 +67,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
fruit.CheckPosition = CheckIfWeCanCatch;
|
fruit.CheckPosition = CheckIfWeCanCatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onJudgement(DrawableHitObject judgedObject, Judgement judgement) => catcherArea.OnJudgement((DrawableCatchHitObject)judgedObject, judgement);
|
private void onNewResult(DrawableHitObject judgedObject, JudgementResult result)
|
||||||
|
=> catcherArea.OnResult((DrawableCatchHitObject)judgedObject, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
|
|
||||||
private DrawableCatchHitObject lastPlateableFruit;
|
private DrawableCatchHitObject lastPlateableFruit;
|
||||||
|
|
||||||
public void OnJudgement(DrawableCatchHitObject fruit, Judgement judgement)
|
public void OnResult(DrawableCatchHitObject fruit, JudgementResult result)
|
||||||
{
|
{
|
||||||
void runAfterLoaded(Action action)
|
void runAfterLoaded(Action action)
|
||||||
{
|
{
|
||||||
@ -63,7 +63,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
lastPlateableFruit.OnLoadComplete = _ => action();
|
lastPlateableFruit.OnLoadComplete = _ => action();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (judgement.IsHit && fruit.CanBePlated)
|
if (result.IsHit && fruit.CanBePlated)
|
||||||
{
|
{
|
||||||
var caughtFruit = (DrawableCatchHitObject)GetVisualRepresentation?.Invoke(fruit.HitObject);
|
var caughtFruit = (DrawableCatchHitObject)GetVisualRepresentation?.Invoke(fruit.HitObject);
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
|
|
||||||
if (fruit.HitObject.LastInCombo)
|
if (fruit.HitObject.LastInCombo)
|
||||||
{
|
{
|
||||||
if (((CatchJudgement)judgement).ShouldExplode)
|
if (((CatchJudgement)result.Judgement).ShouldExplodeFor(result))
|
||||||
runAfterLoaded(() => MovableCatcher.Explode());
|
runAfterLoaded(() => MovableCatcher.Explode());
|
||||||
else
|
else
|
||||||
MovableCatcher.Drop();
|
MovableCatcher.Drop();
|
||||||
|
@ -1,27 +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.Mania.Judgements
|
|
||||||
{
|
|
||||||
public class HoldNoteTailJudgement : ManiaJudgement
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Whether the hold note has been released too early and shouldn't give full score for the release.
|
|
||||||
/// </summary>
|
|
||||||
public bool HasBroken;
|
|
||||||
|
|
||||||
protected override int NumericResultFor(HitResult result)
|
|
||||||
{
|
|
||||||
switch (result)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
return base.NumericResultFor(result);
|
|
||||||
case HitResult.Great:
|
|
||||||
case HitResult.Perfect:
|
|
||||||
return base.NumericResultFor(HasBroken ? HitResult.Good : result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -7,7 +7,6 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Rulesets.Mania.Judgements;
|
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
@ -19,7 +18,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class DrawableHoldNote : DrawableManiaHitObject<HoldNote>, IKeyBindingHandler<ManiaAction>
|
public class DrawableHoldNote : DrawableManiaHitObject<HoldNote>, IKeyBindingHandler<ManiaAction>
|
||||||
{
|
{
|
||||||
public override bool DisplayJudgement => false;
|
public override bool DisplayResult => false;
|
||||||
|
|
||||||
public readonly DrawableNote Head;
|
public readonly DrawableNote Head;
|
||||||
public readonly DrawableNote Tail;
|
public readonly DrawableNote Tail;
|
||||||
@ -97,10 +96,10 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||||
{
|
{
|
||||||
if (Tail.AllJudged)
|
if (Tail.AllJudged)
|
||||||
AddJudgement(new HoldNoteJudgement { Result = HitResult.Perfect });
|
ApplyResult(r => r.Type = HitResult.Perfect);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
@ -166,7 +165,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// If the key has been released too early, the user should not receive full score for the release
|
// If the key has been released too early, the user should not receive full score for the release
|
||||||
if (Judgements.Any(j => j.Result == HitResult.Miss))
|
if (Result.Type == HitResult.Miss)
|
||||||
holdNote.hasBroken = true;
|
holdNote.hasBroken = true;
|
||||||
|
|
||||||
// The head note also handles early hits before the body, but we want accurate early hits to count as the body being held
|
// The head note also handles early hits before the body, but we want accurate early hits to count as the body being held
|
||||||
@ -197,7 +196,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
this.holdNote = holdNote;
|
this.holdNote = holdNote;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||||
{
|
{
|
||||||
// Factor in the release lenience
|
// Factor in the release lenience
|
||||||
timeOffset /= release_window_lenience;
|
timeOffset /= release_window_lenience;
|
||||||
@ -205,13 +204,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
if (!userTriggered)
|
if (!userTriggered)
|
||||||
{
|
{
|
||||||
if (!HitObject.HitWindows.CanBeHit(timeOffset))
|
if (!HitObject.HitWindows.CanBeHit(timeOffset))
|
||||||
{
|
ApplyResult(r => r.Type = HitResult.Miss);
|
||||||
AddJudgement(new HoldNoteTailJudgement
|
|
||||||
{
|
|
||||||
Result = HitResult.Miss,
|
|
||||||
HasBroken = holdNote.hasBroken
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -220,10 +213,12 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
if (result == HitResult.None)
|
if (result == HitResult.None)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
AddJudgement(new HoldNoteTailJudgement
|
ApplyResult(r =>
|
||||||
{
|
{
|
||||||
Result = result,
|
if (holdNote.hasBroken && (result == HitResult.Perfect || result == HitResult.Perfect))
|
||||||
HasBroken = holdNote.hasBroken
|
result = HitResult.Good;
|
||||||
|
|
||||||
|
r.Type = result;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,7 +233,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
if (action != Action.Value)
|
if (action != Action.Value)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
UpdateJudgement(true);
|
UpdateResult(true);
|
||||||
|
|
||||||
// Handled by the hold note, which will set holding = false
|
// Handled by the hold note, which will set holding = false
|
||||||
return false;
|
return false;
|
||||||
|
@ -7,7 +7,6 @@ using OpenTK.Graphics;
|
|||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Rulesets.Mania.Judgements;
|
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
@ -72,29 +71,17 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||||
{
|
{
|
||||||
if (!userTriggered)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (Time.Current < HitObject.StartTime)
|
if (Time.Current < HitObject.StartTime)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (HoldStartTime?.Invoke() > HitObject.StartTime)
|
var startTime = HoldStartTime?.Invoke();
|
||||||
return;
|
|
||||||
|
|
||||||
AddJudgement(new HoldNoteTickJudgement { Result = HitResult.Perfect });
|
if (startTime == null || startTime > HitObject.StartTime)
|
||||||
}
|
ApplyResult(r => r.Type = HitResult.Miss);
|
||||||
|
else
|
||||||
protected override void Update()
|
ApplyResult(r => r.Type = HitResult.Perfect);
|
||||||
{
|
|
||||||
if (AllJudged)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (HoldStartTime?.Invoke() == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
UpdateJudgement(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ using OpenTK.Graphics;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Game.Rulesets.Mania.Judgements;
|
|
||||||
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
@ -56,12 +55,12 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||||
{
|
{
|
||||||
if (!userTriggered)
|
if (!userTriggered)
|
||||||
{
|
{
|
||||||
if (!HitObject.HitWindows.CanBeHit(timeOffset))
|
if (!HitObject.HitWindows.CanBeHit(timeOffset))
|
||||||
AddJudgement(new ManiaJudgement { Result = HitResult.Miss });
|
ApplyResult(r => r.Type = HitResult.Miss);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,7 +68,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
if (result == HitResult.None)
|
if (result == HitResult.None)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
AddJudgement(new ManiaJudgement { Result = result });
|
ApplyResult(r => r.Type = result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual bool OnPressed(ManiaAction action)
|
public virtual bool OnPressed(ManiaAction action)
|
||||||
@ -77,7 +76,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
if (action != Action.Value)
|
if (action != Action.Value)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return UpdateJudgement(true);
|
return UpdateResult(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual bool OnReleased(ManiaAction action) => false;
|
public virtual bool OnReleased(ManiaAction action) => false;
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
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.Mania.Judgements;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Objects
|
namespace osu.Game.Rulesets.Mania.Objects
|
||||||
@ -55,7 +57,7 @@ namespace osu.Game.Rulesets.Mania.Objects
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The tail note of the hold.
|
/// The tail note of the hold.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly Note Tail = new Note();
|
public readonly TailNote Tail = new TailNote();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The time between ticks of this hold.
|
/// The time between ticks of this hold.
|
||||||
@ -94,5 +96,7 @@ namespace osu.Game.Rulesets.Mania.Objects
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Judgement CreateJudgement() => new HoldNoteJudgement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
// 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.Mania.Judgements;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Objects
|
namespace osu.Game.Rulesets.Mania.Objects
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -8,5 +11,6 @@ namespace osu.Game.Rulesets.Mania.Objects
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class HoldNoteTick : ManiaHitObject
|
public class HoldNoteTick : ManiaHitObject
|
||||||
{
|
{
|
||||||
|
public override Judgement CreateJudgement() => new HoldNoteTickJudgement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
// 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.Mania.Judgements;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Objects
|
namespace osu.Game.Rulesets.Mania.Objects
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -8,5 +11,6 @@ namespace osu.Game.Rulesets.Mania.Objects
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class Note : ManiaHitObject
|
public class Note : ManiaHitObject
|
||||||
{
|
{
|
||||||
|
public override Judgement CreateJudgement() => new ManiaJudgement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
13
osu.Game.Rulesets.Mania/Objects/TailNote.cs
Normal file
13
osu.Game.Rulesets.Mania/Objects/TailNote.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// 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.Judgements;
|
||||||
|
using osu.Game.Rulesets.Mania.Judgements;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Objects
|
||||||
|
{
|
||||||
|
public class TailNote : Note
|
||||||
|
{
|
||||||
|
public override Judgement CreateJudgement() => new ManiaJudgement();
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,6 @@
|
|||||||
// 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 System.Linq;
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Mania.Judgements;
|
using osu.Game.Rulesets.Mania.Judgements;
|
||||||
@ -97,31 +96,20 @@ namespace osu.Game.Rulesets.Mania.Scoring
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void SimulateAutoplay(Beatmap<ManiaHitObject> beatmap)
|
protected override void ApplyBeatmap(Beatmap<ManiaHitObject> beatmap)
|
||||||
{
|
{
|
||||||
|
base.ApplyBeatmap(beatmap);
|
||||||
|
|
||||||
BeatmapDifficulty difficulty = beatmap.BeatmapInfo.BaseDifficulty;
|
BeatmapDifficulty difficulty = beatmap.BeatmapInfo.BaseDifficulty;
|
||||||
hpMultiplier = BeatmapDifficulty.DifficultyRange(difficulty.DrainRate, hp_multiplier_min, hp_multiplier_mid, hp_multiplier_max);
|
hpMultiplier = BeatmapDifficulty.DifficultyRange(difficulty.DrainRate, hp_multiplier_min, hp_multiplier_mid, hp_multiplier_max);
|
||||||
hpMissMultiplier = BeatmapDifficulty.DifficultyRange(difficulty.DrainRate, hp_multiplier_miss_min, hp_multiplier_miss_mid, hp_multiplier_miss_max);
|
hpMissMultiplier = BeatmapDifficulty.DifficultyRange(difficulty.DrainRate, hp_multiplier_miss_min, hp_multiplier_miss_mid, hp_multiplier_miss_max);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void SimulateAutoplay(Beatmap<ManiaHitObject> beatmap)
|
||||||
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
foreach (var obj in beatmap.HitObjects)
|
base.SimulateAutoplay(beatmap);
|
||||||
{
|
|
||||||
var holdNote = obj as HoldNote;
|
|
||||||
|
|
||||||
if (holdNote != null)
|
|
||||||
{
|
|
||||||
// Head
|
|
||||||
AddJudgement(new ManiaJudgement { Result = HitResult.Perfect });
|
|
||||||
|
|
||||||
// Ticks
|
|
||||||
int tickCount = holdNote.NestedHitObjects.OfType<HoldNoteTick>().Count();
|
|
||||||
for (int i = 0; i < tickCount; i++)
|
|
||||||
AddJudgement(new HoldNoteTickJudgement { Result = HitResult.Perfect });
|
|
||||||
}
|
|
||||||
|
|
||||||
AddJudgement(new ManiaJudgement { Result = HitResult.Perfect });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!HasFailed)
|
if (!HasFailed)
|
||||||
break;
|
break;
|
||||||
@ -133,20 +121,20 @@ namespace osu.Game.Rulesets.Mania.Scoring
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnNewJudgement(Judgement judgement)
|
protected override void ApplyResult(JudgementResult result)
|
||||||
{
|
{
|
||||||
base.OnNewJudgement(judgement);
|
base.ApplyResult(result);
|
||||||
|
|
||||||
bool isTick = judgement is HoldNoteTickJudgement;
|
bool isTick = result.Judgement is HoldNoteTickJudgement;
|
||||||
|
|
||||||
if (isTick)
|
if (isTick)
|
||||||
{
|
{
|
||||||
if (judgement.IsHit)
|
if (result.IsHit)
|
||||||
Health.Value += hpMultiplier * hp_increase_tick;
|
Health.Value += hpMultiplier * hp_increase_tick;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
switch (judgement.Result)
|
switch (result.Type)
|
||||||
{
|
{
|
||||||
case HitResult.Miss:
|
case HitResult.Miss:
|
||||||
Health.Value += hpMissMultiplier * hp_increase_miss;
|
Health.Value += hpMissMultiplier * hp_increase_miss;
|
||||||
|
@ -131,14 +131,14 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
public override void Add(DrawableHitObject hitObject)
|
public override void Add(DrawableHitObject hitObject)
|
||||||
{
|
{
|
||||||
hitObject.AccentColour = AccentColour;
|
hitObject.AccentColour = AccentColour;
|
||||||
hitObject.OnJudgement += OnJudgement;
|
hitObject.OnNewResult += OnNewResult;
|
||||||
|
|
||||||
HitObjects.Add(hitObject);
|
HitObjects.Add(hitObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
|
internal void OnNewResult(DrawableHitObject judgedObject, JudgementResult result)
|
||||||
{
|
{
|
||||||
if (!judgement.IsHit || !judgedObject.DisplayJudgement || !DisplayJudgements)
|
if (!result.IsHit || !judgedObject.DisplayResult || !DisplayJudgements)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
explosionContainer.Add(new HitExplosion(judgedObject)
|
explosionContainer.Add(new HitExplosion(judgedObject)
|
||||||
|
@ -10,8 +10,8 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
{
|
{
|
||||||
public class DrawableManiaJudgement : DrawableJudgement
|
public class DrawableManiaJudgement : DrawableJudgement
|
||||||
{
|
{
|
||||||
public DrawableManiaJudgement(Judgement judgement, DrawableHitObject judgedObject)
|
public DrawableManiaJudgement(JudgementResult result, DrawableHitObject judgedObject)
|
||||||
: base(judgement, judgedObject)
|
: base(result, judgedObject)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
|
|
||||||
this.FadeInFromZero(50, Easing.OutQuint);
|
this.FadeInFromZero(50, Easing.OutQuint);
|
||||||
|
|
||||||
if (Judgement.IsHit)
|
if (Result.IsHit)
|
||||||
{
|
{
|
||||||
this.ScaleTo(0.8f);
|
this.ScaleTo(0.8f);
|
||||||
this.ScaleTo(1, 250, Easing.OutElastic);
|
this.ScaleTo(1, 250, Easing.OutElastic);
|
||||||
|
@ -156,18 +156,18 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
var maniaObject = (ManiaHitObject)h.HitObject;
|
var maniaObject = (ManiaHitObject)h.HitObject;
|
||||||
int columnIndex = maniaObject.Column - firstColumnIndex;
|
int columnIndex = maniaObject.Column - firstColumnIndex;
|
||||||
Columns.ElementAt(columnIndex).Add(h);
|
Columns.ElementAt(columnIndex).Add(h);
|
||||||
h.OnJudgement += OnJudgement;
|
h.OnNewResult += OnNewResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Add(BarLine barline) => base.Add(new DrawableBarLine(barline));
|
public void Add(BarLine barline) => base.Add(new DrawableBarLine(barline));
|
||||||
|
|
||||||
internal void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
|
internal void OnNewResult(DrawableHitObject judgedObject, JudgementResult result)
|
||||||
{
|
{
|
||||||
if (!judgedObject.DisplayJudgement || !DisplayJudgements)
|
if (!judgedObject.DisplayResult || !DisplayJudgements)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
judgements.Clear();
|
judgements.Clear();
|
||||||
judgements.Add(new DrawableManiaJudgement(judgement, judgedObject)
|
judgements.Add(new DrawableManiaJudgement(result, judgedObject)
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
|
@ -5,12 +5,10 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||||
using osu.Game.Tests.Visual;
|
using osu.Game.Tests.Visual;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using osu.Game.Rulesets.Osu.Judgements;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System;
|
using System;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
@ -96,19 +94,15 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
this.auto = auto;
|
this.auto = auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||||
{
|
{
|
||||||
if (auto && !userTriggered && timeOffset > 0)
|
if (auto && !userTriggered && timeOffset > 0)
|
||||||
{
|
{
|
||||||
// force success
|
// force success
|
||||||
AddJudgement(new OsuJudgement
|
ApplyResult(r => r.Type = HitResult.Great);
|
||||||
{
|
|
||||||
Result = HitResult.Great
|
|
||||||
});
|
|
||||||
State.Value = ArmedState.Hit;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
base.CheckForJudgements(userTriggered, timeOffset);
|
base.CheckForResult(userTriggered, timeOffset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -304,13 +304,13 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
foreach (var mod in Mods.OfType<IApplicableToDrawableHitObjects>())
|
foreach (var mod in Mods.OfType<IApplicableToDrawableHitObjects>())
|
||||||
mod.ApplyToDrawableHitObjects(new[] { drawable });
|
mod.ApplyToDrawableHitObjects(new[] { drawable });
|
||||||
|
|
||||||
drawable.OnJudgement += onJudgement;
|
drawable.OnNewResult += onNewResult;
|
||||||
|
|
||||||
Add(drawable);
|
Add(drawable);
|
||||||
}
|
}
|
||||||
|
|
||||||
private float judgementOffsetDirection = 1;
|
private float judgementOffsetDirection = 1;
|
||||||
private void onJudgement(DrawableHitObject judgedObject, Judgement judgement)
|
private void onNewResult(DrawableHitObject judgedObject, JudgementResult result)
|
||||||
{
|
{
|
||||||
var osuObject = judgedObject as DrawableOsuHitObject;
|
var osuObject = judgedObject as DrawableOsuHitObject;
|
||||||
if (osuObject == null)
|
if (osuObject == null)
|
||||||
@ -321,8 +321,8 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Text = judgement.IsHit ? "Hit!" : "Miss!",
|
Text = result.IsHit ? "Hit!" : "Miss!",
|
||||||
Colour = judgement.IsHit ? Color4.Green : Color4.Red,
|
Colour = result.IsHit ? Color4.Green : Color4.Red,
|
||||||
TextSize = 30,
|
TextSize = 30,
|
||||||
Position = osuObject.HitObject.StackedEndPosition + judgementOffsetDirection * new Vector2(0, 45)
|
Position = osuObject.HitObject.StackedEndPosition + judgementOffsetDirection * new Vector2(0, 45)
|
||||||
});
|
});
|
||||||
|
@ -72,7 +72,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
this.auto = auto;
|
this.auto = auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||||
{
|
{
|
||||||
if (auto && !userTriggered && Time.Current > Spinner.StartTime + Spinner.Duration / 2 && Progress < 1)
|
if (auto && !userTriggered && Time.Current > Spinner.StartTime + Spinner.Duration / 2 && Progress < 1)
|
||||||
{
|
{
|
||||||
@ -81,7 +81,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
auto = false;
|
auto = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
base.CheckForJudgements(userTriggered, timeOffset);
|
base.CheckForResult(userTriggered, timeOffset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
17
osu.Game.Rulesets.Osu/Judgements/ComboResult.cs
Normal file
17
osu.Game.Rulesets.Osu/Judgements/ComboResult.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System.ComponentModel;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Judgements
|
||||||
|
{
|
||||||
|
public enum ComboResult
|
||||||
|
{
|
||||||
|
[Description(@"")]
|
||||||
|
None,
|
||||||
|
[Description(@"Good")]
|
||||||
|
Good,
|
||||||
|
[Description(@"Amazing")]
|
||||||
|
Perfect
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,6 @@
|
|||||||
// 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.Judgements;
|
||||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Judgements
|
namespace osu.Game.Rulesets.Osu.Judgements
|
||||||
@ -25,7 +24,5 @@ namespace osu.Game.Rulesets.Osu.Judgements
|
|||||||
return 300;
|
return 300;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ComboResult Combo;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
17
osu.Game.Rulesets.Osu/Judgements/OsuJudgementResult.cs
Normal file
17
osu.Game.Rulesets.Osu/Judgements/OsuJudgementResult.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// 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.Judgements;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Judgements
|
||||||
|
{
|
||||||
|
public class OsuJudgementResult : JudgementResult
|
||||||
|
{
|
||||||
|
public ComboResult ComboType;
|
||||||
|
|
||||||
|
public OsuJudgementResult(Judgement judgement)
|
||||||
|
: base(judgement)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -6,7 +6,6 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
|
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using osu.Game.Rulesets.Osu.Judgements;
|
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
@ -40,7 +39,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
if (AllJudged)
|
if (AllJudged)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
UpdateJudgement(true);
|
UpdateResult(true);
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -77,12 +76,13 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||||
{
|
{
|
||||||
if (!userTriggered)
|
if (!userTriggered)
|
||||||
{
|
{
|
||||||
if (!HitObject.HitWindows.CanBeHit(timeOffset))
|
if (!HitObject.HitWindows.CanBeHit(timeOffset))
|
||||||
AddJudgement(new OsuJudgement { Result = HitResult.Miss });
|
ApplyResult(r => r.Type = HitResult.Miss);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,10 +90,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
if (result == HitResult.None)
|
if (result == HitResult.None)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
AddJudgement(new OsuJudgement
|
ApplyResult(r => r.Type = result);
|
||||||
{
|
|
||||||
Result = result,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdatePreemptState()
|
protected override void UpdatePreemptState()
|
||||||
|
@ -2,11 +2,11 @@
|
|||||||
// 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 System;
|
using System;
|
||||||
using System.ComponentModel;
|
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using System.Linq;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
|
using osu.Game.Rulesets.Osu.Judgements;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
{
|
{
|
||||||
UpdatePreemptState();
|
UpdatePreemptState();
|
||||||
|
|
||||||
var judgementOffset = Math.Min(HitObject.HitWindows.HalfWindowFor(HitResult.Miss), Judgements.FirstOrDefault()?.TimeOffset ?? 0);
|
var judgementOffset = Math.Min(HitObject.HitWindows.HalfWindowFor(HitResult.Miss), Result?.TimeOffset ?? 0);
|
||||||
|
|
||||||
using (BeginDelayedSequence(HitObject.TimePreempt + judgementOffset, true))
|
using (BeginDelayedSequence(HitObject.TimePreempt + judgementOffset, true))
|
||||||
UpdateCurrentState(state);
|
UpdateCurrentState(state);
|
||||||
@ -57,20 +57,17 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
|
|
||||||
// Todo: At some point we need to move these to DrawableHitObject after ensuring that all other Rulesets apply
|
// Todo: At some point we need to move these to DrawableHitObject after ensuring that all other Rulesets apply
|
||||||
// transforms in the same way and don't rely on them not being cleared
|
// transforms in the same way and don't rely on them not being cleared
|
||||||
public override void ClearTransformsAfter(double time, bool propagateChildren = false, string targetMember = null) { }
|
public override void ClearTransformsAfter(double time, bool propagateChildren = false, string targetMember = null)
|
||||||
public override void ApplyTransformsAt(double time, bool propagateChildren = false) { }
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ApplyTransformsAt(double time, bool propagateChildren = false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
private OsuInputManager osuActionInputManager;
|
private OsuInputManager osuActionInputManager;
|
||||||
internal OsuInputManager OsuActionInputManager => osuActionInputManager ?? (osuActionInputManager = GetContainingInputManager() as OsuInputManager);
|
internal OsuInputManager OsuActionInputManager => osuActionInputManager ?? (osuActionInputManager = GetContainingInputManager() as OsuInputManager);
|
||||||
}
|
|
||||||
|
|
||||||
public enum ComboResult
|
protected override JudgementResult CreateResult(Judgement judgement) => new OsuJudgementResult(judgement);
|
||||||
{
|
|
||||||
[Description(@"")]
|
|
||||||
None,
|
|
||||||
[Description(@"Good")]
|
|
||||||
Good,
|
|
||||||
[Description(@"Amazing")]
|
|
||||||
Perfect
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,14 +11,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
{
|
{
|
||||||
public class DrawableOsuJudgement : DrawableJudgement
|
public class DrawableOsuJudgement : DrawableJudgement
|
||||||
{
|
{
|
||||||
public DrawableOsuJudgement(Judgement judgement, DrawableHitObject judgedObject)
|
public DrawableOsuJudgement(JudgementResult result, DrawableHitObject judgedObject)
|
||||||
: base(judgement, judgedObject)
|
: base(result, judgedObject)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
if (Judgement.Result != HitResult.Miss)
|
if (Result.Type != HitResult.Miss)
|
||||||
JudgementText?.TransformSpacingTo(new Vector2(14, 0), 1800, Easing.OutQuint);
|
JudgementText?.TransformSpacingTo(new Vector2(14, 0), 1800, Easing.OutQuint);
|
||||||
|
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
@ -8,7 +8,6 @@ using osu.Framework.MathUtils;
|
|||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Rulesets.Osu.Judgements;
|
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
@ -42,10 +41,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||||
{
|
{
|
||||||
if (repeatPoint.StartTime <= Time.Current)
|
if (repeatPoint.StartTime <= Time.Current)
|
||||||
AddJudgement(new OsuJudgement { Result = drawableSlider.Tracking ? HitResult.Great : HitResult.Miss });
|
ApplyResult(r => r.Type = drawableSlider.Tracking ? HitResult.Great : HitResult.Miss);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdatePreemptState()
|
protected override void UpdatePreemptState()
|
||||||
|
@ -9,7 +9,6 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Rulesets.Osu.Judgements;
|
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
@ -132,23 +131,27 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||||
{
|
{
|
||||||
if (!userTriggered && Time.Current >= slider.EndTime)
|
if (userTriggered || Time.Current < slider.EndTime)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ApplyResult(r =>
|
||||||
{
|
{
|
||||||
var judgementsCount = NestedHitObjects.Count();
|
var judgementsCount = NestedHitObjects.Count();
|
||||||
var judgementsHit = NestedHitObjects.Count(h => h.IsHit);
|
var judgementsHit = NestedHitObjects.Count(h => h.IsHit);
|
||||||
|
|
||||||
var hitFraction = (double)judgementsHit / judgementsCount;
|
var hitFraction = (double)judgementsHit / judgementsCount;
|
||||||
if (hitFraction == 1 && HeadCircle.Judgements.Any(j => j.Result == HitResult.Great))
|
|
||||||
AddJudgement(new OsuJudgement { Result = HitResult.Great });
|
if (hitFraction == 1 && HeadCircle.Result.Type == HitResult.Great)
|
||||||
else if (hitFraction >= 0.5 && HeadCircle.Judgements.Any(j => j.Result >= HitResult.Good))
|
r.Type = HitResult.Great;
|
||||||
AddJudgement(new OsuJudgement { Result = HitResult.Good });
|
else if (hitFraction >= 0.5 && HeadCircle.Result.Type >= HitResult.Good)
|
||||||
|
r.Type = HitResult.Good;
|
||||||
else if (hitFraction > 0)
|
else if (hitFraction > 0)
|
||||||
AddJudgement(new OsuJudgement { Result = HitResult.Meh });
|
r.Type = HitResult.Meh;
|
||||||
else
|
else
|
||||||
AddJudgement(new OsuJudgement { Result = HitResult.Miss });
|
r.Type = HitResult.Miss;
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdateCurrentState(ArmedState state)
|
protected override void UpdateCurrentState(ArmedState state)
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
// 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.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Rulesets.Osu.Judgements;
|
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||||
@ -12,11 +11,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The judgement text is provided by the <see cref="DrawableSlider"/>.
|
/// The judgement text is provided by the <see cref="DrawableSlider"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public override bool DisplayJudgement => false;
|
public override bool DisplayResult => false;
|
||||||
|
|
||||||
public bool Tracking { get; set; }
|
public bool Tracking { get; set; }
|
||||||
|
|
||||||
public DrawableSliderTail(Slider slider, HitCircle hitCircle)
|
public DrawableSliderTail(Slider slider, SliderTailCircle hitCircle)
|
||||||
: base(hitCircle)
|
: base(hitCircle)
|
||||||
{
|
{
|
||||||
Origin = Anchor.Centre;
|
Origin = Anchor.Centre;
|
||||||
@ -29,10 +28,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
Position = HitObject.Position - slider.Position;
|
Position = HitObject.Position - slider.Position;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||||
{
|
{
|
||||||
if (!userTriggered && timeOffset >= 0)
|
if (!userTriggered && timeOffset >= 0)
|
||||||
AddJudgement(new OsuSliderTailJudgement { Result = Tracking ? HitResult.Great : HitResult.Miss });
|
ApplyResult(r => r.Type = Tracking ? HitResult.Great : HitResult.Miss);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ using osu.Game.Rulesets.Objects.Drawables;
|
|||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Game.Rulesets.Osu.Judgements;
|
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
@ -19,7 +18,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
|
|
||||||
public bool Tracking { get; set; }
|
public bool Tracking { get; set; }
|
||||||
|
|
||||||
public override bool DisplayJudgement => false;
|
public override bool DisplayResult => false;
|
||||||
|
|
||||||
public DrawableSliderTick(SliderTick sliderTick) : base(sliderTick)
|
public DrawableSliderTick(SliderTick sliderTick) : base(sliderTick)
|
||||||
{
|
{
|
||||||
@ -48,10 +47,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||||
{
|
{
|
||||||
if (timeOffset >= 0)
|
if (timeOffset >= 0)
|
||||||
AddJudgement(new OsuJudgement { Result = Tracking ? HitResult.Great : HitResult.Miss });
|
ApplyResult(r => r.Type = Tracking ? HitResult.Great : HitResult.Miss);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdatePreemptState()
|
protected override void UpdatePreemptState()
|
||||||
|
@ -11,7 +11,6 @@ using OpenTK.Graphics;
|
|||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Game.Rulesets.Osu.Judgements;
|
|
||||||
using osu.Game.Screens.Ranking;
|
using osu.Game.Screens.Ranking;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
@ -117,7 +116,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
|
|
||||||
public float Progress => MathHelper.Clamp(Disc.RotationAbsolute / 360 / Spinner.SpinsRequired, 0, 1);
|
public float Progress => MathHelper.Clamp(Disc.RotationAbsolute / 360 / Spinner.SpinsRequired, 0, 1);
|
||||||
|
|
||||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||||
{
|
{
|
||||||
if (Time.Current < HitObject.StartTime) return;
|
if (Time.Current < HitObject.StartTime) return;
|
||||||
|
|
||||||
@ -136,17 +135,20 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
glow.FadeColour(completeColour, duration);
|
glow.FadeColour(completeColour, duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!userTriggered && Time.Current >= Spinner.EndTime)
|
if (userTriggered || Time.Current < Spinner.EndTime)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ApplyResult(r =>
|
||||||
{
|
{
|
||||||
if (Progress >= 1)
|
if (Progress >= 1)
|
||||||
AddJudgement(new OsuJudgement { Result = HitResult.Great });
|
r.Type = HitResult.Great;
|
||||||
else if (Progress > .9)
|
else if (Progress > .9)
|
||||||
AddJudgement(new OsuJudgement { Result = HitResult.Good });
|
r.Type = HitResult.Good;
|
||||||
else if (Progress > .75)
|
else if (Progress > .75)
|
||||||
AddJudgement(new OsuJudgement { Result = HitResult.Meh });
|
r.Type = HitResult.Meh;
|
||||||
else if (Time.Current >= Spinner.EndTime)
|
else if (Time.Current >= Spinner.EndTime)
|
||||||
AddJudgement(new OsuJudgement { Result = HitResult.Miss });
|
r.Type = HitResult.Miss;
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
|
@ -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.Osu.Judgements;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Objects
|
namespace osu.Game.Rulesets.Osu.Objects
|
||||||
{
|
{
|
||||||
public class HitCircle : OsuHitObject
|
public class HitCircle : OsuHitObject
|
||||||
{
|
{
|
||||||
|
public override Judgement CreateJudgement() => new OsuJudgement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
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.Osu.Judgements;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Objects
|
namespace osu.Game.Rulesets.Osu.Objects
|
||||||
{
|
{
|
||||||
@ -24,5 +26,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
if (RepeatIndex > 0)
|
if (RepeatIndex > 0)
|
||||||
TimePreempt = Math.Min(SpanDuration * 2, TimePreempt);
|
TimePreempt = Math.Min(SpanDuration * 2, TimePreempt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Judgement CreateJudgement() => new OsuJudgement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,8 @@ using System.Linq;
|
|||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
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.Osu.Judgements;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Objects
|
namespace osu.Game.Rulesets.Osu.Objects
|
||||||
{
|
{
|
||||||
@ -94,7 +96,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
public double TickDistance;
|
public double TickDistance;
|
||||||
|
|
||||||
public HitCircle HeadCircle;
|
public HitCircle HeadCircle;
|
||||||
public HitCircle TailCircle;
|
public SliderTailCircle TailCircle;
|
||||||
|
|
||||||
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||||
{
|
{
|
||||||
@ -133,7 +135,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
ComboIndex = ComboIndex,
|
ComboIndex = ComboIndex,
|
||||||
};
|
};
|
||||||
|
|
||||||
TailCircle = new SliderCircle(this)
|
TailCircle = new SliderTailCircle(this)
|
||||||
{
|
{
|
||||||
StartTime = EndTime,
|
StartTime = EndTime,
|
||||||
Position = EndPosition,
|
Position = EndPosition,
|
||||||
@ -211,5 +213,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Judgement CreateJudgement() => new OsuJudgement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
18
osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs
Normal file
18
osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// 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.Judgements;
|
||||||
|
using osu.Game.Rulesets.Osu.Judgements;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Objects
|
||||||
|
{
|
||||||
|
public class SliderTailCircle : SliderCircle
|
||||||
|
{
|
||||||
|
public SliderTailCircle(Slider slider)
|
||||||
|
: base(slider)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Judgement CreateJudgement() => new OsuSliderTailJudgement();
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
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.Osu.Judgements;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Objects
|
namespace osu.Game.Rulesets.Osu.Objects
|
||||||
{
|
{
|
||||||
@ -26,5 +28,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
|
|
||||||
TimePreempt = (StartTime - SpanStartTime) / 2 + offset;
|
TimePreempt = (StartTime - SpanStartTime) / 2 + offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Judgement CreateJudgement() => new OsuJudgement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,8 @@ using System;
|
|||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Game.Rulesets.Judgements;
|
||||||
|
using osu.Game.Rulesets.Osu.Judgements;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Objects
|
namespace osu.Game.Rulesets.Osu.Objects
|
||||||
{
|
{
|
||||||
@ -29,5 +31,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
// spinning doesn't match 1:1 with stable, so let's fudge them easier for the time being.
|
// spinning doesn't match 1:1 with stable, so let's fudge them easier for the time being.
|
||||||
SpinsRequired = (int)Math.Max(1, SpinsRequired * 0.6);
|
SpinsRequired = (int)Math.Max(1, SpinsRequired * 0.6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Judgement CreateJudgement() => new OsuJudgement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,13 +2,11 @@
|
|||||||
// 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 System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Osu.Judgements;
|
using osu.Game.Rulesets.Osu.Judgements;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
|
|
||||||
@ -26,28 +24,11 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
|||||||
private readonly Dictionary<HitResult, int> scoreResultCounts = new Dictionary<HitResult, int>();
|
private readonly Dictionary<HitResult, int> scoreResultCounts = new Dictionary<HitResult, int>();
|
||||||
private readonly Dictionary<ComboResult, int> comboResultCounts = new Dictionary<ComboResult, int>();
|
private readonly Dictionary<ComboResult, int> comboResultCounts = new Dictionary<ComboResult, int>();
|
||||||
|
|
||||||
protected override void SimulateAutoplay(Beatmap<OsuHitObject> beatmap)
|
protected override void ApplyBeatmap(Beatmap<OsuHitObject> beatmap)
|
||||||
{
|
{
|
||||||
|
base.ApplyBeatmap(beatmap);
|
||||||
|
|
||||||
hpDrainRate = beatmap.BeatmapInfo.BaseDifficulty.DrainRate;
|
hpDrainRate = beatmap.BeatmapInfo.BaseDifficulty.DrainRate;
|
||||||
|
|
||||||
foreach (var obj in beatmap.HitObjects)
|
|
||||||
{
|
|
||||||
if (obj is Slider slider)
|
|
||||||
{
|
|
||||||
// Head
|
|
||||||
AddJudgement(new OsuJudgement { Result = HitResult.Great });
|
|
||||||
|
|
||||||
// Ticks
|
|
||||||
foreach (var unused in slider.NestedHitObjects.OfType<SliderTick>())
|
|
||||||
AddJudgement(new OsuJudgement { Result = HitResult.Great });
|
|
||||||
|
|
||||||
//Repeats
|
|
||||||
foreach (var unused in slider.NestedHitObjects.OfType<RepeatPoint>())
|
|
||||||
AddJudgement(new OsuJudgement { Result = HitResult.Great });
|
|
||||||
}
|
|
||||||
|
|
||||||
AddJudgement(new OsuJudgement { Result = HitResult.Great });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Reset(bool storeResults)
|
protected override void Reset(bool storeResults)
|
||||||
@ -70,19 +51,19 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
|||||||
|
|
||||||
private const double harshness = 0.01;
|
private const double harshness = 0.01;
|
||||||
|
|
||||||
protected override void OnNewJudgement(Judgement judgement)
|
protected override void ApplyResult(JudgementResult result)
|
||||||
{
|
{
|
||||||
base.OnNewJudgement(judgement);
|
base.ApplyResult(result);
|
||||||
|
|
||||||
var osuJudgement = (OsuJudgement)judgement;
|
var osuResult = (OsuJudgementResult)result;
|
||||||
|
|
||||||
if (judgement.Result != HitResult.None)
|
if (result.Type != HitResult.None)
|
||||||
{
|
{
|
||||||
scoreResultCounts[judgement.Result] = scoreResultCounts.GetOrDefault(judgement.Result) + 1;
|
scoreResultCounts[result.Type] = scoreResultCounts.GetOrDefault(result.Type) + 1;
|
||||||
comboResultCounts[osuJudgement.Combo] = comboResultCounts.GetOrDefault(osuJudgement.Combo) + 1;
|
comboResultCounts[osuResult.ComboType] = comboResultCounts.GetOrDefault(osuResult.ComboType) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (judgement.Result)
|
switch (result.Type)
|
||||||
{
|
{
|
||||||
case HitResult.Great:
|
case HitResult.Great:
|
||||||
Health.Value += (10.2 - hpDrainRate) * harshness;
|
Health.Value += (10.2 - hpDrainRate) * harshness;
|
||||||
@ -105,5 +86,7 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override JudgementResult CreateResult(Judgement judgement) => new OsuJudgementResult(judgement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ namespace osu.Game.Rulesets.Osu.UI
|
|||||||
|
|
||||||
public override void Add(DrawableHitObject h)
|
public override void Add(DrawableHitObject h)
|
||||||
{
|
{
|
||||||
h.OnJudgement += onJudgement;
|
h.OnNewResult += onNewResult;
|
||||||
|
|
||||||
var c = h as IDrawableHitObjectWithProxiedApproach;
|
var c = h as IDrawableHitObjectWithProxiedApproach;
|
||||||
if (c != null)
|
if (c != null)
|
||||||
@ -64,12 +64,12 @@ namespace osu.Game.Rulesets.Osu.UI
|
|||||||
connectionLayer.HitObjects = HitObjects.Objects.Select(d => d.HitObject).OfType<OsuHitObject>();
|
connectionLayer.HitObjects = HitObjects.Objects.Select(d => d.HitObject).OfType<OsuHitObject>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onJudgement(DrawableHitObject judgedObject, Judgement judgement)
|
private void onNewResult(DrawableHitObject judgedObject, JudgementResult result)
|
||||||
{
|
{
|
||||||
if (!judgedObject.DisplayJudgement || !DisplayJudgements)
|
if (!judgedObject.DisplayResult || !DisplayJudgements)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
DrawableOsuJudgement explosion = new DrawableOsuJudgement(judgement, judgedObject)
|
DrawableOsuJudgement explosion = new DrawableOsuJudgement(result, judgedObject)
|
||||||
{
|
{
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Position = ((OsuHitObject)judgedObject.HitObject).StackedEndPosition
|
Position = ((OsuHitObject)judgedObject.HitObject).StackedEndPosition
|
||||||
|
@ -8,9 +8,9 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.MathUtils;
|
using osu.Framework.MathUtils;
|
||||||
using osu.Framework.Timing;
|
|
||||||
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.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Taiko.Judgements;
|
using osu.Game.Rulesets.Taiko.Judgements;
|
||||||
@ -39,8 +39,10 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
AddStep("Hit!", () => addHitJudgement(false));
|
AddStep("Hit", () => addHitJudgement(false));
|
||||||
|
AddStep("Strong hit", () => addStrongHitJudgement(false));
|
||||||
AddStep("Kiai hit", () => addHitJudgement(true));
|
AddStep("Kiai hit", () => addHitJudgement(true));
|
||||||
|
AddStep("Strong kiai hit", () => addStrongHitJudgement(true));
|
||||||
AddStep("Miss :(", addMissJudgement);
|
AddStep("Miss :(", addMissJudgement);
|
||||||
AddStep("DrumRoll", () => addDrumRoll(false));
|
AddStep("DrumRoll", () => addDrumRoll(false));
|
||||||
AddStep("Strong DrumRoll", () => addDrumRoll(true));
|
AddStep("Strong DrumRoll", () => addDrumRoll(true));
|
||||||
@ -78,15 +80,12 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
|||||||
ControlPointInfo = controlPointInfo
|
ControlPointInfo = controlPointInfo
|
||||||
});
|
});
|
||||||
|
|
||||||
var rateAdjustClock = new StopwatchClock(true) { Rate = 1 };
|
|
||||||
|
|
||||||
Add(playfieldContainer = new Container
|
Add(playfieldContainer = new Container
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
Height = 768,
|
Height = 768,
|
||||||
Clock = new FramedClock(rateAdjustClock),
|
|
||||||
Children = new[] { rulesetContainer = new TaikoRulesetContainer(new TaikoRuleset(), beatmap) }
|
Children = new[] { rulesetContainer = new TaikoRulesetContainer(new TaikoRuleset(), beatmap) }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -133,28 +132,35 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
|||||||
HitResult hitResult = RNG.Next(2) == 0 ? HitResult.Good : HitResult.Great;
|
HitResult hitResult = RNG.Next(2) == 0 ? HitResult.Good : HitResult.Great;
|
||||||
|
|
||||||
var cpi = new ControlPointInfo();
|
var cpi = new ControlPointInfo();
|
||||||
cpi.EffectPoints.Add(new EffectControlPoint
|
cpi.EffectPoints.Add(new EffectControlPoint { KiaiMode = kiai });
|
||||||
{
|
|
||||||
KiaiMode = kiai
|
|
||||||
});
|
|
||||||
|
|
||||||
Hit hit = new Hit();
|
Hit hit = new Hit();
|
||||||
hit.ApplyDefaults(cpi, new BeatmapDifficulty());
|
hit.ApplyDefaults(cpi, new BeatmapDifficulty());
|
||||||
|
|
||||||
var h = new DrawableTestHit(hit) { X = RNG.NextSingle(hitResult == HitResult.Good ? -0.1f : -0.05f, hitResult == HitResult.Good ? 0.1f : 0.05f) };
|
var h = new DrawableTestHit(hit) { X = RNG.NextSingle(hitResult == HitResult.Good ? -0.1f : -0.05f, hitResult == HitResult.Good ? 0.1f : 0.05f) };
|
||||||
|
|
||||||
((TaikoPlayfield)rulesetContainer.Playfield).OnJudgement(h, new TaikoJudgement { Result = hitResult });
|
((TaikoPlayfield)rulesetContainer.Playfield).OnNewResult(h, new JudgementResult(new TaikoJudgement()) { Type = hitResult });
|
||||||
|
}
|
||||||
|
|
||||||
if (RNG.Next(10) == 0)
|
private void addStrongHitJudgement(bool kiai)
|
||||||
{
|
{
|
||||||
((TaikoPlayfield)rulesetContainer.Playfield).OnJudgement(h, new TaikoJudgement { Result = hitResult });
|
HitResult hitResult = RNG.Next(2) == 0 ? HitResult.Good : HitResult.Great;
|
||||||
((TaikoPlayfield)rulesetContainer.Playfield).OnJudgement(h, new TaikoStrongHitJudgement());
|
|
||||||
}
|
var cpi = new ControlPointInfo();
|
||||||
|
cpi.EffectPoints.Add(new EffectControlPoint { KiaiMode = kiai });
|
||||||
|
|
||||||
|
Hit hit = new Hit();
|
||||||
|
hit.ApplyDefaults(cpi, new BeatmapDifficulty());
|
||||||
|
|
||||||
|
var h = new DrawableTestHit(hit) { X = RNG.NextSingle(hitResult == HitResult.Good ? -0.1f : -0.05f, hitResult == HitResult.Good ? 0.1f : 0.05f) };
|
||||||
|
|
||||||
|
((TaikoPlayfield)rulesetContainer.Playfield).OnNewResult(h, new JudgementResult(new TaikoJudgement()) { Type = hitResult });
|
||||||
|
((TaikoPlayfield)rulesetContainer.Playfield).OnNewResult(new TestStrongNestedHit(h), new JudgementResult(new TaikoStrongJudgement()) { Type = HitResult.Great });
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addMissJudgement()
|
private void addMissJudgement()
|
||||||
{
|
{
|
||||||
((TaikoPlayfield)rulesetContainer.Playfield).OnJudgement(new DrawableTestHit(new Hit()), new TaikoJudgement { Result = HitResult.Miss });
|
((TaikoPlayfield)rulesetContainer.Playfield).OnNewResult(new DrawableTestHit(new Hit()), new JudgementResult(new TaikoJudgement()) { Type = HitResult.Miss });
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addBarLine(bool major, double delay = scroll_time)
|
private void addBarLine(bool major, double delay = scroll_time)
|
||||||
@ -204,10 +210,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
|||||||
|
|
||||||
h.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
h.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||||
|
|
||||||
if (strong)
|
rulesetContainer.Playfield.Add(new DrawableCentreHit(h));
|
||||||
rulesetContainer.Playfield.Add(new DrawableCentreHitStrong(h));
|
|
||||||
else
|
|
||||||
rulesetContainer.Playfield.Add(new DrawableCentreHit(h));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addRimHit(bool strong)
|
private void addRimHit(bool strong)
|
||||||
@ -220,10 +223,17 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
|||||||
|
|
||||||
h.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
h.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||||
|
|
||||||
if (strong)
|
rulesetContainer.Playfield.Add(new DrawableRimHit(h));
|
||||||
rulesetContainer.Playfield.Add(new DrawableRimHitStrong(h));
|
}
|
||||||
else
|
|
||||||
rulesetContainer.Playfield.Add(new DrawableRimHit(h));
|
private class TestStrongNestedHit : DrawableStrongNestedHit
|
||||||
|
{
|
||||||
|
public TestStrongNestedHit(DrawableHitObject mainObject)
|
||||||
|
: base(null, mainObject)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool OnPressed(TaikoAction action) => false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DrawableTestHit : DrawableHitObject<TaikoHitObject>
|
private class DrawableTestHit : DrawableHitObject<TaikoHitObject>
|
||||||
|
@ -7,15 +7,10 @@ namespace osu.Game.Rulesets.Taiko.Judgements
|
|||||||
{
|
{
|
||||||
public class TaikoIntermediateSwellJudgement : TaikoJudgement
|
public class TaikoIntermediateSwellJudgement : TaikoJudgement
|
||||||
{
|
{
|
||||||
public override HitResult MaxResult => HitResult.Perfect;
|
public override HitResult MaxResult => HitResult.Great;
|
||||||
|
|
||||||
public override bool AffectsCombo => false;
|
public override bool AffectsCombo => false;
|
||||||
|
|
||||||
public TaikoIntermediateSwellJudgement()
|
|
||||||
{
|
|
||||||
Final = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Computes the numeric result value for the combo portion of the score.
|
/// Computes the numeric result value for the combo portion of the score.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -3,13 +3,8 @@
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.Judgements
|
namespace osu.Game.Rulesets.Taiko.Judgements
|
||||||
{
|
{
|
||||||
public class TaikoStrongHitJudgement : TaikoJudgement
|
public class TaikoStrongJudgement : TaikoJudgement
|
||||||
{
|
{
|
||||||
public override bool AffectsCombo => false;
|
public override bool AffectsCombo => false;
|
||||||
|
|
||||||
public TaikoStrongHitJudgement()
|
|
||||||
{
|
|
||||||
Final = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
{
|
{
|
||||||
public class DrawableCentreHit : DrawableHit
|
public class DrawableCentreHit : DrawableHit
|
||||||
{
|
{
|
||||||
protected override TaikoAction[] HitActions { get; } = { TaikoAction.LeftCentre, TaikoAction.RightCentre };
|
public override TaikoAction[] HitActions { get; } = { TaikoAction.LeftCentre, TaikoAction.RightCentre };
|
||||||
|
|
||||||
public DrawableCentreHit(Hit hit)
|
public DrawableCentreHit(Hit hit)
|
||||||
: base(hit)
|
: base(hit)
|
||||||
|
@ -1,26 +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.Framework.Allocation;
|
|
||||||
using osu.Game.Graphics;
|
|
||||||
using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|
||||||
{
|
|
||||||
public class DrawableCentreHitStrong : DrawableHitStrong
|
|
||||||
{
|
|
||||||
protected override TaikoAction[] HitActions { get; } = { TaikoAction.LeftCentre, TaikoAction.RightCentre };
|
|
||||||
|
|
||||||
public DrawableCentreHitStrong(Hit hit)
|
|
||||||
: base(hit)
|
|
||||||
{
|
|
||||||
MainPiece.Add(new CentreHitSymbolPiece());
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(OsuColour colours)
|
|
||||||
{
|
|
||||||
MainPiece.AccentColour = colours.PinkDarker;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,7 +6,6 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.MathUtils;
|
using osu.Framework.MathUtils;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Taiko.Judgements;
|
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces;
|
using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces;
|
||||||
@ -40,7 +39,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
foreach (var tick in drumRoll.NestedHitObjects.OfType<DrumRollTick>())
|
foreach (var tick in drumRoll.NestedHitObjects.OfType<DrumRollTick>())
|
||||||
{
|
{
|
||||||
var newTick = new DrawableDrumRollTick(tick);
|
var newTick = new DrawableDrumRollTick(tick);
|
||||||
newTick.OnJudgement += onTickJudgement;
|
newTick.OnNewResult += onNewTickResult;
|
||||||
|
|
||||||
AddNested(newTick);
|
AddNested(newTick);
|
||||||
tickContainer.Add(newTick);
|
tickContainer.Add(newTick);
|
||||||
@ -61,9 +60,9 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
colourEngaged = colours.YellowDarker;
|
colourEngaged = colours.YellowDarker;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onTickJudgement(DrawableHitObject obj, Judgement judgement)
|
private void onNewTickResult(DrawableHitObject obj, JudgementResult result)
|
||||||
{
|
{
|
||||||
if (judgement.Result > HitResult.Miss)
|
if (result.Type > HitResult.Miss)
|
||||||
rollingHits++;
|
rollingHits++;
|
||||||
else
|
else
|
||||||
rollingHits--;
|
rollingHits--;
|
||||||
@ -74,7 +73,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
MainPiece.FadeAccent(newColour, 100);
|
MainPiece.FadeAccent(newColour, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||||
{
|
{
|
||||||
if (userTriggered)
|
if (userTriggered)
|
||||||
return;
|
return;
|
||||||
@ -84,13 +83,9 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
|
|
||||||
int countHit = NestedHitObjects.Count(o => o.IsHit);
|
int countHit = NestedHitObjects.Count(o => o.IsHit);
|
||||||
if (countHit >= HitObject.RequiredGoodHits)
|
if (countHit >= HitObject.RequiredGoodHits)
|
||||||
{
|
ApplyResult(r => r.Type = countHit >= HitObject.RequiredGreatHits ? HitResult.Great : HitResult.Good);
|
||||||
AddJudgement(new TaikoJudgement { Result = countHit >= HitObject.RequiredGreatHits ? HitResult.Great : HitResult.Good });
|
|
||||||
if (HitObject.IsStrong)
|
|
||||||
AddJudgement(new TaikoStrongHitJudgement());
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
AddJudgement(new TaikoJudgement { Result = HitResult.Miss });
|
ApplyResult(r => r.Type = HitResult.Miss);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdateState(ArmedState state)
|
protected override void UpdateState(ArmedState state)
|
||||||
@ -103,5 +98,25 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override DrawableStrongNestedHit CreateStrongHit(StrongHitObject hitObject) => new StrongNestedHit(hitObject, this);
|
||||||
|
|
||||||
|
private class StrongNestedHit : DrawableStrongNestedHit
|
||||||
|
{
|
||||||
|
public StrongNestedHit(StrongHitObject strong, DrawableDrumRoll drumRoll)
|
||||||
|
: base(strong, drumRoll)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||||
|
{
|
||||||
|
if (!MainObject.Judged)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ApplyResult(r => r.Type = MainObject.IsHit ? HitResult.Great : HitResult.Miss);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool OnPressed(TaikoAction action) => false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ using System;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.Taiko.Judgements;
|
|
||||||
using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces;
|
using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||||
@ -18,24 +17,26 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
FillMode = FillMode.Fit;
|
FillMode = FillMode.Fit;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool DisplayJudgement => false;
|
public override bool DisplayResult => false;
|
||||||
|
|
||||||
protected override TaikoPiece CreateMainPiece() => new TickPiece
|
protected override TaikoPiece CreateMainPiece() => new TickPiece
|
||||||
{
|
{
|
||||||
Filled = HitObject.FirstTick
|
Filled = HitObject.FirstTick
|
||||||
};
|
};
|
||||||
|
|
||||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||||
{
|
{
|
||||||
if (!userTriggered)
|
if (!userTriggered)
|
||||||
|
{
|
||||||
|
if (timeOffset > HitObject.HitWindow)
|
||||||
|
ApplyResult(r => r.Type = HitResult.Miss);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Math.Abs(timeOffset) > HitObject.HitWindow)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!(Math.Abs(timeOffset) < HitObject.HitWindow))
|
ApplyResult(r => r.Type = HitResult.Great);
|
||||||
return;
|
|
||||||
|
|
||||||
AddJudgement(new TaikoDrumRollTickJudgement { Result = HitResult.Great });
|
|
||||||
if (HitObject.IsStrong)
|
|
||||||
AddJudgement(new TaikoStrongHitJudgement());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdateState(ArmedState state)
|
protected override void UpdateState(ArmedState state)
|
||||||
@ -48,6 +49,26 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool OnPressed(TaikoAction action) => UpdateJudgement(true);
|
public override bool OnPressed(TaikoAction action) => UpdateResult(true);
|
||||||
|
|
||||||
|
protected override DrawableStrongNestedHit CreateStrongHit(StrongHitObject hitObject) => new StrongNestedHit(hitObject, this);
|
||||||
|
|
||||||
|
private class StrongNestedHit : DrawableStrongNestedHit
|
||||||
|
{
|
||||||
|
public StrongNestedHit(StrongHitObject strong, DrawableDrumRollTick tick)
|
||||||
|
: base(strong, tick)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||||
|
{
|
||||||
|
if (!MainObject.Judged)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ApplyResult(r => r.Type = MainObject.IsHit ? HitResult.Great : HitResult.Miss);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool OnPressed(TaikoAction action) => false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
// 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 System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.Taiko.Judgements;
|
|
||||||
using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces;
|
using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||||
@ -15,17 +15,14 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A list of keys which can result in hits for this HitObject.
|
/// A list of keys which can result in hits for this HitObject.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected abstract TaikoAction[] HitActions { get; }
|
public abstract TaikoAction[] HitActions { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether a second hit is allowed to be processed. This occurs once this hit object has been hit successfully.
|
/// The action that caused this <see cref="DrawableHit"/> to be hit.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected bool SecondHitAllowed { get; private set; }
|
public TaikoAction? HitAction { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
private bool validActionPressed;
|
||||||
/// Whether the last key pressed is a valid hit key.
|
|
||||||
/// </summary>
|
|
||||||
private bool validKeyPressed;
|
|
||||||
|
|
||||||
protected DrawableHit(Hit hit)
|
protected DrawableHit(Hit hit)
|
||||||
: base(hit)
|
: base(hit)
|
||||||
@ -33,12 +30,12 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
FillMode = FillMode.Fit;
|
FillMode = FillMode.Fit;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||||
{
|
{
|
||||||
if (!userTriggered)
|
if (!userTriggered)
|
||||||
{
|
{
|
||||||
if (!HitObject.HitWindows.CanBeHit(timeOffset))
|
if (!HitObject.HitWindows.CanBeHit(timeOffset))
|
||||||
AddJudgement(new TaikoJudgement { Result = HitResult.Miss });
|
ApplyResult(r => r.Type = HitResult.Miss);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,26 +43,33 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
if (result == HitResult.None)
|
if (result == HitResult.None)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!validKeyPressed || result == HitResult.Miss)
|
if (!validActionPressed)
|
||||||
AddJudgement(new TaikoJudgement { Result = HitResult.Miss });
|
ApplyResult(r => r.Type = HitResult.Miss);
|
||||||
else
|
else
|
||||||
{
|
ApplyResult(r => r.Type = result);
|
||||||
AddJudgement(new TaikoJudgement
|
|
||||||
{
|
|
||||||
Result = result,
|
|
||||||
Final = !HitObject.IsStrong
|
|
||||||
});
|
|
||||||
|
|
||||||
SecondHitAllowed = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool OnPressed(TaikoAction action)
|
public override bool OnPressed(TaikoAction action)
|
||||||
{
|
{
|
||||||
validKeyPressed = HitActions.Contains(action);
|
if (Judged)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
validActionPressed = HitActions.Contains(action);
|
||||||
|
|
||||||
// Only count this as handled if the new judgement is a hit
|
// Only count this as handled if the new judgement is a hit
|
||||||
return UpdateJudgement(true);
|
var result = UpdateResult(true);
|
||||||
|
|
||||||
|
if (IsHit)
|
||||||
|
HitAction = action;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool OnReleased(TaikoAction action)
|
||||||
|
{
|
||||||
|
if (action == HitAction)
|
||||||
|
HitAction = null;
|
||||||
|
return base.OnReleased(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
@ -86,8 +90,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
switch (State.Value)
|
switch (State.Value)
|
||||||
{
|
{
|
||||||
case ArmedState.Idle:
|
case ArmedState.Idle:
|
||||||
SecondHitAllowed = false;
|
validActionPressed = false;
|
||||||
validKeyPressed = false;
|
|
||||||
|
|
||||||
UnproxyContent();
|
UnproxyContent();
|
||||||
this.Delay(HitObject.HitWindows.HalfWindowFor(HitResult.Miss)).Expire();
|
this.Delay(HitObject.HitWindows.HalfWindowFor(HitResult.Miss)).Expire();
|
||||||
@ -123,5 +126,65 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override DrawableStrongNestedHit CreateStrongHit(StrongHitObject hitObject) => new StrongNestedHit(hitObject, this);
|
||||||
|
|
||||||
|
private class StrongNestedHit : DrawableStrongNestedHit
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The lenience for the second key press.
|
||||||
|
/// This does not adjust by map difficulty in ScoreV2 yet.
|
||||||
|
/// </summary>
|
||||||
|
private const double second_hit_window = 30;
|
||||||
|
|
||||||
|
public new DrawableHit MainObject => (DrawableHit)base.MainObject;
|
||||||
|
|
||||||
|
public StrongNestedHit(StrongHitObject strong, DrawableHit hit)
|
||||||
|
: base(strong, hit)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||||
|
{
|
||||||
|
if (!MainObject.Result.HasResult)
|
||||||
|
{
|
||||||
|
base.CheckForResult(userTriggered, timeOffset);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!MainObject.Result.IsHit)
|
||||||
|
{
|
||||||
|
ApplyResult(r => r.Type = HitResult.Miss);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!userTriggered)
|
||||||
|
{
|
||||||
|
if (timeOffset > second_hit_window)
|
||||||
|
ApplyResult(r => r.Type = HitResult.Miss);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Math.Abs(MainObject.Result.TimeOffset - timeOffset) < second_hit_window)
|
||||||
|
ApplyResult(r => r.Type = HitResult.Great);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool OnPressed(TaikoAction action)
|
||||||
|
{
|
||||||
|
// Don't process actions until the main hitobject is hit
|
||||||
|
if (!MainObject.IsHit)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Don't process actions if the pressed button was released
|
||||||
|
if (MainObject.HitAction == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Don't handle invalid hit action presses
|
||||||
|
if (!MainObject.HitActions.Contains(action))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return UpdateResult(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,103 +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 System;
|
|
||||||
using System.Linq;
|
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
|
||||||
using osu.Game.Rulesets.Scoring;
|
|
||||||
using osu.Game.Rulesets.Taiko.Judgements;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|
||||||
{
|
|
||||||
public abstract class DrawableHitStrong : DrawableHit
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The lenience for the second key press.
|
|
||||||
/// This does not adjust by map difficulty in ScoreV2 yet.
|
|
||||||
/// </summary>
|
|
||||||
private const double second_hit_window = 30;
|
|
||||||
|
|
||||||
private double firstHitTime;
|
|
||||||
private bool firstKeyHeld;
|
|
||||||
private TaikoAction firstHitAction;
|
|
||||||
|
|
||||||
protected DrawableHitStrong(Hit hit)
|
|
||||||
: base(hit)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
|
||||||
{
|
|
||||||
if (!SecondHitAllowed)
|
|
||||||
{
|
|
||||||
base.CheckForJudgements(userTriggered, timeOffset);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!userTriggered)
|
|
||||||
{
|
|
||||||
if (timeOffset > second_hit_window)
|
|
||||||
AddJudgement(new TaikoStrongHitJudgement { Result = HitResult.None });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we get here, we're assured that the key pressed is the correct secondary key
|
|
||||||
|
|
||||||
if (Math.Abs(firstHitTime - Time.Current) < second_hit_window)
|
|
||||||
AddJudgement(new TaikoStrongHitJudgement { Result = HitResult.Great });
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void UpdateState(ArmedState state)
|
|
||||||
{
|
|
||||||
base.UpdateState(state);
|
|
||||||
|
|
||||||
switch (state)
|
|
||||||
{
|
|
||||||
case ArmedState.Idle:
|
|
||||||
firstHitTime = 0;
|
|
||||||
firstKeyHeld = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool OnReleased(TaikoAction action)
|
|
||||||
{
|
|
||||||
if (action == firstHitAction)
|
|
||||||
firstKeyHeld = false;
|
|
||||||
return base.OnReleased(action);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool OnPressed(TaikoAction action)
|
|
||||||
{
|
|
||||||
if (AllJudged)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Check if we've handled the first key
|
|
||||||
if (!SecondHitAllowed)
|
|
||||||
{
|
|
||||||
// First key hasn't been handled yet, attempt to handle it
|
|
||||||
bool handled = base.OnPressed(action);
|
|
||||||
|
|
||||||
if (handled)
|
|
||||||
{
|
|
||||||
firstHitTime = Time.Current;
|
|
||||||
firstHitAction = action;
|
|
||||||
firstKeyHeld = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return handled;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't handle represses of the first key
|
|
||||||
if (firstHitAction == action)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Don't handle invalid hit action presses
|
|
||||||
if (!HitActions.Contains(action))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Assume the intention was to hit the strong hit with both keys only if the first key is still being held down
|
|
||||||
return firstKeyHeld && UpdateJudgement(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
{
|
{
|
||||||
public class DrawableRimHit : DrawableHit
|
public class DrawableRimHit : DrawableHit
|
||||||
{
|
{
|
||||||
protected override TaikoAction[] HitActions { get; } = { TaikoAction.LeftRim, TaikoAction.RightRim };
|
public override TaikoAction[] HitActions { get; } = { TaikoAction.LeftRim, TaikoAction.RightRim };
|
||||||
|
|
||||||
public DrawableRimHit(Hit hit)
|
public DrawableRimHit(Hit hit)
|
||||||
: base(hit)
|
: base(hit)
|
||||||
|
@ -1,26 +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.Framework.Allocation;
|
|
||||||
using osu.Game.Graphics;
|
|
||||||
using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|
||||||
{
|
|
||||||
public class DrawableRimHitStrong : DrawableHitStrong
|
|
||||||
{
|
|
||||||
protected override TaikoAction[] HitActions { get; } = { TaikoAction.LeftRim, TaikoAction.RightRim };
|
|
||||||
|
|
||||||
public DrawableRimHitStrong(Hit hit)
|
|
||||||
: base(hit)
|
|
||||||
{
|
|
||||||
MainPiece.Add(new RimHitSymbolPiece());
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(OsuColour colours)
|
|
||||||
{
|
|
||||||
MainPiece.AccentColour = colours.BlueDarker;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,26 @@
|
|||||||
|
// 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.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.Taiko.Judgements;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Used as a nested hitobject to provide <see cref="TaikoStrongJudgement"/>s for <see cref="DrawableTaikoHitObject"/>s.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class DrawableStrongNestedHit : DrawableTaikoHitObject
|
||||||
|
{
|
||||||
|
public readonly DrawableHitObject MainObject;
|
||||||
|
|
||||||
|
protected DrawableStrongNestedHit(StrongHitObject strong, DrawableHitObject mainObject)
|
||||||
|
: base(strong)
|
||||||
|
{
|
||||||
|
MainObject = mainObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void UpdateState(ArmedState state)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,8 @@
|
|||||||
// 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 System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
@ -12,23 +14,19 @@ using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces;
|
|||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Game.Rulesets.Taiko.Judgements;
|
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||||
{
|
{
|
||||||
public class DrawableSwell : DrawableTaikoHitObject<Swell>
|
public class DrawableSwell : DrawableTaikoHitObject<Swell>
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// A judgement is only displayed when the user has complete the swell (either a hit or miss).
|
|
||||||
/// </summary>
|
|
||||||
public override bool DisplayJudgement => AllJudged;
|
|
||||||
|
|
||||||
private const float target_ring_thick_border = 1.4f;
|
private const float target_ring_thick_border = 1.4f;
|
||||||
private const float target_ring_thin_border = 1f;
|
private const float target_ring_thin_border = 1f;
|
||||||
private const float target_ring_scale = 5f;
|
private const float target_ring_scale = 5f;
|
||||||
private const float inner_ring_alpha = 0.65f;
|
private const float inner_ring_alpha = 0.65f;
|
||||||
|
|
||||||
|
private readonly List<DrawableSwellTick> ticks = new List<DrawableSwellTick>();
|
||||||
|
|
||||||
private readonly Container bodyContainer;
|
private readonly Container bodyContainer;
|
||||||
private readonly CircularContainer targetRing;
|
private readonly CircularContainer targetRing;
|
||||||
private readonly CircularContainer expandingRing;
|
private readonly CircularContainer expandingRing;
|
||||||
@ -106,6 +104,15 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
});
|
});
|
||||||
|
|
||||||
MainPiece.Add(symbol = new SwellSymbolPiece());
|
MainPiece.Add(symbol = new SwellSymbolPiece());
|
||||||
|
|
||||||
|
foreach (var tick in HitObject.NestedHitObjects.OfType<SwellTick>())
|
||||||
|
{
|
||||||
|
var vis = new DrawableSwellTick(tick);
|
||||||
|
|
||||||
|
ticks.Add(vis);
|
||||||
|
AddInternal(vis);
|
||||||
|
AddNested(vis);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
@ -124,13 +131,17 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
Width *= Parent.RelativeChildSize.X;
|
Width *= Parent.RelativeChildSize.X;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||||
{
|
{
|
||||||
if (userTriggered)
|
if (userTriggered)
|
||||||
{
|
{
|
||||||
AddJudgement(new TaikoIntermediateSwellJudgement());
|
var nextTick = ticks.FirstOrDefault(j => !j.IsHit);
|
||||||
|
|
||||||
var completion = (float)Judgements.Count / HitObject.RequiredHits;
|
nextTick?.TriggerResult(HitResult.Great);
|
||||||
|
|
||||||
|
var numHits = ticks.Count(r => r.IsHit);
|
||||||
|
|
||||||
|
var completion = (float)numHits / HitObject.RequiredHits;
|
||||||
|
|
||||||
expandingRing
|
expandingRing
|
||||||
.FadeTo(expandingRing.Alpha + MathHelper.Clamp(completion / 16, 0.1f, 0.6f), 50)
|
.FadeTo(expandingRing.Alpha + MathHelper.Clamp(completion / 16, 0.1f, 0.6f), 50)
|
||||||
@ -141,18 +152,30 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
|
|
||||||
expandingRing.ScaleTo(1f + Math.Min(target_ring_scale - 1f, (target_ring_scale - 1f) * completion * 1.3f), 260, Easing.OutQuint);
|
expandingRing.ScaleTo(1f + Math.Min(target_ring_scale - 1f, (target_ring_scale - 1f) * completion * 1.3f), 260, Easing.OutQuint);
|
||||||
|
|
||||||
if (Judgements.Count == HitObject.RequiredHits)
|
if (numHits == HitObject.RequiredHits)
|
||||||
AddJudgement(new TaikoJudgement { Result = HitResult.Great });
|
ApplyResult(r => r.Type = HitResult.Great);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (timeOffset < 0)
|
if (timeOffset < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//TODO: THIS IS SHIT AND CAN'T EXIST POST-TAIKO WORLD CUP
|
int numHits = 0;
|
||||||
AddJudgement(Judgements.Count > HitObject.RequiredHits / 2
|
|
||||||
? new TaikoJudgement { Result = HitResult.Good }
|
foreach (var tick in ticks)
|
||||||
: new TaikoJudgement { Result = HitResult.Miss });
|
{
|
||||||
|
if (tick.IsHit)
|
||||||
|
{
|
||||||
|
numHits++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
tick.TriggerResult(HitResult.Miss);
|
||||||
|
}
|
||||||
|
|
||||||
|
var hitResult = numHits > HitObject.RequiredHits / 2 ? HitResult.Good : HitResult.Miss;
|
||||||
|
|
||||||
|
ApplyResult(r => r.Type = hitResult);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,7 +231,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
return false;
|
return false;
|
||||||
lastWasCentre = isCentre;
|
lastWasCentre = isCentre;
|
||||||
|
|
||||||
UpdateJudgement(true);
|
UpdateResult(true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
// 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.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||||
|
{
|
||||||
|
public class DrawableSwellTick : DrawableTaikoHitObject
|
||||||
|
{
|
||||||
|
public override bool DisplayResult => false;
|
||||||
|
|
||||||
|
public DrawableSwellTick(TaikoHitObject hitObject)
|
||||||
|
: base(hitObject)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void TriggerResult(HitResult type) => ApplyResult(r => r.Type = type);
|
||||||
|
|
||||||
|
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void UpdateState(ArmedState state)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool OnPressed(TaikoAction action) => false;
|
||||||
|
}
|
||||||
|
}
|
@ -101,6 +101,15 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
|
|
||||||
Content.Add(MainPiece = CreateMainPiece());
|
Content.Add(MainPiece = CreateMainPiece());
|
||||||
MainPiece.KiaiMode = HitObject.Kiai;
|
MainPiece.KiaiMode = HitObject.Kiai;
|
||||||
|
|
||||||
|
var strongObject = HitObject.NestedHitObjects.OfType<StrongHitObject>().FirstOrDefault();
|
||||||
|
if (strongObject != null)
|
||||||
|
{
|
||||||
|
var strongHit = CreateStrongHit(strongObject);
|
||||||
|
|
||||||
|
AddNested(strongHit);
|
||||||
|
AddInternal(strongHit);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normal and clap samples are handled by the drum
|
// Normal and clap samples are handled by the drum
|
||||||
@ -109,5 +118,13 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
protected override string SampleNamespace => "Taiko";
|
protected override string SampleNamespace => "Taiko";
|
||||||
|
|
||||||
protected virtual TaikoPiece CreateMainPiece() => new CirclePiece();
|
protected virtual TaikoPiece CreateMainPiece() => new CirclePiece();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates the handler for this <see cref="DrawableHitObject"/>'s <see cref="StrongHitObject"/>.
|
||||||
|
/// This is only invoked if <see cref="TaikoHitObject.IsStrong"/> is true for <see cref="HitObject"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hitObject">The strong hitobject.</param>
|
||||||
|
/// <returns>The strong hitobject handler.</returns>
|
||||||
|
protected virtual DrawableStrongNestedHit CreateStrongHit(StrongHitObject hitObject) => null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,12 +54,12 @@ namespace osu.Game.Rulesets.Taiko.Objects
|
|||||||
|
|
||||||
protected override void CreateNestedHitObjects()
|
protected override void CreateNestedHitObjects()
|
||||||
{
|
{
|
||||||
base.CreateNestedHitObjects();
|
|
||||||
|
|
||||||
createTicks();
|
createTicks();
|
||||||
|
|
||||||
RequiredGoodHits = NestedHitObjects.Count * Math.Min(0.15, 0.05 + 0.10 / 6 * overallDifficulty);
|
RequiredGoodHits = NestedHitObjects.Count * Math.Min(0.15, 0.05 + 0.10 / 6 * overallDifficulty);
|
||||||
RequiredGreatHits = NestedHitObjects.Count * Math.Min(0.30, 0.10 + 0.20 / 6 * overallDifficulty);
|
RequiredGreatHits = NestedHitObjects.Count * Math.Min(0.30, 0.10 + 0.20 / 6 * overallDifficulty);
|
||||||
|
|
||||||
|
base.CreateNestedHitObjects();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createTicks()
|
private void createTicks()
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
// 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 DrumRollTick : TaikoHitObject
|
public class DrumRollTick : TaikoHitObject
|
||||||
@ -20,5 +23,7 @@ namespace osu.Game.Rulesets.Taiko.Objects
|
|||||||
/// The time allowed to hit this tick.
|
/// The time allowed to hit this tick.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double HitWindow => TickSpacing / 2;
|
public double HitWindow => TickSpacing / 2;
|
||||||
|
|
||||||
|
public override Judgement CreateJudgement() => new TaikoDrumRollTickJudgement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
13
osu.Game.Rulesets.Taiko/Objects/StrongHitObject.cs
Normal file
13
osu.Game.Rulesets.Taiko/Objects/StrongHitObject.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// 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.Judgements;
|
||||||
|
using osu.Game.Rulesets.Taiko.Judgements;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Taiko.Objects
|
||||||
|
{
|
||||||
|
public class StrongHitObject : TaikoHitObject
|
||||||
|
{
|
||||||
|
public override Judgement CreateJudgement() => new TaikoStrongJudgement();
|
||||||
|
}
|
||||||
|
}
|
@ -15,5 +15,13 @@ namespace osu.Game.Rulesets.Taiko.Objects
|
|||||||
/// The number of hits required to complete the swell successfully.
|
/// The number of hits required to complete the swell successfully.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int RequiredHits = 10;
|
public int RequiredHits = 10;
|
||||||
|
|
||||||
|
protected override void CreateNestedHitObjects()
|
||||||
|
{
|
||||||
|
base.CreateNestedHitObjects();
|
||||||
|
|
||||||
|
for (int i = 0; i < RequiredHits; i++)
|
||||||
|
AddNested(new SwellTick());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
9
osu.Game.Rulesets.Taiko/Objects/SwellTick.cs
Normal file
9
osu.Game.Rulesets.Taiko/Objects/SwellTick.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Taiko.Objects
|
||||||
|
{
|
||||||
|
public class SwellTick : TaikoHitObject
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,10 @@
|
|||||||
// 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.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
|
using osu.Game.Rulesets.Taiko.Judgements;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.Objects
|
namespace osu.Game.Rulesets.Taiko.Objects
|
||||||
{
|
{
|
||||||
@ -28,6 +31,16 @@ namespace osu.Game.Rulesets.Taiko.Objects
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsStrong;
|
public bool IsStrong;
|
||||||
|
|
||||||
|
protected override void CreateNestedHitObjects()
|
||||||
|
{
|
||||||
|
base.CreateNestedHitObjects();
|
||||||
|
|
||||||
|
if (IsStrong)
|
||||||
|
AddNested(new StrongHitObject { StartTime = (this as IHasEndTime)?.EndTime ?? StartTime });
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Judgement CreateJudgement() => new TaikoJudgement();
|
||||||
|
|
||||||
protected override HitWindows CreateHitWindows() => new TaikoHitWindows();
|
protected override HitWindows CreateHitWindows() => new TaikoHitWindows();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// 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 System.Linq;
|
|
||||||
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;
|
||||||
@ -60,63 +59,31 @@ namespace osu.Game.Rulesets.Taiko.Scoring
|
|||||||
private double hpIncreaseGood;
|
private double hpIncreaseGood;
|
||||||
private double hpIncreaseMiss;
|
private double hpIncreaseMiss;
|
||||||
|
|
||||||
public TaikoScoreProcessor()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public TaikoScoreProcessor(RulesetContainer<TaikoHitObject> rulesetContainer)
|
public TaikoScoreProcessor(RulesetContainer<TaikoHitObject> rulesetContainer)
|
||||||
: base(rulesetContainer)
|
: base(rulesetContainer)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void SimulateAutoplay(Beatmap<TaikoHitObject> beatmap)
|
protected override void ApplyBeatmap(Beatmap<TaikoHitObject> 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));
|
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));
|
||||||
|
|
||||||
hpIncreaseTick = hp_hit_tick;
|
hpIncreaseTick = hp_hit_tick;
|
||||||
hpIncreaseGreat = hpMultiplierNormal * hp_hit_great;
|
hpIncreaseGreat = hpMultiplierNormal * hp_hit_great;
|
||||||
hpIncreaseGood = hpMultiplierNormal * hp_hit_good;
|
hpIncreaseGood = hpMultiplierNormal * hp_hit_good;
|
||||||
hpIncreaseMiss = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, hp_miss_min, hp_miss_mid, hp_miss_max);
|
hpIncreaseMiss = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, hp_miss_min, hp_miss_mid, hp_miss_max);
|
||||||
|
|
||||||
foreach (var obj in beatmap.HitObjects)
|
|
||||||
{
|
|
||||||
switch (obj)
|
|
||||||
{
|
|
||||||
case Hit _:
|
|
||||||
AddJudgement(new TaikoJudgement { Result = HitResult.Great });
|
|
||||||
if (obj.IsStrong)
|
|
||||||
AddJudgement(new TaikoStrongHitJudgement());
|
|
||||||
break;
|
|
||||||
case DrumRoll drumRoll:
|
|
||||||
var count = drumRoll.NestedHitObjects.OfType<DrumRollTick>().Count();
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
AddJudgement(new TaikoDrumRollTickJudgement { Result = HitResult.Great });
|
|
||||||
|
|
||||||
if (obj.IsStrong)
|
|
||||||
AddJudgement(new TaikoStrongHitJudgement());
|
|
||||||
}
|
|
||||||
|
|
||||||
AddJudgement(new TaikoJudgement { Result = HitResult.Great });
|
|
||||||
|
|
||||||
if (obj.IsStrong)
|
|
||||||
AddJudgement(new TaikoStrongHitJudgement());
|
|
||||||
break;
|
|
||||||
case Swell _:
|
|
||||||
AddJudgement(new TaikoJudgement { Result = HitResult.Great });
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnNewJudgement(Judgement judgement)
|
protected override void ApplyResult(JudgementResult result)
|
||||||
{
|
{
|
||||||
base.OnNewJudgement(judgement);
|
base.ApplyResult(result);
|
||||||
|
|
||||||
bool isTick = judgement is TaikoDrumRollTickJudgement;
|
bool isTick = result.Judgement is TaikoDrumRollTickJudgement;
|
||||||
|
|
||||||
// Apply HP changes
|
// Apply HP changes
|
||||||
switch (judgement.Result)
|
switch (result.Type)
|
||||||
{
|
{
|
||||||
case HitResult.Miss:
|
case HitResult.Miss:
|
||||||
// Missing ticks shouldn't drop HP
|
// Missing ticks shouldn't drop HP
|
||||||
|
@ -19,16 +19,16 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
/// Creates a new judgement text.
|
/// Creates a new judgement text.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="judgedObject">The object which is being judged.</param>
|
/// <param name="judgedObject">The object which is being judged.</param>
|
||||||
/// <param name="judgement">The judgement to visualise.</param>
|
/// <param name="result">The judgement to visualise.</param>
|
||||||
public DrawableTaikoJudgement(Judgement judgement, DrawableHitObject judgedObject)
|
public DrawableTaikoJudgement(JudgementResult result, DrawableHitObject judgedObject)
|
||||||
: base(judgement, judgedObject)
|
: base(result, judgedObject)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load(OsuColour colours)
|
||||||
{
|
{
|
||||||
switch (Judgement.Result)
|
switch (Result.Type)
|
||||||
{
|
{
|
||||||
case HitResult.Good:
|
case HitResult.Good:
|
||||||
Colour = colours.GreenLight;
|
Colour = colours.GreenLight;
|
||||||
@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
if (Judgement.IsHit)
|
if (Result.IsHit)
|
||||||
this.MoveToY(-100, 500);
|
this.MoveToY(-100, 500);
|
||||||
|
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
@ -209,7 +209,7 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
|
|
||||||
public override void Add(DrawableHitObject h)
|
public override void Add(DrawableHitObject h)
|
||||||
{
|
{
|
||||||
h.OnJudgement += OnJudgement;
|
h.OnNewResult += OnNewResult;
|
||||||
|
|
||||||
base.Add(h);
|
base.Add(h);
|
||||||
|
|
||||||
@ -224,35 +224,40 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
|
internal void OnNewResult(DrawableHitObject judgedObject, JudgementResult result)
|
||||||
{
|
{
|
||||||
if (!DisplayJudgements)
|
if (!DisplayJudgements)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (judgedObject.DisplayJudgement && judgementContainer.FirstOrDefault(j => j.JudgedObject == judgedObject) == null)
|
if (!judgedObject.DisplayResult)
|
||||||
{
|
|
||||||
judgementContainer.Add(new DrawableTaikoJudgement(judgement, judgedObject)
|
|
||||||
{
|
|
||||||
Anchor = judgement.IsHit ? Anchor.TopLeft : Anchor.CentreLeft,
|
|
||||||
Origin = judgement.IsHit ? Anchor.BottomCentre : Anchor.Centre,
|
|
||||||
RelativePositionAxes = Axes.X,
|
|
||||||
X = judgement.IsHit ? judgedObject.Position.X : 0,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!judgement.IsHit)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bool isRim = judgedObject.HitObject is RimHit;
|
switch (result.Judgement)
|
||||||
|
|
||||||
if (judgement is TaikoStrongHitJudgement)
|
|
||||||
hitExplosionContainer.Children.FirstOrDefault(e => e.JudgedObject == judgedObject)?.VisualiseSecondHit();
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
hitExplosionContainer.Add(new HitExplosion(judgedObject, isRim));
|
case TaikoStrongJudgement _:
|
||||||
|
if (result.IsHit)
|
||||||
|
hitExplosionContainer.Children.FirstOrDefault(e => e.JudgedObject == ((DrawableStrongNestedHit)judgedObject).MainObject)?.VisualiseSecondHit();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
judgementContainer.Add(new DrawableTaikoJudgement(result, judgedObject)
|
||||||
|
{
|
||||||
|
Anchor = result.IsHit ? Anchor.TopLeft : Anchor.CentreLeft,
|
||||||
|
Origin = result.IsHit ? Anchor.BottomCentre : Anchor.Centre,
|
||||||
|
RelativePositionAxes = Axes.X,
|
||||||
|
X = result.IsHit ? judgedObject.Position.X : 0,
|
||||||
|
});
|
||||||
|
|
||||||
if (judgedObject.HitObject.Kiai)
|
if (!result.IsHit)
|
||||||
kiaiExplosionContainer.Add(new KiaiHitExplosion(judgedObject, isRim));
|
break;
|
||||||
|
|
||||||
|
bool isRim = judgedObject.HitObject is RimHit;
|
||||||
|
|
||||||
|
hitExplosionContainer.Add(new HitExplosion(judgedObject, isRim));
|
||||||
|
|
||||||
|
if (judgedObject.HitObject.Kiai)
|
||||||
|
kiaiExplosionContainer.Add(new KiaiHitExplosion(judgedObject, isRim));
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,12 +100,8 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
{
|
{
|
||||||
switch (h)
|
switch (h)
|
||||||
{
|
{
|
||||||
case CentreHit centreHit when h.IsStrong:
|
|
||||||
return new DrawableCentreHitStrong(centreHit);
|
|
||||||
case CentreHit centreHit:
|
case CentreHit centreHit:
|
||||||
return new DrawableCentreHit(centreHit);
|
return new DrawableCentreHit(centreHit);
|
||||||
case RimHit rimHit when h.IsStrong:
|
|
||||||
return new DrawableRimHitStrong(rimHit);
|
|
||||||
case RimHit rimHit:
|
case RimHit rimHit:
|
||||||
return new DrawableRimHit(rimHit);
|
return new DrawableRimHit(rimHit);
|
||||||
case DrumRoll drumRoll:
|
case DrumRoll drumRoll:
|
||||||
|
@ -354,6 +354,11 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
|
|
||||||
private void handleTimingControlPoint(TimingControlPoint newPoint)
|
private void handleTimingControlPoint(TimingControlPoint newPoint)
|
||||||
{
|
{
|
||||||
|
var existing = beatmap.ControlPointInfo.TimingPointAt(newPoint.Time);
|
||||||
|
|
||||||
|
if (existing.Time == newPoint.Time)
|
||||||
|
beatmap.ControlPointInfo.TimingPoints.Remove(existing);
|
||||||
|
|
||||||
beatmap.ControlPointInfo.TimingPoints.Add(newPoint);
|
beatmap.ControlPointInfo.TimingPoints.Add(newPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -364,7 +369,9 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
if (newPoint.EquivalentTo(existing))
|
if (newPoint.EquivalentTo(existing))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
beatmap.ControlPointInfo.DifficultyPoints.RemoveAll(x => x.Time == newPoint.Time);
|
if (existing.Time == newPoint.Time)
|
||||||
|
beatmap.ControlPointInfo.DifficultyPoints.Remove(existing);
|
||||||
|
|
||||||
beatmap.ControlPointInfo.DifficultyPoints.Add(newPoint);
|
beatmap.ControlPointInfo.DifficultyPoints.Add(newPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -375,6 +382,9 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
if (newPoint.EquivalentTo(existing))
|
if (newPoint.EquivalentTo(existing))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (existing.Time == newPoint.Time)
|
||||||
|
beatmap.ControlPointInfo.EffectPoints.Remove(existing);
|
||||||
|
|
||||||
beatmap.ControlPointInfo.EffectPoints.Add(newPoint);
|
beatmap.ControlPointInfo.EffectPoints.Add(newPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -385,6 +395,9 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
if (newPoint.EquivalentTo(existing))
|
if (newPoint.EquivalentTo(existing))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (existing.Time == newPoint.Time)
|
||||||
|
beatmap.ControlPointInfo.SamplePoints.Remove(existing);
|
||||||
|
|
||||||
beatmap.ControlPointInfo.SamplePoints.Add(newPoint);
|
beatmap.ControlPointInfo.SamplePoints.Add(newPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Judgements
|
|||||||
|
|
||||||
private OsuColour colours;
|
private OsuColour colours;
|
||||||
|
|
||||||
protected readonly Judgement Judgement;
|
protected readonly JudgementResult Result;
|
||||||
|
|
||||||
public readonly DrawableHitObject JudgedObject;
|
public readonly DrawableHitObject JudgedObject;
|
||||||
|
|
||||||
@ -34,11 +34,11 @@ namespace osu.Game.Rulesets.Judgements
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a drawable which visualises a <see cref="Judgements.Judgement"/>.
|
/// Creates a drawable which visualises a <see cref="Judgements.Judgement"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="judgement">The judgement to visualise.</param>
|
/// <param name="result">The judgement to visualise.</param>
|
||||||
/// <param name="judgedObject">The object which was judged.</param>
|
/// <param name="judgedObject">The object which was judged.</param>
|
||||||
public DrawableJudgement(Judgement judgement, DrawableHitObject judgedObject)
|
public DrawableJudgement(JudgementResult result, DrawableHitObject judgedObject)
|
||||||
{
|
{
|
||||||
Judgement = judgement;
|
Result = result;
|
||||||
JudgedObject = judgedObject;
|
JudgedObject = judgedObject;
|
||||||
|
|
||||||
Size = new Vector2(judgement_size);
|
Size = new Vector2(judgement_size);
|
||||||
@ -49,11 +49,11 @@ namespace osu.Game.Rulesets.Judgements
|
|||||||
{
|
{
|
||||||
this.colours = colours;
|
this.colours = colours;
|
||||||
|
|
||||||
Child = new SkinnableDrawable($"Play/{Judgement.Result}", _ => JudgementText = new OsuSpriteText
|
Child = new SkinnableDrawable($"Play/{Result.Type}", _ => JudgementText = new OsuSpriteText
|
||||||
{
|
{
|
||||||
Text = Judgement.Result.GetDescription().ToUpperInvariant(),
|
Text = Result.Type.GetDescription().ToUpperInvariant(),
|
||||||
Font = @"Venera",
|
Font = @"Venera",
|
||||||
Colour = judgementColour(Judgement.Result),
|
Colour = judgementColour(Result.Type),
|
||||||
Scale = new Vector2(0.85f, 1),
|
Scale = new Vector2(0.85f, 1),
|
||||||
TextSize = 12
|
TextSize = 12
|
||||||
}, restrictSize: false);
|
}, restrictSize: false);
|
||||||
@ -65,7 +65,7 @@ namespace osu.Game.Rulesets.Judgements
|
|||||||
|
|
||||||
this.FadeInFromZero(100, Easing.OutQuint);
|
this.FadeInFromZero(100, Easing.OutQuint);
|
||||||
|
|
||||||
switch (Judgement.Result)
|
switch (Result.Type)
|
||||||
{
|
{
|
||||||
case HitResult.None:
|
case HitResult.None:
|
||||||
break;
|
break;
|
||||||
|
@ -1,74 +1,48 @@
|
|||||||
// 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.Objects.Drawables;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Judgements
|
namespace osu.Game.Rulesets.Judgements
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The scoring information provided by a <see cref="HitObject"/>.
|
||||||
|
/// </summary>
|
||||||
public class Judgement
|
public class Judgement
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Whether this judgement is the result of a hit or a miss.
|
|
||||||
/// </summary>
|
|
||||||
public HitResult Result;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The maximum <see cref="HitResult"/> that can be achieved.
|
/// The maximum <see cref="HitResult"/> that can be achieved.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual HitResult MaxResult => HitResult.Perfect;
|
public virtual HitResult MaxResult => HitResult.Perfect;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The combo prior to this judgement occurring.
|
/// Whether this <see cref="Judgement"/> should affect the current combo.
|
||||||
/// </summary>
|
|
||||||
public int ComboAtJudgement;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The highest combo achieved prior to this judgement occurring.
|
|
||||||
/// </summary>
|
|
||||||
public int HighestComboAtJudgement;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether a successful hit occurred.
|
|
||||||
/// </summary>
|
|
||||||
public bool IsHit => Result > HitResult.Miss;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether this judgement is the final judgement for the hit object.
|
|
||||||
/// </summary>
|
|
||||||
public bool Final = true;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The offset from a perfect hit at which this judgement occurred.
|
|
||||||
/// Populated when added via <see cref="DrawableHitObject{TObject}.AddJudgement"/>.
|
|
||||||
/// </summary>
|
|
||||||
public double TimeOffset { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether the <see cref="Result"/> should affect the current combo.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual bool AffectsCombo => true;
|
public virtual bool AffectsCombo => true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether the <see cref="Result"/> should be counted as base (combo) or bonus score.
|
/// Whether this <see cref="Judgement"/> should be counted as base (combo) or bonus score.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual bool IsBonus => !AffectsCombo;
|
public virtual bool IsBonus => !AffectsCombo;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The numeric representation for the result achieved.
|
/// The numeric score representation for the maximum achievable result.
|
||||||
/// </summary>
|
|
||||||
public int NumericResult => NumericResultFor(Result);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The numeric representation for the maximum achievable result.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int MaxNumericResult => NumericResultFor(MaxResult);
|
public int MaxNumericResult => NumericResultFor(MaxResult);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Convert a <see cref="HitResult"/> to a numeric score representation.
|
/// Retrieves the numeric score representation of a <see cref="HitResult"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="result">The value to convert.</param>
|
/// <param name="result">The <see cref="HitResult"/> to find the numeric score representation for.</param>
|
||||||
/// <returns>The number.</returns>
|
/// <returns>The numeric score representation of <paramref name="result"/>.</returns>
|
||||||
protected virtual int NumericResultFor(HitResult result) => result > HitResult.Miss ? 1 : 0;
|
protected virtual int NumericResultFor(HitResult result) => result > HitResult.Miss ? 1 : 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the numeric score representation of a <see cref="JudgementResult"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <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>
|
||||||
|
public int NumericResultFor(JudgementResult result) => NumericResultFor(result.Type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
59
osu.Game/Rulesets/Judgements/JudgementResult.cs
Normal file
59
osu.Game/Rulesets/Judgements/JudgementResult.cs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
// 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.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Judgements
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The scoring result of a <see cref="DrawableHitObject"/>.
|
||||||
|
/// </summary>
|
||||||
|
public class JudgementResult
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Whether this <see cref="JudgementResult"/> is the result of a hit or a miss.
|
||||||
|
/// </summary>
|
||||||
|
public HitResult Type;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="Judgement"/> which this <see cref="JudgementResult"/> applies for.
|
||||||
|
/// </summary>
|
||||||
|
public readonly Judgement Judgement;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The offset from a perfect hit at which this <see cref="JudgementResult"/> occurred.
|
||||||
|
/// Populated when this <see cref="JudgementResult"/> is applied via <see cref="DrawableHitObject.ApplyResult"/>.
|
||||||
|
/// </summary>
|
||||||
|
public double TimeOffset { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The combo prior to this <see cref="JudgementResult"/> occurring.
|
||||||
|
/// </summary>
|
||||||
|
public int ComboAtJudgement { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The highest combo achieved prior to this <see cref="JudgementResult"/> occurring.
|
||||||
|
/// </summary>
|
||||||
|
public int HighestComboAtJudgement { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether a miss or hit occurred.
|
||||||
|
/// </summary>
|
||||||
|
public bool HasResult => Type > HitResult.None;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether a successful hit occurred.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsHit => Type > HitResult.Miss;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new <see cref="JudgementResult"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="judgement">The <see cref="Judgement"/> to refer to for scoring information.</param>
|
||||||
|
public JudgementResult(Judgement judgement)
|
||||||
|
{
|
||||||
|
Judgement = judgement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -6,6 +6,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
|
using osu.Framework.Extensions.TypeExtensions;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
@ -35,34 +36,44 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
private readonly Lazy<List<DrawableHitObject>> nestedHitObjects = new Lazy<List<DrawableHitObject>>();
|
private readonly Lazy<List<DrawableHitObject>> nestedHitObjects = new Lazy<List<DrawableHitObject>>();
|
||||||
public IEnumerable<DrawableHitObject> NestedHitObjects => nestedHitObjects.IsValueCreated ? nestedHitObjects.Value : Enumerable.Empty<DrawableHitObject>();
|
public IEnumerable<DrawableHitObject> NestedHitObjects => nestedHitObjects.IsValueCreated ? nestedHitObjects.Value : Enumerable.Empty<DrawableHitObject>();
|
||||||
|
|
||||||
public event Action<DrawableHitObject, Judgement> OnJudgement;
|
/// <summary>
|
||||||
public event Action<DrawableHitObject, Judgement> OnJudgementRemoved;
|
/// Invoked when a <see cref="JudgementResult"/> has been applied by this <see cref="DrawableHitObject"/> or a nested <see cref="DrawableHitObject"/>.
|
||||||
|
/// </summary>
|
||||||
public IReadOnlyList<Judgement> Judgements => judgements;
|
public event Action<DrawableHitObject, JudgementResult> OnNewResult;
|
||||||
private readonly List<Judgement> judgements = new List<Judgement>();
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether a visible judgement should be displayed when this representation is hit.
|
/// Invoked when a <see cref="JudgementResult"/> is being reverted by this <see cref="DrawableHitObject"/> or a nested <see cref="DrawableHitObject"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual bool DisplayJudgement => true;
|
public event Action<DrawableHitObject, JudgementResult> OnRevertResult;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether this <see cref="DrawableHitObject"/> and all of its nested <see cref="DrawableHitObject"/>s have been hit.
|
/// Whether a visual indicator should be displayed when a scoring result occurs.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsHit => Judgements.Any(j => j.Final && j.IsHit) && NestedHitObjects.All(n => n.IsHit);
|
public virtual bool DisplayResult => true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether this <see cref="DrawableHitObject"/> and all of its nested <see cref="DrawableHitObject"/>s have been judged.
|
/// Whether this <see cref="DrawableHitObject"/> and all of its nested <see cref="DrawableHitObject"/>s have been judged.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool AllJudged => (!ProvidesJudgement || judgementFinalized) && NestedHitObjects.All(h => h.AllJudged);
|
public bool AllJudged => Judged && NestedHitObjects.All(h => h.AllJudged);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether this <see cref="DrawableHitObject"/> can be judged.
|
/// Whether this <see cref="DrawableHitObject"/> has been hit. This occurs if <see cref="Result.IsHit"/> is <see cref="true"/>.
|
||||||
|
/// Note: This does NOT include nested hitobjects.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual bool ProvidesJudgement => true;
|
public bool IsHit => Result?.IsHit ?? false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether this <see cref="DrawableHitObject"/> has been judged.
|
||||||
|
/// Note: This does NOT include nested hitobjects.
|
||||||
|
/// </summary>
|
||||||
|
public bool Judged => Result?.HasResult ?? true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The scoring result of this <see cref="DrawableHitObject"/>.
|
||||||
|
/// </summary>
|
||||||
|
public JudgementResult Result { get; private set; }
|
||||||
|
|
||||||
private bool judgementOccurred;
|
private bool judgementOccurred;
|
||||||
private bool judgementFinalized => judgements.LastOrDefault()?.Final == true;
|
|
||||||
|
|
||||||
public bool Interactive = true;
|
public bool Interactive = true;
|
||||||
public override bool HandleKeyboardInput => Interactive;
|
public override bool HandleKeyboardInput => Interactive;
|
||||||
@ -82,6 +93,14 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
|
var judgement = HitObject.CreateJudgement();
|
||||||
|
if (judgement != null)
|
||||||
|
{
|
||||||
|
Result = CreateResult(judgement);
|
||||||
|
if (Result == null)
|
||||||
|
throw new InvalidOperationException($"{GetType().ReadableName()} must provide a {nameof(JudgementResult)} through {nameof(CreateResult)}.");
|
||||||
|
}
|
||||||
|
|
||||||
var samples = GetSamples().ToArray();
|
var samples = GetSamples().ToArray();
|
||||||
|
|
||||||
if (samples.Any())
|
if (samples.Any())
|
||||||
@ -128,56 +147,63 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void PlaySamples() => Samples?.Play();
|
public void PlaySamples() => Samples?.Play();
|
||||||
|
|
||||||
|
private double lastUpdateTime;
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
var endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime;
|
if (Result != null && lastUpdateTime > Time.Current)
|
||||||
|
|
||||||
while (judgements.Count > 0)
|
|
||||||
{
|
{
|
||||||
var lastJudgement = judgements[judgements.Count - 1];
|
var endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime;
|
||||||
if (lastJudgement.TimeOffset + endTime <= Time.Current)
|
|
||||||
break;
|
|
||||||
|
|
||||||
judgements.RemoveAt(judgements.Count - 1);
|
if (Result.TimeOffset + endTime < Time.Current)
|
||||||
State.Value = ArmedState.Idle;
|
{
|
||||||
|
OnRevertResult?.Invoke(this, Result);
|
||||||
|
|
||||||
OnJudgementRemoved?.Invoke(this, lastJudgement);
|
Result.Type = HitResult.None;
|
||||||
|
State.Value = ArmedState.Idle;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lastUpdateTime = Time.Current;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdateAfterChildren()
|
protected override void UpdateAfterChildren()
|
||||||
{
|
{
|
||||||
base.UpdateAfterChildren();
|
base.UpdateAfterChildren();
|
||||||
|
|
||||||
UpdateJudgement(false);
|
UpdateResult(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void AddNested(DrawableHitObject h)
|
protected virtual void AddNested(DrawableHitObject h)
|
||||||
{
|
{
|
||||||
h.OnJudgement += (d, j) => OnJudgement?.Invoke(d, j);
|
h.OnNewResult += (d, r) => OnNewResult?.Invoke(d, r);
|
||||||
h.OnJudgementRemoved += (d, j) => OnJudgementRemoved?.Invoke(d, j);
|
h.OnRevertResult += (d, r) => OnRevertResult?.Invoke(d, r);
|
||||||
h.ApplyCustomUpdateState += (d, j) => ApplyCustomUpdateState?.Invoke(d, j);
|
h.ApplyCustomUpdateState += (d, j) => ApplyCustomUpdateState?.Invoke(d, j);
|
||||||
|
|
||||||
nestedHitObjects.Value.Add(h);
|
nestedHitObjects.Value.Add(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Notifies that a new judgement has occurred for this <see cref="DrawableHitObject"/>.
|
/// Applies the <see cref="Result"/> of this <see cref="DrawableHitObject"/>, notifying responders such as
|
||||||
|
/// the <see cref="ScoreProcessor"/> of the <see cref="JudgementResult"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="judgement">The <see cref="Judgement"/>.</param>
|
/// <param name="application">The callback that applies changes to the <see cref="JudgementResult"/>.</param>
|
||||||
protected void AddJudgement(Judgement judgement)
|
protected void ApplyResult(Action<JudgementResult> application)
|
||||||
{
|
{
|
||||||
|
application?.Invoke(Result);
|
||||||
|
|
||||||
|
if (!Result.HasResult)
|
||||||
|
throw new InvalidOperationException($"{GetType().ReadableName()} applied a {nameof(JudgementResult)} but did not update {nameof(JudgementResult.Type)}.");
|
||||||
|
|
||||||
judgementOccurred = true;
|
judgementOccurred = true;
|
||||||
|
|
||||||
// Ensure that the judgement is given a valid time offset, because this may not get set by the caller
|
// Ensure that the judgement is given a valid time offset, because this may not get set by the caller
|
||||||
var endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime;
|
var endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime;
|
||||||
judgement.TimeOffset = Time.Current - endTime;
|
Result.TimeOffset = Time.Current - endTime;
|
||||||
|
|
||||||
judgements.Add(judgement);
|
switch (Result.Type)
|
||||||
|
|
||||||
switch (judgement.Result)
|
|
||||||
{
|
{
|
||||||
case HitResult.None:
|
case HitResult.None:
|
||||||
break;
|
break;
|
||||||
@ -189,15 +215,15 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
OnJudgement?.Invoke(this, judgement);
|
OnNewResult?.Invoke(this, Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Processes this <see cref="DrawableHitObject"/>, checking if any judgements have occurred.
|
/// Processes this <see cref="DrawableHitObject"/>, checking if a scoring result has occurred.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="userTriggered">Whether the user triggered this process.</param>
|
/// <param name="userTriggered">Whether the user triggered this process.</param>
|
||||||
/// <returns>Whether a judgement has occurred from this <see cref="DrawableHitObject"/> or any nested <see cref="DrawableHitObject"/>s.</returns>
|
/// <returns>Whether a scoring result has occurred from this <see cref="DrawableHitObject"/> or any nested <see cref="DrawableHitObject"/>.</returns>
|
||||||
protected bool UpdateJudgement(bool userTriggered)
|
protected bool UpdateResult(bool userTriggered)
|
||||||
{
|
{
|
||||||
judgementOccurred = false;
|
judgementOccurred = false;
|
||||||
|
|
||||||
@ -205,27 +231,35 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
foreach (var d in NestedHitObjects)
|
foreach (var d in NestedHitObjects)
|
||||||
judgementOccurred |= d.UpdateJudgement(userTriggered);
|
judgementOccurred |= d.UpdateResult(userTriggered);
|
||||||
|
|
||||||
if (!ProvidesJudgement || judgementFinalized || judgementOccurred)
|
if (judgementOccurred || Judged)
|
||||||
return judgementOccurred;
|
return judgementOccurred;
|
||||||
|
|
||||||
var endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime;
|
var endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime;
|
||||||
CheckForJudgements(userTriggered, Time.Current - endTime);
|
CheckForResult(userTriggered, Time.Current - endTime);
|
||||||
|
|
||||||
return judgementOccurred;
|
return judgementOccurred;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if any judgements have occurred for this <see cref="DrawableHitObject"/>. This method must construct
|
/// Checks if a scoring result has occurred for this <see cref="DrawableHitObject"/>.
|
||||||
/// all <see cref="Judgement"/>s and notify of them through <see cref="AddJudgement"/>.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// If a scoring result has occurred, this method must invoke <see cref="ApplyResult"/> to update the result and notify responders.
|
||||||
|
/// </remarks>
|
||||||
/// <param name="userTriggered">Whether the user triggered this check.</param>
|
/// <param name="userTriggered">Whether the user triggered this check.</param>
|
||||||
/// <param name="timeOffset">The offset from the <see cref="HitObject"/> end time at which this check occurred. A <paramref name="timeOffset"/> > 0
|
/// <param name="timeOffset">The offset from the end time of the <see cref="HitObject"/> at which this check occurred.
|
||||||
/// implies that this check occurred after the end time of <see cref="HitObject"/>. </param>
|
/// A <paramref name="timeOffset"/> > 0 implies that this check occurred after the end time of the <see cref="HitObject"/>. </param>
|
||||||
protected virtual void CheckForJudgements(bool userTriggered, double timeOffset)
|
protected virtual void CheckForResult(bool userTriggered, double timeOffset)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates the <see cref="JudgementResult"/> that represents the scoring result for this <see cref="DrawableHitObject"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="judgement">The <see cref="Judgement"/> that provides the scoring information.</param>
|
||||||
|
protected virtual JudgementResult CreateResult(Judgement judgement) => new JudgementResult(judgement);
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class DrawableHitObject<TObject> : DrawableHitObject
|
public abstract class DrawableHitObject<TObject> : DrawableHitObject
|
||||||
|
@ -9,6 +9,7 @@ using osu.Framework.Lists;
|
|||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
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.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Objects
|
namespace osu.Game.Rulesets.Objects
|
||||||
@ -105,6 +106,12 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
|
|
||||||
protected void AddNested(HitObject hitObject) => nestedHitObjects.Value.Add(hitObject);
|
protected void AddNested(HitObject hitObject) => nestedHitObjects.Value.Add(hitObject);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates the <see cref="Judgement"/> that represents the scoring information for this <see cref="HitObject"/>.
|
||||||
|
/// May be null.
|
||||||
|
/// </summary>
|
||||||
|
public virtual Judgement CreateJudgement() => null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates the <see cref="HitWindows"/> for this <see cref="HitObject"/>.
|
/// Creates the <see cref="HitWindows"/> for this <see cref="HitObject"/>.
|
||||||
/// This can be null to indicate that the <see cref="HitObject"/> has no <see cref="HitWindows"/>.
|
/// This can be null to indicate that the <see cref="HitObject"/> has no <see cref="HitWindows"/>.
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
|
using osu.Framework.Extensions.TypeExtensions;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
@ -28,7 +29,7 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invoked when a new judgement has occurred. This occurs after the judgement has been processed by the <see cref="ScoreProcessor"/>.
|
/// Invoked when a new judgement has occurred. This occurs after the judgement has been processed by the <see cref="ScoreProcessor"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event Action<Judgement> NewJudgement;
|
public event Action<JudgementResult> NewJudgement;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Additional conditions on top of <see cref="DefaultFailCondition"/> that cause a failing state.
|
/// Additional conditions on top of <see cref="DefaultFailCondition"/> that cause a failing state.
|
||||||
@ -144,9 +145,10 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
/// Notifies subscribers of <see cref="NewJudgement"/> that a new judgement has occurred.
|
/// Notifies subscribers of <see cref="NewJudgement"/> that a new judgement has occurred.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="judgement">The judgement to notify subscribers of.</param>
|
/// <param name="judgement">The judgement to notify subscribers of.</param>
|
||||||
protected void NotifyNewJudgement(Judgement judgement)
|
/// <param name="result">The judgement scoring result to notify subscribers of.</param>
|
||||||
|
protected void NotifyNewJudgement(JudgementResult result)
|
||||||
{
|
{
|
||||||
NewJudgement?.Invoke(judgement);
|
NewJudgement?.Invoke(result);
|
||||||
|
|
||||||
if (HasCompleted)
|
if (HasCompleted)
|
||||||
AllJudged?.Invoke();
|
AllJudged?.Invoke();
|
||||||
@ -194,9 +196,10 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
{
|
{
|
||||||
Debug.Assert(base_portion + combo_portion == 1.0);
|
Debug.Assert(base_portion + combo_portion == 1.0);
|
||||||
|
|
||||||
rulesetContainer.OnJudgement += AddJudgement;
|
rulesetContainer.OnNewResult += applyResult;
|
||||||
rulesetContainer.OnJudgementRemoved += RemoveJudgement;
|
rulesetContainer.OnRevertResult += revertResult;
|
||||||
|
|
||||||
|
ApplyBeatmap(rulesetContainer.Beatmap);
|
||||||
SimulateAutoplay(rulesetContainer.Beatmap);
|
SimulateAutoplay(rulesetContainer.Beatmap);
|
||||||
Reset(true);
|
Reset(true);
|
||||||
|
|
||||||
@ -210,46 +213,80 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Simulates an autoplay of <see cref="HitObject"/>s that will be judged by this <see cref="ScoreProcessor{TObject}"/>
|
/// Applies any properties of the <see cref="Beatmap{TObject}"/> which affect scoring to this <see cref="ScoreProcessor{TObject}"/>.
|
||||||
/// by adding <see cref="Judgement"/>s for each <see cref="HitObject"/> in the <see cref="Beatmap{TObject}"/>.
|
|
||||||
/// <para>
|
|
||||||
/// This is required for <see cref="ScoringMode.Standardised"/> to work, otherwise <see cref="ScoringMode.Classic"/> will be used.
|
|
||||||
/// </para>
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="beatmap">The <see cref="Beatmap{TObject}"/> containing the <see cref="HitObject"/>s that will be judged by this <see cref="ScoreProcessor{TObject}"/>.</param>
|
/// <param name="beatmap">The <see cref="Beatmap{TObject}"/> to read properties from.</param>
|
||||||
protected virtual void SimulateAutoplay(Beatmap<TObject> beatmap) { }
|
protected virtual void ApplyBeatmap(Beatmap<TObject> beatmap)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds a judgement to this ScoreProcessor.
|
/// Simulates an autoplay of the <see cref="Beatmap{TObject}"/> to determine scoring values.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="judgement">The judgement to add.</param>
|
/// <remarks>This provided temporarily. DO NOT USE.</remarks>
|
||||||
protected void AddJudgement(Judgement judgement)
|
/// <param name="beatmap">The <see cref="Beatmap{TObject}"/> to simulate.</param>
|
||||||
|
protected virtual void SimulateAutoplay(Beatmap<TObject> beatmap)
|
||||||
{
|
{
|
||||||
OnNewJudgement(judgement);
|
foreach (var obj in beatmap.HitObjects)
|
||||||
|
simulate(obj);
|
||||||
|
|
||||||
|
void simulate(HitObject obj)
|
||||||
|
{
|
||||||
|
foreach (var nested in obj.NestedHitObjects)
|
||||||
|
simulate(nested);
|
||||||
|
|
||||||
|
var judgement = obj.CreateJudgement();
|
||||||
|
if (judgement == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var result = CreateResult(judgement);
|
||||||
|
if (result == null)
|
||||||
|
throw new InvalidOperationException($"{GetType().ReadableName()} must provide a {nameof(JudgementResult)} through {nameof(CreateResult)}.");
|
||||||
|
|
||||||
|
result.Type = judgement.MaxResult;
|
||||||
|
|
||||||
|
applyResult(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Applies the score change of a <see cref="JudgementResult"/> to this <see cref="ScoreProcessor"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="result">The <see cref="JudgementResult"/> to apply.</param>
|
||||||
|
private void applyResult(JudgementResult result)
|
||||||
|
{
|
||||||
|
ApplyResult(result);
|
||||||
updateScore();
|
updateScore();
|
||||||
|
|
||||||
UpdateFailed();
|
UpdateFailed();
|
||||||
NotifyNewJudgement(judgement);
|
NotifyNewJudgement(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void RemoveJudgement(Judgement judgement)
|
/// <summary>
|
||||||
|
/// Reverts the score change of a <see cref="JudgementResult"/> that was applied to this <see cref="ScoreProcessor"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="judgement">The judgement to remove.</param>
|
||||||
|
/// <param name="result">The judgement scoring result.</param>
|
||||||
|
private void revertResult(JudgementResult result)
|
||||||
{
|
{
|
||||||
OnJudgementRemoved(judgement);
|
RevertResult(result);
|
||||||
updateScore();
|
updateScore();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Applies a judgement.
|
/// Applies the score change of a <see cref="JudgementResult"/> to this <see cref="ScoreProcessor"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="judgement">The judgement to apply/</param>
|
/// <param name="result">The <see cref="JudgementResult"/> to apply.</param>
|
||||||
protected virtual void OnNewJudgement(Judgement judgement)
|
protected virtual void ApplyResult(JudgementResult result)
|
||||||
{
|
{
|
||||||
judgement.ComboAtJudgement = Combo;
|
result.ComboAtJudgement = Combo;
|
||||||
judgement.HighestComboAtJudgement = HighestCombo;
|
result.HighestComboAtJudgement = HighestCombo;
|
||||||
|
|
||||||
if (judgement.AffectsCombo)
|
JudgedHits++;
|
||||||
|
|
||||||
|
if (result.Judgement.AffectsCombo)
|
||||||
{
|
{
|
||||||
switch (judgement.Result)
|
switch (result.Type)
|
||||||
{
|
{
|
||||||
case HitResult.None:
|
case HitResult.None:
|
||||||
break;
|
break;
|
||||||
@ -260,43 +297,41 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
Combo.Value++;
|
Combo.Value++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
JudgedHits++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (judgement.IsBonus)
|
if (result.Judgement.IsBonus)
|
||||||
{
|
{
|
||||||
if (judgement.IsHit)
|
if (result.IsHit)
|
||||||
bonusScore += judgement.NumericResult;
|
bonusScore += result.Judgement.NumericResultFor(result);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
baseScore += judgement.NumericResult;
|
baseScore += result.Judgement.NumericResultFor(result);
|
||||||
rollingMaxBaseScore += judgement.MaxNumericResult;
|
rollingMaxBaseScore += result.Judgement.MaxNumericResult;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Removes a judgement. This should reverse everything in <see cref="OnNewJudgement(Judgement)"/>.
|
/// Reverts the score change of a <see cref="JudgementResult"/> that was applied to this <see cref="ScoreProcessor"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="judgement">The judgement to remove.</param>
|
/// <param name="judgement">The judgement to remove.</param>
|
||||||
protected virtual void OnJudgementRemoved(Judgement judgement)
|
/// <param name="result">The judgement scoring result.</param>
|
||||||
|
protected virtual void RevertResult(JudgementResult result)
|
||||||
{
|
{
|
||||||
Combo.Value = judgement.ComboAtJudgement;
|
Combo.Value = result.ComboAtJudgement;
|
||||||
HighestCombo.Value = judgement.HighestComboAtJudgement;
|
HighestCombo.Value = result.HighestComboAtJudgement;
|
||||||
|
|
||||||
if (judgement.AffectsCombo)
|
JudgedHits--;
|
||||||
JudgedHits--;
|
|
||||||
|
|
||||||
if (judgement.IsBonus)
|
if (result.Judgement.IsBonus)
|
||||||
{
|
{
|
||||||
if (judgement.IsHit)
|
if (result.IsHit)
|
||||||
bonusScore -= judgement.NumericResult;
|
bonusScore -= result.Judgement.NumericResultFor(result);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
baseScore -= judgement.NumericResult;
|
baseScore -= result.Judgement.NumericResultFor(result);
|
||||||
rollingMaxBaseScore -= judgement.MaxNumericResult;
|
rollingMaxBaseScore -= result.Judgement.MaxNumericResult;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -333,6 +368,12 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
rollingMaxBaseScore = 0;
|
rollingMaxBaseScore = 0;
|
||||||
bonusScore = 0;
|
bonusScore = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates the <see cref="JudgementResult"/> that represents the scoring result for a <see cref="HitObject"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="judgement">The <see cref="Judgement"/> that provides the scoring information.</param>
|
||||||
|
protected virtual JudgementResult CreateResult(Judgement judgement) => new JudgementResult(judgement);
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ScoringMode
|
public enum ScoringMode
|
||||||
|
@ -182,8 +182,15 @@ namespace osu.Game.Rulesets.UI
|
|||||||
public abstract class RulesetContainer<TObject> : RulesetContainer
|
public abstract class RulesetContainer<TObject> : RulesetContainer
|
||||||
where TObject : HitObject
|
where TObject : HitObject
|
||||||
{
|
{
|
||||||
public event Action<Judgement> OnJudgement;
|
/// <summary>
|
||||||
public event Action<Judgement> OnJudgementRemoved;
|
/// Invoked when a <see cref="JudgementResult"/> has been applied by a <see cref="DrawableHitObject"/>.
|
||||||
|
/// </summary>
|
||||||
|
public event Action<JudgementResult> OnNewResult;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invoked when a <see cref="JudgementResult"/> is being reverted by a <see cref="DrawableHitObject"/>.
|
||||||
|
/// </summary>
|
||||||
|
public event Action<JudgementResult> OnRevertResult;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The Beatmap
|
/// The Beatmap
|
||||||
@ -290,8 +297,8 @@ namespace osu.Game.Rulesets.UI
|
|||||||
if (drawableObject == null)
|
if (drawableObject == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
drawableObject.OnJudgement += (d, j) => OnJudgement?.Invoke(j);
|
drawableObject.OnNewResult += (_, r) => OnNewResult?.Invoke(r);
|
||||||
drawableObject.OnJudgementRemoved += (d, j) => OnJudgementRemoved?.Invoke(j);
|
drawableObject.OnRevertResult += (_, r) => OnRevertResult?.Invoke(r);
|
||||||
|
|
||||||
Playfield.Add(drawableObject);
|
Playfield.Add(drawableObject);
|
||||||
}
|
}
|
||||||
|
@ -92,9 +92,9 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Flash(Judgement judgement)
|
public void Flash(JudgementResult result)
|
||||||
{
|
{
|
||||||
if (judgement.Result == HitResult.Miss)
|
if (result.Type == HitResult.Miss)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
fill.FadeEdgeEffectTo(Math.Min(1, fill.EdgeEffect.Colour.Linear.A + (1f - base_glow_opacity) / glow_max_hits), 50, Easing.OutQuint)
|
fill.FadeEdgeEffectTo(Math.Min(1, fill.EdgeEffect.Colour.Linear.A + (1f - base_glow_opacity) / glow_max_hits), 50, Easing.OutQuint)
|
||||||
|
Loading…
Reference in New Issue
Block a user