mirror of
https://github.com/ppy/osu.git
synced 2024-11-06 06:17:23 +08:00
Merge branch 'master' into sentry-logging
This commit is contained in:
commit
9fc0a75b71
@ -27,7 +27,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="System.IO.Packaging" Version="4.5.0" />
|
||||
<PackageReference Include="ppy.squirrel.windows" Version="1.8.0.3" />
|
||||
<PackageReference Include="ppy.squirrel.windows" Version="1.8.0.5" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.1.1" />
|
||||
</ItemGroup>
|
||||
|
@ -41,6 +41,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
|
||||
RepeatCount = curveData.RepeatCount,
|
||||
X = (positionData?.X ?? 0) / CatchPlayfield.BASE_WIDTH,
|
||||
NewCombo = comboData?.NewCombo ?? false,
|
||||
ComboOffset = comboData?.ComboOffset ?? 0,
|
||||
LegacyLastTickOffset = legacyOffset?.LegacyLastTickOffset ?? 0
|
||||
};
|
||||
}
|
||||
@ -51,7 +52,8 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
|
||||
StartTime = obj.StartTime,
|
||||
Samples = obj.Samples,
|
||||
Duration = endTime.Duration,
|
||||
NewCombo = comboData?.NewCombo ?? false
|
||||
NewCombo = comboData?.NewCombo ?? false,
|
||||
ComboOffset = comboData?.ComboOffset ?? 0,
|
||||
};
|
||||
}
|
||||
else
|
||||
@ -61,6 +63,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
|
||||
StartTime = obj.StartTime,
|
||||
Samples = obj.Samples,
|
||||
NewCombo = comboData?.NewCombo ?? false,
|
||||
ComboOffset = comboData?.ComboOffset ?? 0,
|
||||
X = (positionData?.X ?? 0) / CatchPlayfield.BASE_WIDTH
|
||||
};
|
||||
}
|
||||
|
@ -93,13 +93,11 @@ namespace osu.Game.Rulesets.Catch
|
||||
new CatchModHidden(),
|
||||
new CatchModFlashlight(),
|
||||
};
|
||||
case ModType.Special:
|
||||
case ModType.Automation:
|
||||
return new Mod[]
|
||||
{
|
||||
new CatchModRelax(),
|
||||
null,
|
||||
null,
|
||||
new MultiMod(new CatchModAutoplay(), new ModCinema()),
|
||||
new CatchModRelax(),
|
||||
};
|
||||
default:
|
||||
return new Mod[] { };
|
||||
|
@ -1,6 +1,7 @@
|
||||
// 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.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Judgements
|
||||
@ -9,8 +10,6 @@ namespace osu.Game.Rulesets.Catch.Judgements
|
||||
{
|
||||
public override bool AffectsCombo => false;
|
||||
|
||||
public override bool ShouldExplode => true;
|
||||
|
||||
protected override int NumericResultFor(HitResult result)
|
||||
{
|
||||
switch (result)
|
||||
@ -32,5 +31,7 @@ namespace osu.Game.Rulesets.Catch.Judgements
|
||||
return 8;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool ShouldExplodeFor(JudgementResult result) => true;
|
||||
}
|
||||
}
|
||||
|
@ -23,21 +23,10 @@ namespace osu.Game.Rulesets.Catch.Judgements
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The base health increase for the result achieved.
|
||||
/// Retrieves the numeric health increase of a <see cref="HitResult"/>.
|
||||
/// </summary>
|
||||
public float HealthIncrease => HealthIncreaseFor(Result);
|
||||
|
||||
/// <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>
|
||||
/// <param name="result">The <see cref="HitResult"/> to find the numeric health increase for.</param>
|
||||
/// <returns>The numeric health increase of <paramref name="result"/>.</returns>
|
||||
protected virtual float HealthIncreaseFor(HitResult result)
|
||||
{
|
||||
switch (result)
|
||||
@ -48,5 +37,18 @@ namespace osu.Game.Rulesets.Catch.Judgements
|
||||
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>.
|
||||
// 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
|
||||
{
|
||||
public class Banana : Fruit
|
||||
{
|
||||
public override FruitVisualRepresentation VisualRepresentation => FruitVisualRepresentation.Banana;
|
||||
|
||||
public override Judgement CreateJudgement() => new CatchBananaJudgement();
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,8 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
|
||||
public virtual bool NewCombo { get; set; }
|
||||
|
||||
public int ComboOffset { get; set; }
|
||||
|
||||
public int IndexInCurrentCombo { get; set; }
|
||||
|
||||
public int ComboIndex { get; set; }
|
||||
|
@ -1,8 +1,6 @@
|
||||
// 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.Catch.Judgements;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
{
|
||||
public class DrawableBanana : DrawableFruit
|
||||
@ -11,7 +9,5 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
: base(h)
|
||||
{
|
||||
}
|
||||
|
||||
protected override CatchJudgement CreateJudgement() => new CatchBananaJudgement();
|
||||
}
|
||||
}
|
||||
|
@ -26,8 +26,6 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
AddNested(getVisualRepresentation?.Invoke(b));
|
||||
}
|
||||
|
||||
protected override bool ProvidesJudgement => false;
|
||||
|
||||
protected override void AddNested(DrawableHitObject h)
|
||||
{
|
||||
((DrawableCatchHitObject)h).CheckPosition = o => CheckPosition?.Invoke(o) ?? false;
|
||||
|
@ -5,7 +5,6 @@ using System;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Catch.Judgements;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
@ -53,20 +52,14 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
|
||||
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 (timeOffset >= 0)
|
||||
{
|
||||
var judgement = CreateJudgement();
|
||||
judgement.Result = CheckPosition.Invoke(HitObject) ? HitResult.Perfect : HitResult.Miss;
|
||||
AddJudgement(judgement);
|
||||
}
|
||||
if (timeOffset >= 0 && Result != null)
|
||||
ApplyResult(r => r.Type = CheckPosition.Invoke(HitObject) ? HitResult.Perfect : HitResult.Miss);
|
||||
}
|
||||
|
||||
protected virtual CatchJudgement CreateJudgement() => new CatchJudgement();
|
||||
|
||||
protected override void SkinChanged(ISkinSource skin, bool allowFallback)
|
||||
{
|
||||
base.SkinChanged(skin, allowFallback);
|
||||
|
@ -6,7 +6,6 @@ using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Catch.Objects.Drawable.Pieces;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Game.Rulesets.Catch.Judgements;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
{
|
||||
@ -24,8 +23,6 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
Masking = false;
|
||||
}
|
||||
|
||||
protected override CatchJudgement CreateJudgement() => new CatchDropletJudgement();
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
|
@ -26,8 +26,6 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
AddNested(getVisualRepresentation?.Invoke(o));
|
||||
}
|
||||
|
||||
protected override bool ProvidesJudgement => false;
|
||||
|
||||
protected override void AddNested(DrawableHitObject h)
|
||||
{
|
||||
var catchObject = (DrawableCatchHitObject)h;
|
||||
|
@ -2,18 +2,15 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using OpenTK;
|
||||
using osu.Game.Rulesets.Catch.Judgements;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
{
|
||||
public class DrawableTinyDroplet : DrawableDroplet
|
||||
{
|
||||
public DrawableTinyDroplet(Droplet h)
|
||||
public DrawableTinyDroplet(TinyDroplet h)
|
||||
: base(h)
|
||||
{
|
||||
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>.
|
||||
// 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
|
||||
{
|
||||
public class Droplet : CatchHitObject
|
||||
{
|
||||
public override Judgement CreateJudgement() => new CatchDropletJudgement();
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +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.Catch.Judgements;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects
|
||||
{
|
||||
public class Fruit : CatchHitObject
|
||||
{
|
||||
public override Judgement CreateJudgement() => new CatchJudgement();
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +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.Catch.Judgements;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects
|
||||
{
|
||||
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
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Catch.Judgements;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
@ -21,55 +20,28 @@ namespace osu.Game.Rulesets.Catch.Scoring
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
hpDrainRate = beatmap.BeatmapInfo.BaseDifficulty.DrainRate;
|
||||
}
|
||||
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
if (judgement is CatchJudgement catchJudgement)
|
||||
Health.Value += Math.Max(catchJudgement.HealthIncrease - hpDrainRate, 0) * harshness;
|
||||
if (result.Judgement is CatchJudgement catchJudgement)
|
||||
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)
|
||||
{
|
||||
h.OnJudgement += onJudgement;
|
||||
h.OnNewResult += onNewResult;
|
||||
|
||||
base.Add(h);
|
||||
|
||||
@ -67,6 +67,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
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;
|
||||
|
||||
public void OnJudgement(DrawableCatchHitObject fruit, Judgement judgement)
|
||||
public void OnResult(DrawableCatchHitObject fruit, JudgementResult result)
|
||||
{
|
||||
void runAfterLoaded(Action action)
|
||||
{
|
||||
@ -63,7 +63,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
lastPlateableFruit.OnLoadComplete = _ => action();
|
||||
}
|
||||
|
||||
if (judgement.IsHit && fruit.CanBePlated)
|
||||
if (result.IsHit && fruit.CanBePlated)
|
||||
{
|
||||
var caughtFruit = (DrawableCatchHitObject)GetVisualRepresentation?.Invoke(fruit.HitObject);
|
||||
|
||||
@ -86,7 +86,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
|
||||
if (fruit.HitObject.LastInCombo)
|
||||
{
|
||||
if (((CatchJudgement)judgement).ShouldExplode)
|
||||
if (((CatchJudgement)result.Judgement).ShouldExplodeFor(result))
|
||||
runAfterLoaded(() => MovableCatcher.Explode());
|
||||
else
|
||||
MovableCatcher.Drop();
|
||||
|
@ -14,24 +14,20 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
/// </summary>
|
||||
public class ScrollingTestContainer : Container
|
||||
{
|
||||
private readonly ScrollingDirection direction;
|
||||
[Cached(Type = typeof(IScrollingInfo))]
|
||||
private readonly TestScrollingInfo scrollingInfo = new TestScrollingInfo();
|
||||
|
||||
public ScrollingTestContainer(ScrollingDirection direction)
|
||||
{
|
||||
this.direction = direction;
|
||||
scrollingInfo.Direction.Value = direction;
|
||||
}
|
||||
|
||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
||||
{
|
||||
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
||||
dependencies.CacheAs<IScrollingInfo>(new ScrollingInfo { Direction = { Value = direction }});
|
||||
return dependencies;
|
||||
}
|
||||
public void Flip() => scrollingInfo.Direction.Value = scrollingInfo.Direction.Value == ScrollingDirection.Up ? ScrollingDirection.Down : ScrollingDirection.Up;
|
||||
}
|
||||
|
||||
private class ScrollingInfo : IScrollingInfo
|
||||
{
|
||||
public readonly Bindable<ScrollingDirection> Direction = new Bindable<ScrollingDirection>();
|
||||
IBindable<ScrollingDirection> IScrollingInfo.Direction => Direction;
|
||||
}
|
||||
public class TestScrollingInfo : IScrollingInfo
|
||||
{
|
||||
public readonly Bindable<ScrollingDirection> Direction = new Bindable<ScrollingDirection>();
|
||||
IBindable<ScrollingDirection> IScrollingInfo.Direction => Direction;
|
||||
}
|
||||
}
|
||||
|
32
osu.Game.Rulesets.Mania.Tests/TestCaseEditor.cs
Normal file
32
osu.Game.Rulesets.Mania.Tests/TestCaseEditor.cs
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Game.Rulesets.Mania.Configuration;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
using osu.Game.Tests.Visual;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestCaseEditor : EditorTestCase
|
||||
{
|
||||
private readonly Bindable<ManiaScrollingDirection> direction = new Bindable<ManiaScrollingDirection>();
|
||||
|
||||
public TestCaseEditor()
|
||||
: base(new ManiaRuleset())
|
||||
{
|
||||
AddStep("upwards scroll", () => direction.Value = ManiaScrollingDirection.Up);
|
||||
AddStep("downwards scroll", () => direction.Value = ManiaScrollingDirection.Down);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(RulesetConfigCache configCache)
|
||||
{
|
||||
var config = (ManiaConfigManager)configCache.GetConfigFor(Ruleset.Value.CreateInstance());
|
||||
config.BindWith(ManiaSetting.ScrollDirection, direction);
|
||||
}
|
||||
}
|
||||
}
|
@ -46,15 +46,20 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
Spacing = new Vector2(20),
|
||||
Children = new[]
|
||||
{
|
||||
createNoteDisplay(ScrollingDirection.Down),
|
||||
createNoteDisplay(ScrollingDirection.Up),
|
||||
createHoldNoteDisplay(ScrollingDirection.Down),
|
||||
createHoldNoteDisplay(ScrollingDirection.Up),
|
||||
createNoteDisplay(ScrollingDirection.Down, 1, out var note1),
|
||||
createNoteDisplay(ScrollingDirection.Up, 2, out var note2),
|
||||
createHoldNoteDisplay(ScrollingDirection.Down, 1, out var holdNote1),
|
||||
createHoldNoteDisplay(ScrollingDirection.Up, 2, out var holdNote2),
|
||||
}
|
||||
};
|
||||
|
||||
AddAssert("note 1 facing downwards", () => verifyAnchors(note1, Anchor.y2));
|
||||
AddAssert("note 2 facing upwards", () => verifyAnchors(note2, Anchor.y0));
|
||||
AddAssert("hold note 1 facing downwards", () => verifyAnchors(holdNote1, Anchor.y2));
|
||||
AddAssert("hold note 2 facing upwards", () => verifyAnchors(holdNote2, Anchor.y0));
|
||||
}
|
||||
|
||||
private Drawable createNoteDisplay(ScrollingDirection direction)
|
||||
private Drawable createNoteDisplay(ScrollingDirection direction, int identifier, out DrawableNote hitObject)
|
||||
{
|
||||
var note = new Note { StartTime = 999999999 };
|
||||
note.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||
@ -62,24 +67,24 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
return new ScrollingTestContainer(direction)
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Child = new NoteContainer(direction, $"note, scrolling {direction.ToString().ToLowerInvariant()}")
|
||||
Child = new NoteContainer(direction, $"note {identifier}, scrolling {direction.ToString().ToLowerInvariant()}")
|
||||
{
|
||||
Child = new DrawableNote(note) { AccentColour = Color4.OrangeRed }
|
||||
Child = hitObject = new DrawableNote(note) { AccentColour = Color4.OrangeRed }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Drawable createHoldNoteDisplay(ScrollingDirection direction)
|
||||
private Drawable createHoldNoteDisplay(ScrollingDirection direction, int identifier, out DrawableHoldNote hitObject)
|
||||
{
|
||||
var note = new HoldNote { StartTime = 999999999, Duration = 1000 };
|
||||
var note = new HoldNote { StartTime = 999999999, Duration = 5000 };
|
||||
note.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||
|
||||
return new ScrollingTestContainer(direction)
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Child = new NoteContainer(direction, $"hold note, scrolling {direction.ToString().ToLowerInvariant()}")
|
||||
Child = new NoteContainer(direction, $"hold note {identifier}, scrolling {direction.ToString().ToLowerInvariant()}")
|
||||
{
|
||||
Child = new DrawableHoldNote(note)
|
||||
Child = hitObject = new DrawableHoldNote(note)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
AccentColour = Color4.OrangeRed,
|
||||
@ -88,6 +93,12 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
};
|
||||
}
|
||||
|
||||
private bool verifyAnchors(DrawableHitObject hitObject, Anchor expectedAnchor)
|
||||
=> hitObject.Anchor.HasFlag(expectedAnchor) && hitObject.Origin.HasFlag(expectedAnchor);
|
||||
|
||||
private bool verifyAnchors(DrawableHoldNote holdNote, Anchor expectedAnchor)
|
||||
=> verifyAnchors((DrawableHitObject)holdNote, expectedAnchor) && holdNote.NestedHitObjects.All(n => verifyAnchors(n, expectedAnchor));
|
||||
|
||||
private class NoteContainer : Container
|
||||
{
|
||||
private readonly Container content;
|
||||
|
@ -2,6 +2,7 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
@ -24,6 +25,8 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
|
||||
private readonly List<ManiaStage> stages = new List<ManiaStage>();
|
||||
|
||||
private FillFlowContainer<ScrollingTestContainer> fill;
|
||||
|
||||
public TestCaseStage()
|
||||
: base(columns)
|
||||
{
|
||||
@ -32,7 +35,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Child = new FillFlowContainer
|
||||
Child = fill = new FillFlowContainer<ScrollingTestContainer>
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Anchor = Anchor.Centre,
|
||||
@ -54,8 +57,22 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
AddStep("hold note", createHoldNote);
|
||||
AddStep("minor bar line", () => createBarLine(false));
|
||||
AddStep("major bar line", () => createBarLine(true));
|
||||
|
||||
AddAssert("check note anchors", () => notesInStageAreAnchored(stages[0], Anchor.TopCentre));
|
||||
AddAssert("check note anchors", () => notesInStageAreAnchored(stages[1], Anchor.BottomCentre));
|
||||
|
||||
AddStep("flip direction", () =>
|
||||
{
|
||||
foreach (var c in fill.Children)
|
||||
c.Flip();
|
||||
});
|
||||
|
||||
AddAssert("check note anchors", () => notesInStageAreAnchored(stages[0], Anchor.BottomCentre));
|
||||
AddAssert("check note anchors", () => notesInStageAreAnchored(stages[1], Anchor.TopCentre));
|
||||
}
|
||||
|
||||
private bool notesInStageAreAnchored(ManiaStage stage, Anchor anchor) => stage.Columns.SelectMany(c => c.AllHitObjects).All(o => o.Anchor == anchor);
|
||||
|
||||
private void createNote()
|
||||
{
|
||||
foreach (var stage in stages)
|
||||
@ -101,7 +118,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
}
|
||||
}
|
||||
|
||||
private Drawable createStage(ScrollingDirection direction, ManiaAction action)
|
||||
private ScrollingTestContainer createStage(ScrollingDirection direction, ManiaAction action)
|
||||
{
|
||||
var specialAction = ManiaAction.Special1;
|
||||
|
||||
|
@ -176,16 +176,23 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
int nextColumn = Random.Next(RandomStart, TotalColumns);
|
||||
for (int i = 0; i < Math.Min(usableColumns, noteCount); i++)
|
||||
{
|
||||
while (pattern.ColumnHasObject(nextColumn) || PreviousPattern.ColumnHasObject(nextColumn)) //find available column
|
||||
// Find available column
|
||||
RunWhile(() => pattern.ColumnHasObject(nextColumn) || PreviousPattern.ColumnHasObject(nextColumn), () =>
|
||||
{
|
||||
nextColumn = Random.Next(RandomStart, TotalColumns);
|
||||
});
|
||||
|
||||
addToPattern(pattern, nextColumn, startTime, EndTime);
|
||||
}
|
||||
|
||||
// This is can't be combined with the above loop due to RNG
|
||||
for (int i = 0; i < noteCount - usableColumns; i++)
|
||||
{
|
||||
while (pattern.ColumnHasObject(nextColumn))
|
||||
RunWhile(() => pattern.ColumnHasObject(nextColumn), () =>
|
||||
{
|
||||
nextColumn = Random.Next(RandomStart, TotalColumns);
|
||||
});
|
||||
|
||||
addToPattern(pattern, nextColumn, startTime, EndTime);
|
||||
}
|
||||
|
||||
@ -211,16 +218,21 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
||||
if (convertType.HasFlag(PatternType.ForceNotStack) && PreviousPattern.ColumnWithObjects < TotalColumns)
|
||||
{
|
||||
while (PreviousPattern.ColumnHasObject(nextColumn))
|
||||
RunWhile(() => PreviousPattern.ColumnHasObject(nextColumn), () =>
|
||||
{
|
||||
nextColumn = Random.Next(RandomStart, TotalColumns);
|
||||
});
|
||||
}
|
||||
|
||||
int lastColumn = nextColumn;
|
||||
for (int i = 0; i < noteCount; i++)
|
||||
{
|
||||
addToPattern(pattern, nextColumn, startTime, startTime);
|
||||
while (nextColumn == lastColumn)
|
||||
|
||||
RunWhile(() => nextColumn == lastColumn, () =>
|
||||
{
|
||||
nextColumn = Random.Next(RandomStart, TotalColumns);
|
||||
});
|
||||
|
||||
lastColumn = nextColumn;
|
||||
startTime += SegmentDuration;
|
||||
@ -393,14 +405,18 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
||||
if (convertType.HasFlag(PatternType.ForceNotStack) && PreviousPattern.ColumnWithObjects < TotalColumns)
|
||||
{
|
||||
while (PreviousPattern.ColumnHasObject(nextColumn))
|
||||
RunWhile(() => PreviousPattern.ColumnHasObject(nextColumn), () =>
|
||||
{
|
||||
nextColumn = Random.Next(RandomStart, TotalColumns);
|
||||
});
|
||||
}
|
||||
|
||||
for (int i = 0; i < columnRepeat; i++)
|
||||
{
|
||||
while (pattern.ColumnHasObject(nextColumn))
|
||||
RunWhile(() => pattern.ColumnHasObject(nextColumn), () =>
|
||||
{
|
||||
nextColumn = Random.Next(RandomStart, TotalColumns);
|
||||
});
|
||||
|
||||
addToPattern(pattern, nextColumn, startTime, EndTime);
|
||||
startTime += SegmentDuration;
|
||||
@ -427,8 +443,10 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
int holdColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
||||
if (convertType.HasFlag(PatternType.ForceNotStack) && PreviousPattern.ColumnWithObjects < TotalColumns)
|
||||
{
|
||||
while (PreviousPattern.ColumnHasObject(holdColumn))
|
||||
RunWhile(() => PreviousPattern.ColumnHasObject(holdColumn), () =>
|
||||
{
|
||||
holdColumn = Random.Next(RandomStart, TotalColumns);
|
||||
});
|
||||
}
|
||||
|
||||
// Create the hold note
|
||||
@ -455,8 +473,11 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
{
|
||||
for (int j = 0; j < noteCount; j++)
|
||||
{
|
||||
while (rowPattern.ColumnHasObject(nextColumn) || nextColumn == holdColumn)
|
||||
RunWhile(() => rowPattern.ColumnHasObject(nextColumn) || nextColumn == holdColumn, () =>
|
||||
{
|
||||
nextColumn = Random.Next(RandomStart, TotalColumns);
|
||||
});
|
||||
|
||||
addToPattern(rowPattern, nextColumn, startTime, startTime);
|
||||
}
|
||||
}
|
||||
|
@ -59,8 +59,10 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
{
|
||||
int nextColumn = Random.Next(start, TotalColumns);
|
||||
|
||||
while (PreviousPattern.ColumnHasObject(nextColumn))
|
||||
RunWhile(() => PreviousPattern.ColumnHasObject(nextColumn), () =>
|
||||
{
|
||||
nextColumn = Random.Next(start, TotalColumns);
|
||||
});
|
||||
|
||||
return nextColumn;
|
||||
}
|
||||
|
@ -234,7 +234,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
||||
for (int i = 0; i < noteCount; i++)
|
||||
{
|
||||
while (pattern.ColumnHasObject(nextColumn) || PreviousPattern.ColumnHasObject(nextColumn) && !allowStacking)
|
||||
RunWhile(() => pattern.ColumnHasObject(nextColumn) || PreviousPattern.ColumnHasObject(nextColumn) && !allowStacking, () =>
|
||||
{
|
||||
if (convertType.HasFlag(PatternType.Gathered))
|
||||
{
|
||||
@ -244,7 +244,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
}
|
||||
else
|
||||
nextColumn = Random.Next(RandomStart, TotalColumns);
|
||||
}
|
||||
});
|
||||
|
||||
addToPattern(pattern, nextColumn);
|
||||
}
|
||||
@ -295,8 +295,10 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
int nextColumn = Random.Next(RandomStart, columnLimit);
|
||||
for (int i = 0; i < noteCount; i++)
|
||||
{
|
||||
while (pattern.ColumnHasObject(nextColumn))
|
||||
RunWhile(() => pattern.ColumnHasObject(nextColumn), () =>
|
||||
{
|
||||
nextColumn = Random.Next(RandomStart, columnLimit);
|
||||
});
|
||||
|
||||
// Add normal note
|
||||
addToPattern(pattern, nextColumn);
|
||||
|
@ -3,6 +3,9 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns
|
||||
@ -12,6 +15,12 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns
|
||||
/// </summary>
|
||||
internal abstract class PatternGenerator
|
||||
{
|
||||
/// <summary>
|
||||
/// An arbitrary maximum amount of iterations to perform in <see cref="RunWhile"/>.
|
||||
/// The specific value is not super important - enough such that no false-positives occur.
|
||||
/// </summary>
|
||||
private const int max_rng_iterations = 20;
|
||||
|
||||
/// <summary>
|
||||
/// The last pattern.
|
||||
/// </summary>
|
||||
@ -42,6 +51,21 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns
|
||||
TotalColumns = Beatmap.TotalColumns;
|
||||
}
|
||||
|
||||
protected void RunWhile([InstantHandle] Func<bool> condition, Action action)
|
||||
{
|
||||
int iterations = 0;
|
||||
|
||||
while (condition() && iterations++ < max_rng_iterations)
|
||||
action();
|
||||
|
||||
if (iterations < max_rng_iterations)
|
||||
return;
|
||||
|
||||
// Generate + log an error/stacktrace
|
||||
|
||||
Logger.Log($"Allowable iterations ({max_rng_iterations}) exceeded:\n{new StackTrace(0)}", level: LogLevel.Error);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates the patterns for <see cref="HitObject"/>, each filled with hit objects.
|
||||
/// </summary>
|
||||
|
@ -0,0 +1,84 @@
|
||||
// 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.Framework.Configuration;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Edit.Layers.Selection.Overlays
|
||||
{
|
||||
public class HoldNoteMask : HitObjectMask
|
||||
{
|
||||
public new DrawableHoldNote HitObject => (DrawableHoldNote)base.HitObject;
|
||||
|
||||
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
||||
|
||||
private readonly BodyPiece body;
|
||||
|
||||
public HoldNoteMask(DrawableHoldNote hold)
|
||||
: base(hold)
|
||||
{
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
new HoldNoteNoteMask(hold.Head),
|
||||
new HoldNoteNoteMask(hold.Tail),
|
||||
body = new BodyPiece
|
||||
{
|
||||
AccentColour = Color4.Transparent
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours, IScrollingInfo scrollingInfo)
|
||||
{
|
||||
body.BorderColour = colours.Yellow;
|
||||
|
||||
direction.BindTo(scrollingInfo.Direction);
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
Size = HitObject.DrawSize + new Vector2(0, HitObject.Tail.DrawHeight);
|
||||
Position = Parent.ToLocalSpace(HitObject.ScreenSpaceDrawQuad.TopLeft);
|
||||
|
||||
// This is a side-effect of not matching the hitobject's anchors/origins, which is kinda hard to do
|
||||
// When scrolling upwards our origin is already at the top of the head note (which is the intended location),
|
||||
// but when scrolling downwards our origin is at the _bottom_ of the tail note (where we need to be at the _top_ of the tail note)
|
||||
if (direction.Value == ScrollingDirection.Down)
|
||||
Y -= HitObject.Tail.DrawHeight;
|
||||
}
|
||||
|
||||
private class HoldNoteNoteMask : NoteMask
|
||||
{
|
||||
public HoldNoteNoteMask(DrawableNote note)
|
||||
: base(note)
|
||||
{
|
||||
Select();
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
Anchor = HitObject.Anchor;
|
||||
Origin = HitObject.Origin;
|
||||
|
||||
Position = HitObject.DrawPosition;
|
||||
}
|
||||
|
||||
// Todo: This is temporary, since the note masks don't do anything special yet. In the future they will handle input.
|
||||
public override bool HandleMouseInput => false;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
// 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.Edit;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Edit.Layers.Selection.Overlays
|
||||
{
|
||||
public class NoteMask : HitObjectMask
|
||||
{
|
||||
public NoteMask(DrawableNote note)
|
||||
: base(note)
|
||||
{
|
||||
Scale = note.Scale;
|
||||
|
||||
CornerRadius = 5;
|
||||
Masking = true;
|
||||
|
||||
AddInternal(new NotePiece());
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
Colour = colours.Yellow;
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
Size = HitObject.DrawSize;
|
||||
Position = Parent.ToLocalSpace(HitObject.ScreenSpaceDrawQuad.TopLeft);
|
||||
}
|
||||
}
|
||||
}
|
17
osu.Game.Rulesets.Mania/Edit/ManiaEditPlayfield.cs
Normal file
17
osu.Game.Rulesets.Mania/Edit/ManiaEditPlayfield.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.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Edit
|
||||
{
|
||||
public class ManiaEditPlayfield : ManiaPlayfield
|
||||
{
|
||||
public ManiaEditPlayfield(List<StageDefinition> stages)
|
||||
: base(stages)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
27
osu.Game.Rulesets.Mania/Edit/ManiaEditRulesetContainer.cs
Normal file
27
osu.Game.Rulesets.Mania/Edit/ManiaEditRulesetContainer.cs
Normal file
@ -0,0 +1,27 @@
|
||||
// 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.Graphics;
|
||||
using OpenTK;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
using osu.Game.Rulesets.UI;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Edit
|
||||
{
|
||||
public class ManiaEditRulesetContainer : ManiaRulesetContainer
|
||||
{
|
||||
public ManiaEditRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap)
|
||||
: base(ruleset, beatmap)
|
||||
{
|
||||
}
|
||||
|
||||
protected override Playfield CreatePlayfield() => new ManiaEditPlayfield(Beatmap.Stages)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
};
|
||||
|
||||
protected override Vector2 PlayfieldArea => Vector2.One;
|
||||
}
|
||||
}
|
56
osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs
Normal file
56
osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs
Normal file
@ -0,0 +1,56 @@
|
||||
// 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.Beatmaps;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Edit.Tools;
|
||||
using osu.Game.Rulesets.Mania.Edit.Layers.Selection.Overlays;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Rulesets.Mania.Configuration;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Edit
|
||||
{
|
||||
public class ManiaHitObjectComposer : HitObjectComposer
|
||||
{
|
||||
protected new ManiaConfigManager Config => (ManiaConfigManager)base.Config;
|
||||
|
||||
public ManiaHitObjectComposer(Ruleset ruleset)
|
||||
: base(ruleset)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
||||
{
|
||||
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
||||
dependencies.CacheAs<IScrollingInfo>(new ManiaScrollingInfo(Config));
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
protected override RulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) => new ManiaEditRulesetContainer(ruleset, beatmap);
|
||||
|
||||
protected override IReadOnlyList<ICompositionTool> CompositionTools => new ICompositionTool[]
|
||||
{
|
||||
new HitObjectCompositionTool<Note>("Note"),
|
||||
new HitObjectCompositionTool<HoldNote>("Hold"),
|
||||
};
|
||||
|
||||
public override HitObjectMask CreateMaskFor(DrawableHitObject hitObject)
|
||||
{
|
||||
switch (hitObject)
|
||||
{
|
||||
case DrawableNote note:
|
||||
return new NoteMask(note);
|
||||
case DrawableHoldNote holdNote:
|
||||
return new HoldNoteMask(holdNote);
|
||||
}
|
||||
|
||||
return base.CreateMaskFor(hitObject);
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -19,9 +19,11 @@ using osu.Game.Configuration;
|
||||
using osu.Game.Overlays.Settings;
|
||||
using osu.Game.Rulesets.Configuration;
|
||||
using osu.Game.Rulesets.Difficulty;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Configuration;
|
||||
using osu.Game.Rulesets.Mania.Difficulty;
|
||||
using osu.Game.Rulesets.Mania.Edit;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania
|
||||
@ -32,6 +34,8 @@ namespace osu.Game.Rulesets.Mania
|
||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap);
|
||||
public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, Score score) => new ManiaPerformanceCalculator(this, beatmap, score);
|
||||
|
||||
public override HitObjectComposer CreateHitObjectComposer() => new ManiaHitObjectComposer(this);
|
||||
|
||||
public override IEnumerable<Mod> ConvertLegacyMods(LegacyMods mods)
|
||||
{
|
||||
if (mods.HasFlag(LegacyMods.Nightcore))
|
||||
@ -120,7 +124,7 @@ namespace osu.Game.Rulesets.Mania
|
||||
new MultiMod(new ManiaModFadeIn(), new ManiaModHidden()),
|
||||
new ManiaModFlashlight(),
|
||||
};
|
||||
case ModType.Special:
|
||||
case ModType.Conversion:
|
||||
return new Mod[]
|
||||
{
|
||||
new MultiMod(new ManiaModKey4(),
|
||||
@ -135,6 +139,10 @@ namespace osu.Game.Rulesets.Mania
|
||||
new ManiaModRandom(),
|
||||
new ManiaModDualStages(),
|
||||
new ManiaModMirror(),
|
||||
};
|
||||
case ModType.Automation:
|
||||
return new Mod[]
|
||||
{
|
||||
new MultiMod(new ManiaModAutoplay(), new ModCinema()),
|
||||
};
|
||||
default:
|
||||
|
@ -13,6 +13,7 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
{
|
||||
public override string ShortenedName => Name;
|
||||
public abstract int KeyCount { get; }
|
||||
public override ModType Type => ModType.Conversion;
|
||||
public override double ScoreMultiplier => 1; // TODO: Implement the mania key mod score multiplier
|
||||
public override bool Ranked => true;
|
||||
|
||||
|
@ -16,6 +16,7 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
public override string Name => "Dual Stages";
|
||||
public override string ShortenedName => "DS";
|
||||
public override string Description => @"Double the stages, double the fun!";
|
||||
public override ModType Type => ModType.Conversion;
|
||||
public override double ScoreMultiplier => 1;
|
||||
|
||||
private bool isForCurrentRuleset;
|
||||
|
@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
{
|
||||
public override string Name => "Mirror";
|
||||
public override string ShortenedName => "MR";
|
||||
public override ModType Type => ModType.Special;
|
||||
public override ModType Type => ModType.Conversion;
|
||||
public override double ScoreMultiplier => 1;
|
||||
public override bool Ranked => true;
|
||||
|
||||
|
@ -16,6 +16,7 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
{
|
||||
public override string Name => "Random";
|
||||
public override string ShortenedName => "RD";
|
||||
public override ModType Type => ModType.Conversion;
|
||||
public override FontAwesome Icon => FontAwesome.fa_osu_dice;
|
||||
public override string Description => @"Shuffle around the keys!";
|
||||
public override double ScoreMultiplier => 1;
|
||||
|
@ -7,7 +7,6 @@ using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Rulesets.Mania.Judgements;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
@ -19,10 +18,10 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
/// </summary>
|
||||
public class DrawableHoldNote : DrawableManiaHitObject<HoldNote>, IKeyBindingHandler<ManiaAction>
|
||||
{
|
||||
public override bool DisplayJudgement => false;
|
||||
public override bool DisplayResult => false;
|
||||
|
||||
private readonly DrawableNote head;
|
||||
private readonly DrawableNote tail;
|
||||
public readonly DrawableNote Head;
|
||||
public readonly DrawableNote Tail;
|
||||
|
||||
private readonly BodyPiece bodyPiece;
|
||||
|
||||
@ -57,12 +56,12 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
HoldStartTime = () => holdStartTime
|
||||
})
|
||||
},
|
||||
head = new DrawableHeadNote(this)
|
||||
Head = new DrawableHeadNote(this)
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre
|
||||
},
|
||||
tail = new DrawableTailNote(this)
|
||||
Tail = new DrawableTailNote(this)
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre
|
||||
@ -72,8 +71,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
foreach (var tick in tickContainer)
|
||||
AddNested(tick);
|
||||
|
||||
AddNested(head);
|
||||
AddNested(tail);
|
||||
AddNested(Head);
|
||||
AddNested(Tail);
|
||||
}
|
||||
|
||||
protected override void OnDirectionChanged(ScrollingDirection direction)
|
||||
@ -91,16 +90,16 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
base.AccentColour = value;
|
||||
|
||||
bodyPiece.AccentColour = value;
|
||||
head.AccentColour = value;
|
||||
tail.AccentColour = value;
|
||||
Head.AccentColour = value;
|
||||
Tail.AccentColour = value;
|
||||
tickContainer.ForEach(t => t.AccentColour = value);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||
{
|
||||
if (tail.AllJudged)
|
||||
AddJudgement(new HoldNoteJudgement { Result = HitResult.Perfect });
|
||||
if (Tail.AllJudged)
|
||||
ApplyResult(r => r.Type = HitResult.Perfect);
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
@ -108,8 +107,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
base.Update();
|
||||
|
||||
// Make the body piece not lie under the head note
|
||||
bodyPiece.Y = (Direction.Value == ScrollingDirection.Up ? 1 : -1) * head.Height / 2;
|
||||
bodyPiece.Height = DrawHeight - head.Height / 2 + tail.Height / 2;
|
||||
bodyPiece.Y = (Direction.Value == ScrollingDirection.Up ? 1 : -1) * Head.Height / 2;
|
||||
bodyPiece.Height = DrawHeight - Head.Height / 2 + Tail.Height / 2;
|
||||
}
|
||||
|
||||
public bool OnPressed(ManiaAction action)
|
||||
@ -141,7 +140,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
holdStartTime = null;
|
||||
|
||||
// If the key has been released too early, the user should not receive full score for the release
|
||||
if (!tail.IsHit)
|
||||
if (!Tail.IsHit)
|
||||
hasBroken = true;
|
||||
|
||||
return true;
|
||||
@ -166,7 +165,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
return false;
|
||||
|
||||
// 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;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||
{
|
||||
// Factor in the release lenience
|
||||
timeOffset /= release_window_lenience;
|
||||
@ -205,13 +204,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
if (!userTriggered)
|
||||
{
|
||||
if (!HitObject.HitWindows.CanBeHit(timeOffset))
|
||||
{
|
||||
AddJudgement(new HoldNoteTailJudgement
|
||||
{
|
||||
Result = HitResult.Miss,
|
||||
HasBroken = holdNote.hasBroken
|
||||
});
|
||||
}
|
||||
ApplyResult(r => r.Type = HitResult.Miss);
|
||||
|
||||
return;
|
||||
}
|
||||
@ -220,10 +213,12 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
if (result == HitResult.None)
|
||||
return;
|
||||
|
||||
AddJudgement(new HoldNoteTailJudgement
|
||||
ApplyResult(r =>
|
||||
{
|
||||
Result = result,
|
||||
HasBroken = holdNote.hasBroken
|
||||
if (holdNote.hasBroken && (result == HitResult.Perfect || result == HitResult.Perfect))
|
||||
result = HitResult.Good;
|
||||
|
||||
r.Type = result;
|
||||
});
|
||||
}
|
||||
|
||||
@ -238,7 +233,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
if (action != Action.Value)
|
||||
return false;
|
||||
|
||||
UpdateJudgement(true);
|
||||
UpdateResult(true);
|
||||
|
||||
// Handled by the hold note, which will set holding = false
|
||||
return false;
|
||||
|
@ -7,7 +7,6 @@ using OpenTK.Graphics;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Rulesets.Mania.Judgements;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
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)
|
||||
return;
|
||||
|
||||
if (HoldStartTime?.Invoke() > HitObject.StartTime)
|
||||
return;
|
||||
var startTime = HoldStartTime?.Invoke();
|
||||
|
||||
AddJudgement(new HoldNoteTickJudgement { Result = HitResult.Perfect });
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
if (AllJudged)
|
||||
return;
|
||||
|
||||
if (HoldStartTime?.Invoke() == null)
|
||||
return;
|
||||
|
||||
UpdateJudgement(true);
|
||||
if (startTime == null || startTime > HitObject.StartTime)
|
||||
ApplyResult(r => r.Type = HitResult.Miss);
|
||||
else
|
||||
ApplyResult(r => r.Type = HitResult.Perfect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ using OpenTK.Graphics;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Game.Rulesets.Mania.Judgements;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
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 (!HitObject.HitWindows.CanBeHit(timeOffset))
|
||||
AddJudgement(new ManiaJudgement { Result = HitResult.Miss });
|
||||
ApplyResult(r => r.Type = HitResult.Miss);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -69,7 +68,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
if (result == HitResult.None)
|
||||
return;
|
||||
|
||||
AddJudgement(new ManiaJudgement { Result = result });
|
||||
ApplyResult(r => r.Type = result);
|
||||
}
|
||||
|
||||
public virtual bool OnPressed(ManiaAction action)
|
||||
@ -77,7 +76,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
if (action != Action.Value)
|
||||
return false;
|
||||
|
||||
return UpdateJudgement(true);
|
||||
return UpdateResult(true);
|
||||
}
|
||||
|
||||
public virtual bool OnReleased(ManiaAction action) => false;
|
||||
|
@ -3,6 +3,8 @@
|
||||
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Mania.Judgements;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Objects
|
||||
@ -55,7 +57,7 @@ namespace osu.Game.Rulesets.Mania.Objects
|
||||
/// <summary>
|
||||
/// The tail note of the hold.
|
||||
/// </summary>
|
||||
public readonly Note Tail = new Note();
|
||||
public readonly TailNote Tail = new TailNote();
|
||||
|
||||
/// <summary>
|
||||
/// The time between ticks of this hold.
|
||||
@ -68,9 +70,6 @@ namespace osu.Game.Rulesets.Mania.Objects
|
||||
|
||||
TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime);
|
||||
tickSpacing = timingPoint.BeatLength / difficulty.SliderTickRate;
|
||||
|
||||
Head.ApplyDefaults(controlPointInfo, difficulty);
|
||||
Tail.ApplyDefaults(controlPointInfo, difficulty);
|
||||
}
|
||||
|
||||
protected override void CreateNestedHitObjects()
|
||||
@ -78,6 +77,9 @@ namespace osu.Game.Rulesets.Mania.Objects
|
||||
base.CreateNestedHitObjects();
|
||||
|
||||
createTicks();
|
||||
|
||||
AddNested(Head);
|
||||
AddNested(Tail);
|
||||
}
|
||||
|
||||
private void createTicks()
|
||||
@ -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>.
|
||||
// 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
|
||||
{
|
||||
/// <summary>
|
||||
@ -8,5 +11,6 @@ namespace osu.Game.Rulesets.Mania.Objects
|
||||
/// </summary>
|
||||
public class HoldNoteTick : ManiaHitObject
|
||||
{
|
||||
public override Judgement CreateJudgement() => new HoldNoteTickJudgement();
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +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
|
||||
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Mania.Judgements;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Objects
|
||||
{
|
||||
/// <summary>
|
||||
@ -8,5 +11,6 @@ namespace osu.Game.Rulesets.Mania.Objects
|
||||
/// </summary>
|
||||
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>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.Linq;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.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;
|
||||
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);
|
||||
}
|
||||
|
||||
protected override void SimulateAutoplay(Beatmap<ManiaHitObject> beatmap)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
foreach (var obj in beatmap.HitObjects)
|
||||
{
|
||||
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 });
|
||||
}
|
||||
base.SimulateAutoplay(beatmap);
|
||||
|
||||
if (!HasFailed)
|
||||
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 (judgement.IsHit)
|
||||
if (result.IsHit)
|
||||
Health.Value += hpMultiplier * hp_increase_tick;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (judgement.Result)
|
||||
switch (result.Type)
|
||||
{
|
||||
case HitResult.Miss:
|
||||
Health.Value += hpMissMultiplier * hp_increase_miss;
|
||||
|
@ -131,14 +131,14 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
public override void Add(DrawableHitObject hitObject)
|
||||
{
|
||||
hitObject.AccentColour = AccentColour;
|
||||
hitObject.OnJudgement += OnJudgement;
|
||||
hitObject.OnNewResult += OnNewResult;
|
||||
|
||||
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;
|
||||
|
||||
explosionContainer.Add(new HitExplosion(judgedObject)
|
||||
|
@ -8,10 +8,10 @@ using osu.Game.Rulesets.Objects.Drawables;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
internal class DrawableManiaJudgement : DrawableJudgement
|
||||
public class DrawableManiaJudgement : DrawableJudgement
|
||||
{
|
||||
public DrawableManiaJudgement(Judgement judgement, DrawableHitObject judgedObject)
|
||||
: base(judgement, judgedObject)
|
||||
public DrawableManiaJudgement(JudgementResult result, DrawableHitObject judgedObject)
|
||||
: base(result, judgedObject)
|
||||
{
|
||||
}
|
||||
|
||||
@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
|
||||
this.FadeInFromZero(50, Easing.OutQuint);
|
||||
|
||||
if (Judgement.IsHit)
|
||||
if (Result.IsHit)
|
||||
{
|
||||
this.ScaleTo(0.8f);
|
||||
this.ScaleTo(1, 250, Easing.OutElastic);
|
||||
|
@ -1,22 +1,20 @@
|
||||
// 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.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Mania.Configuration;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
public class ManiaPlayfield : ManiaScrollingPlayfield
|
||||
{
|
||||
public List<Column> Columns => stages.SelectMany(x => x.Columns).ToList();
|
||||
private readonly List<ManiaStage> stages = new List<ManiaStage>();
|
||||
|
||||
public ManiaPlayfield(List<StageDefinition> stageDefinitions)
|
||||
|
@ -4,7 +4,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Input;
|
||||
@ -35,8 +34,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
|
||||
public IEnumerable<BarLine> BarLines;
|
||||
|
||||
private readonly Bindable<ManiaScrollingDirection> configDirection = new Bindable<ManiaScrollingDirection>();
|
||||
private ScrollingInfo scrollingInfo;
|
||||
protected new ManiaConfigManager Config => (ManiaConfigManager)base.Config;
|
||||
|
||||
public ManiaRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap)
|
||||
: base(ruleset, beatmap)
|
||||
@ -73,9 +71,6 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
private void load()
|
||||
{
|
||||
BarLines.ForEach(Playfield.Add);
|
||||
|
||||
((ManiaConfigManager)Config).BindWith(ManiaSetting.ScrollDirection, configDirection);
|
||||
configDirection.BindValueChanged(d => scrollingInfo.Direction.Value = (ScrollingDirection)d, true);
|
||||
}
|
||||
|
||||
private DependencyContainer dependencies;
|
||||
@ -83,11 +78,14 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
||||
{
|
||||
dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
||||
dependencies.CacheAs<IScrollingInfo>(scrollingInfo = new ScrollingInfo());
|
||||
|
||||
if (dependencies.Get<ManiaScrollingInfo>() == null)
|
||||
dependencies.CacheAs<IScrollingInfo>(new ManiaScrollingInfo(Config));
|
||||
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
protected sealed override Playfield CreatePlayfield() => new ManiaPlayfield(Beatmap.Stages)
|
||||
protected override Playfield CreatePlayfield() => new ManiaPlayfield(Beatmap.Stages)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
@ -115,11 +113,5 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
protected override Vector2 PlayfieldArea => new Vector2(1, 0.8f);
|
||||
|
||||
protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new ManiaFramedReplayInputHandler(replay);
|
||||
|
||||
private class ScrollingInfo : IScrollingInfo
|
||||
{
|
||||
public readonly Bindable<ScrollingDirection> Direction = new Bindable<ScrollingDirection>();
|
||||
IBindable<ScrollingDirection> IScrollingInfo.Direction => Direction;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
23
osu.Game.Rulesets.Mania/UI/ManiaScrollingInfo.cs
Normal file
23
osu.Game.Rulesets.Mania/UI/ManiaScrollingInfo.cs
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Game.Rulesets.Mania.Configuration;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
public class ManiaScrollingInfo : IScrollingInfo
|
||||
{
|
||||
private readonly Bindable<ManiaScrollingDirection> configDirection = new Bindable<ManiaScrollingDirection>();
|
||||
|
||||
public readonly Bindable<ScrollingDirection> Direction = new Bindable<ScrollingDirection>();
|
||||
IBindable<ScrollingDirection> IScrollingInfo.Direction => Direction;
|
||||
|
||||
public ManiaScrollingInfo(ManiaConfigManager config)
|
||||
{
|
||||
config.BindWith(ManiaSetting.ScrollDirection, configDirection);
|
||||
configDirection.BindValueChanged(v => Direction.Value = (ScrollingDirection)v, true);
|
||||
}
|
||||
}
|
||||
}
|
@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
/// <summary>
|
||||
/// A collection of <see cref="Column"/>s.
|
||||
/// </summary>
|
||||
internal class ManiaStage : ManiaScrollingPlayfield
|
||||
public class ManiaStage : ManiaScrollingPlayfield
|
||||
{
|
||||
public const float HIT_TARGET_POSITION = 50;
|
||||
|
||||
@ -156,18 +156,18 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
var maniaObject = (ManiaHitObject)h.HitObject;
|
||||
int columnIndex = maniaObject.Column - firstColumnIndex;
|
||||
Columns.ElementAt(columnIndex).Add(h);
|
||||
h.OnJudgement += OnJudgement;
|
||||
h.OnNewResult += OnNewResult;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
judgements.Clear();
|
||||
judgements.Add(new DrawableManiaJudgement(judgement, judgedObject)
|
||||
judgements.Add(new DrawableManiaJudgement(result, judgedObject)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
|
@ -5,12 +5,10 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osu.Game.Tests.Visual;
|
||||
using OpenTK;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
@ -96,19 +94,15 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
this.auto = auto;
|
||||
}
|
||||
|
||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||
{
|
||||
if (auto && !userTriggered && timeOffset > 0)
|
||||
{
|
||||
// force success
|
||||
AddJudgement(new OsuJudgement
|
||||
{
|
||||
Result = HitResult.Great
|
||||
});
|
||||
State.Value = ArmedState.Hit;
|
||||
ApplyResult(r => r.Type = HitResult.Great);
|
||||
}
|
||||
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>())
|
||||
mod.ApplyToDrawableHitObjects(new[] { drawable });
|
||||
|
||||
drawable.OnJudgement += onJudgement;
|
||||
drawable.OnNewResult += onNewResult;
|
||||
|
||||
Add(drawable);
|
||||
}
|
||||
|
||||
private float judgementOffsetDirection = 1;
|
||||
private void onJudgement(DrawableHitObject judgedObject, Judgement judgement)
|
||||
private void onNewResult(DrawableHitObject judgedObject, JudgementResult result)
|
||||
{
|
||||
var osuObject = judgedObject as DrawableOsuHitObject;
|
||||
if (osuObject == null)
|
||||
@ -321,8 +321,8 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Text = judgement.IsHit ? "Hit!" : "Miss!",
|
||||
Colour = judgement.IsHit ? Color4.Green : Color4.Red,
|
||||
Text = result.IsHit ? "Hit!" : "Miss!",
|
||||
Colour = result.IsHit ? Color4.Green : Color4.Red,
|
||||
TextSize = 30,
|
||||
Position = osuObject.HitObject.StackedEndPosition + judgementOffsetDirection * new Vector2(0, 45)
|
||||
});
|
||||
|
@ -72,7 +72,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
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)
|
||||
{
|
||||
@ -81,7 +81,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
auto = false;
|
||||
}
|
||||
|
||||
base.CheckForJudgements(userTriggered, timeOffset);
|
||||
base.CheckForResult(userTriggered, timeOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -42,6 +42,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
||||
RepeatCount = curveData.RepeatCount,
|
||||
Position = positionData?.Position ?? Vector2.Zero,
|
||||
NewCombo = comboData?.NewCombo ?? false,
|
||||
ComboOffset = comboData?.ComboOffset ?? 0,
|
||||
LegacyLastTickOffset = legacyOffset?.LegacyLastTickOffset
|
||||
};
|
||||
}
|
||||
@ -52,7 +53,9 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
||||
StartTime = original.StartTime,
|
||||
Samples = original.Samples,
|
||||
EndTime = endTimeData.EndTime,
|
||||
Position = positionData?.Position ?? OsuPlayfield.BASE_SIZE / 2
|
||||
Position = positionData?.Position ?? OsuPlayfield.BASE_SIZE / 2,
|
||||
NewCombo = comboData?.NewCombo ?? false,
|
||||
ComboOffset = comboData?.ComboOffset ?? 0,
|
||||
};
|
||||
}
|
||||
else
|
||||
@ -62,7 +65,8 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
||||
StartTime = original.StartTime,
|
||||
Samples = original.Samples,
|
||||
Position = positionData?.Position ?? Vector2.Zero,
|
||||
NewCombo = comboData?.NewCombo ?? false
|
||||
NewCombo = comboData?.NewCombo ?? false,
|
||||
ComboOffset = comboData?.ComboOffset ?? 0,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
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
|
||||
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Judgements
|
||||
@ -25,7 +24,5 @@ namespace osu.Game.Rulesets.Osu.Judgements
|
||||
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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@ -12,6 +12,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
public override string Name => "Autopilot";
|
||||
public override string ShortenedName => "AP";
|
||||
public override FontAwesome Icon => FontAwesome.fa_osu_mod_autopilot;
|
||||
public override ModType Type => ModType.Automation;
|
||||
public override string Description => @"Automatic cursor movement - just follow the rhythm.";
|
||||
public override double ScoreMultiplier => 1;
|
||||
public override Type[] IncompatibleMods => new[] { typeof(OsuModSpunOut), typeof(ModRelax), typeof(ModSuddenDeath), typeof(ModNoFail), typeof(ModAutoplay) };
|
||||
|
@ -12,6 +12,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
public override string Name => "Spun Out";
|
||||
public override string ShortenedName => "SO";
|
||||
public override FontAwesome Icon => FontAwesome.fa_osu_mod_spunout;
|
||||
public override ModType Type => ModType.DifficultyReduction;
|
||||
public override string Description => @"Spinners will be automatically completed.";
|
||||
public override double ScoreMultiplier => 0.9;
|
||||
public override bool Ranked => true;
|
||||
|
@ -10,6 +10,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
{
|
||||
public override string Name => "Target";
|
||||
public override string ShortenedName => "TP";
|
||||
public override ModType Type => ModType.Conversion;
|
||||
public override FontAwesome Icon => FontAwesome.fa_osu_mod_target;
|
||||
public override string Description => @"Practice keeping up with the beat of the song.";
|
||||
public override double ScoreMultiplier => 1;
|
||||
|
@ -6,7 +6,6 @@ using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
|
||||
using OpenTK;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
@ -40,7 +39,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
if (AllJudged)
|
||||
return false;
|
||||
|
||||
UpdateJudgement(true);
|
||||
UpdateResult(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 (!HitObject.HitWindows.CanBeHit(timeOffset))
|
||||
AddJudgement(new OsuJudgement { Result = HitResult.Miss });
|
||||
ApplyResult(r => r.Type = HitResult.Miss);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -90,10 +90,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
if (result == HitResult.None)
|
||||
return;
|
||||
|
||||
AddJudgement(new OsuJudgement
|
||||
{
|
||||
Result = result,
|
||||
});
|
||||
ApplyResult(r => r.Type = result);
|
||||
}
|
||||
|
||||
protected override void UpdatePreemptState()
|
||||
|
@ -2,11 +2,11 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Framework.Graphics;
|
||||
using System.Linq;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Skinning;
|
||||
using OpenTK.Graphics;
|
||||
@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
{
|
||||
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))
|
||||
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
|
||||
// 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 ApplyTransformsAt(double time, bool propagateChildren = false) { }
|
||||
public override void ClearTransformsAfter(double time, bool propagateChildren = false, string targetMember = null)
|
||||
{
|
||||
}
|
||||
|
||||
public override void ApplyTransformsAt(double time, bool propagateChildren = false)
|
||||
{
|
||||
}
|
||||
|
||||
private OsuInputManager osuActionInputManager;
|
||||
internal OsuInputManager OsuActionInputManager => osuActionInputManager ?? (osuActionInputManager = GetContainingInputManager() as OsuInputManager);
|
||||
}
|
||||
|
||||
public enum ComboResult
|
||||
{
|
||||
[Description(@"")]
|
||||
None,
|
||||
[Description(@"Good")]
|
||||
Good,
|
||||
[Description(@"Amazing")]
|
||||
Perfect
|
||||
protected override JudgementResult CreateResult(Judgement judgement) => new OsuJudgementResult(judgement);
|
||||
}
|
||||
}
|
||||
|
@ -11,14 +11,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
{
|
||||
public class DrawableOsuJudgement : DrawableJudgement
|
||||
{
|
||||
public DrawableOsuJudgement(Judgement judgement, DrawableHitObject judgedObject)
|
||||
: base(judgement, judgedObject)
|
||||
public DrawableOsuJudgement(JudgementResult result, DrawableHitObject judgedObject)
|
||||
: base(result, judgedObject)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
if (Judgement.Result != HitResult.Miss)
|
||||
if (Result.Type != HitResult.Miss)
|
||||
JudgementText?.TransformSpacingTo(new Vector2(14, 0), 1800, Easing.OutQuint);
|
||||
|
||||
base.LoadComplete();
|
||||
|
@ -8,7 +8,6 @@ using osu.Framework.MathUtils;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using OpenTK;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
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)
|
||||
AddJudgement(new OsuJudgement { Result = drawableSlider.Tracking ? HitResult.Great : HitResult.Miss });
|
||||
ApplyResult(r => r.Type = drawableSlider.Tracking ? HitResult.Great : HitResult.Miss);
|
||||
}
|
||||
|
||||
protected override void UpdatePreemptState()
|
||||
|
@ -9,7 +9,6 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
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 judgementsHit = NestedHitObjects.Count(h => h.IsHit);
|
||||
|
||||
var hitFraction = (double)judgementsHit / judgementsCount;
|
||||
if (hitFraction == 1 && HeadCircle.Judgements.Any(j => j.Result == HitResult.Great))
|
||||
AddJudgement(new OsuJudgement { Result = HitResult.Great });
|
||||
else if (hitFraction >= 0.5 && HeadCircle.Judgements.Any(j => j.Result >= HitResult.Good))
|
||||
AddJudgement(new OsuJudgement { Result = HitResult.Good });
|
||||
|
||||
if (hitFraction == 1 && HeadCircle.Result.Type == HitResult.Great)
|
||||
r.Type = HitResult.Great;
|
||||
else if (hitFraction >= 0.5 && HeadCircle.Result.Type >= HitResult.Good)
|
||||
r.Type = HitResult.Good;
|
||||
else if (hitFraction > 0)
|
||||
AddJudgement(new OsuJudgement { Result = HitResult.Meh });
|
||||
r.Type = HitResult.Meh;
|
||||
else
|
||||
AddJudgement(new OsuJudgement { Result = HitResult.Miss });
|
||||
}
|
||||
r.Type = HitResult.Miss;
|
||||
});
|
||||
}
|
||||
|
||||
protected override void UpdateCurrentState(ArmedState state)
|
||||
|
@ -2,7 +2,6 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
@ -12,11 +11,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
/// <summary>
|
||||
/// The judgement text is provided by the <see cref="DrawableSlider"/>.
|
||||
/// </summary>
|
||||
public override bool DisplayJudgement => false;
|
||||
public override bool DisplayResult => false;
|
||||
|
||||
public bool Tracking { get; set; }
|
||||
|
||||
public DrawableSliderTail(Slider slider, HitCircle hitCircle)
|
||||
public DrawableSliderTail(Slider slider, SliderTailCircle hitCircle)
|
||||
: base(hitCircle)
|
||||
{
|
||||
Origin = Anchor.Centre;
|
||||
@ -29,10 +28,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
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)
|
||||
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.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
@ -19,7 +18,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
|
||||
public bool Tracking { get; set; }
|
||||
|
||||
public override bool DisplayJudgement => false;
|
||||
public override bool DisplayResult => false;
|
||||
|
||||
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)
|
||||
AddJudgement(new OsuJudgement { Result = Tracking ? HitResult.Great : HitResult.Miss });
|
||||
ApplyResult(r => r.Type = Tracking ? HitResult.Great : HitResult.Miss);
|
||||
}
|
||||
|
||||
protected override void UpdatePreemptState()
|
||||
|
@ -11,7 +11,6 @@ using OpenTK.Graphics;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
using osu.Game.Screens.Ranking;
|
||||
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);
|
||||
|
||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||
{
|
||||
if (Time.Current < HitObject.StartTime) return;
|
||||
|
||||
@ -136,17 +135,20 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
glow.FadeColour(completeColour, duration);
|
||||
}
|
||||
|
||||
if (!userTriggered && Time.Current >= Spinner.EndTime)
|
||||
if (userTriggered || Time.Current < Spinner.EndTime)
|
||||
return;
|
||||
|
||||
ApplyResult(r =>
|
||||
{
|
||||
if (Progress >= 1)
|
||||
AddJudgement(new OsuJudgement { Result = HitResult.Great });
|
||||
r.Type = HitResult.Great;
|
||||
else if (Progress > .9)
|
||||
AddJudgement(new OsuJudgement { Result = HitResult.Good });
|
||||
r.Type = HitResult.Good;
|
||||
else if (Progress > .75)
|
||||
AddJudgement(new OsuJudgement { Result = HitResult.Meh });
|
||||
r.Type = HitResult.Meh;
|
||||
else if (Time.Current >= Spinner.EndTime)
|
||||
AddJudgement(new OsuJudgement { Result = HitResult.Miss });
|
||||
}
|
||||
r.Type = HitResult.Miss;
|
||||
});
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
|
@ -1,9 +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.Osu.Judgements;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects
|
||||
{
|
||||
public class HitCircle : OsuHitObject
|
||||
{
|
||||
public override Judgement CreateJudgement() => new OsuJudgement();
|
||||
}
|
||||
}
|
||||
|
@ -54,6 +54,8 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
|
||||
public virtual bool NewCombo { get; set; }
|
||||
|
||||
public int ComboOffset { get; set; }
|
||||
|
||||
public virtual int IndexInCurrentCombo { get; set; }
|
||||
|
||||
public virtual int ComboIndex { get; set; }
|
||||
|
@ -4,6 +4,8 @@
|
||||
using System;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects
|
||||
{
|
||||
@ -24,5 +26,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
if (RepeatIndex > 0)
|
||||
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.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects
|
||||
{
|
||||
@ -94,7 +96,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
public double TickDistance;
|
||||
|
||||
public HitCircle HeadCircle;
|
||||
public HitCircle TailCircle;
|
||||
public SliderTailCircle TailCircle;
|
||||
|
||||
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||
{
|
||||
@ -133,7 +135,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
ComboIndex = ComboIndex,
|
||||
};
|
||||
|
||||
TailCircle = new SliderCircle(this)
|
||||
TailCircle = new SliderTailCircle(this)
|
||||
{
|
||||
StartTime = EndTime,
|
||||
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.ControlPoints;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects
|
||||
{
|
||||
@ -26,5 +28,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
|
||||
TimePreempt = (StartTime - SpanStartTime) / 2 + offset;
|
||||
}
|
||||
|
||||
public override Judgement CreateJudgement() => new OsuJudgement();
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,8 @@ using System;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
|
||||
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.
|
||||
SpinsRequired = (int)Math.Max(1, SpinsRequired * 0.6);
|
||||
}
|
||||
|
||||
public override Judgement CreateJudgement() => new OsuJudgement();
|
||||
}
|
||||
}
|
||||
|
@ -94,6 +94,7 @@ namespace osu.Game.Rulesets.Osu
|
||||
new OsuModEasy(),
|
||||
new OsuModNoFail(),
|
||||
new MultiMod(new OsuModHalfTime(), new OsuModDaycore()),
|
||||
new OsuModSpunOut(),
|
||||
};
|
||||
case ModType.DifficultyIncrease:
|
||||
return new Mod[]
|
||||
@ -104,14 +105,17 @@ namespace osu.Game.Rulesets.Osu
|
||||
new OsuModHidden(),
|
||||
new OsuModFlashlight(),
|
||||
};
|
||||
case ModType.Special:
|
||||
case ModType.Conversion:
|
||||
return new Mod[]
|
||||
{
|
||||
new OsuModTarget(),
|
||||
};
|
||||
case ModType.Automation:
|
||||
return new Mod[]
|
||||
{
|
||||
new MultiMod(new OsuModAutoplay(), new ModCinema()),
|
||||
new OsuModRelax(),
|
||||
new OsuModAutopilot(),
|
||||
new OsuModSpunOut(),
|
||||
new MultiMod(new OsuModAutoplay(), new ModCinema()),
|
||||
new OsuModTarget(),
|
||||
};
|
||||
default:
|
||||
return new Mod[] { };
|
||||
|
@ -2,13 +2,11 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
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<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;
|
||||
|
||||
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)
|
||||
@ -70,19 +51,19 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
||||
|
||||
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;
|
||||
comboResultCounts[osuJudgement.Combo] = comboResultCounts.GetOrDefault(osuJudgement.Combo) + 1;
|
||||
scoreResultCounts[result.Type] = scoreResultCounts.GetOrDefault(result.Type) + 1;
|
||||
comboResultCounts[osuResult.ComboType] = comboResultCounts.GetOrDefault(osuResult.ComboType) + 1;
|
||||
}
|
||||
|
||||
switch (judgement.Result)
|
||||
switch (result.Type)
|
||||
{
|
||||
case HitResult.Great:
|
||||
Health.Value += (10.2 - hpDrainRate) * harshness;
|
||||
@ -105,5 +86,7 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
||||
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)
|
||||
{
|
||||
h.OnJudgement += onJudgement;
|
||||
h.OnNewResult += onNewResult;
|
||||
|
||||
var c = h as IDrawableHitObjectWithProxiedApproach;
|
||||
if (c != null)
|
||||
@ -64,12 +64,12 @@ namespace osu.Game.Rulesets.Osu.UI
|
||||
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;
|
||||
|
||||
DrawableOsuJudgement explosion = new DrawableOsuJudgement(judgement, judgedObject)
|
||||
DrawableOsuJudgement explosion = new DrawableOsuJudgement(result, judgedObject)
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Position = ((OsuHitObject)judgedObject.HitObject).StackedEndPosition
|
||||
|
@ -8,9 +8,9 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Taiko.Judgements;
|
||||
@ -39,8 +39,10 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
AddStep("Hit!", () => addHitJudgement(false));
|
||||
AddStep("Hit", () => addHitJudgement(false));
|
||||
AddStep("Strong hit", () => addStrongHitJudgement(false));
|
||||
AddStep("Kiai hit", () => addHitJudgement(true));
|
||||
AddStep("Strong kiai hit", () => addStrongHitJudgement(true));
|
||||
AddStep("Miss :(", addMissJudgement);
|
||||
AddStep("DrumRoll", () => addDrumRoll(false));
|
||||
AddStep("Strong DrumRoll", () => addDrumRoll(true));
|
||||
@ -78,15 +80,12 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
||||
ControlPointInfo = controlPointInfo
|
||||
});
|
||||
|
||||
var rateAdjustClock = new StopwatchClock(true) { Rate = 1 };
|
||||
|
||||
Add(playfieldContainer = new Container
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 768,
|
||||
Clock = new FramedClock(rateAdjustClock),
|
||||
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;
|
||||
|
||||
var cpi = new ControlPointInfo();
|
||||
cpi.EffectPoints.Add(new EffectControlPoint
|
||||
{
|
||||
KiaiMode = kiai
|
||||
});
|
||||
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).OnJudgement(h, new TaikoJudgement { Result = hitResult });
|
||||
((TaikoPlayfield)rulesetContainer.Playfield).OnNewResult(h, new JudgementResult(new TaikoJudgement()) { Type = hitResult });
|
||||
}
|
||||
|
||||
if (RNG.Next(10) == 0)
|
||||
{
|
||||
((TaikoPlayfield)rulesetContainer.Playfield).OnJudgement(h, new TaikoJudgement { Result = hitResult });
|
||||
((TaikoPlayfield)rulesetContainer.Playfield).OnJudgement(h, new TaikoStrongHitJudgement());
|
||||
}
|
||||
private void addStrongHitJudgement(bool kiai)
|
||||
{
|
||||
HitResult hitResult = RNG.Next(2) == 0 ? HitResult.Good : HitResult.Great;
|
||||
|
||||
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()
|
||||
{
|
||||
((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)
|
||||
@ -204,10 +210,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
||||
|
||||
h.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||
|
||||
if (strong)
|
||||
rulesetContainer.Playfield.Add(new DrawableCentreHitStrong(h));
|
||||
else
|
||||
rulesetContainer.Playfield.Add(new DrawableCentreHit(h));
|
||||
rulesetContainer.Playfield.Add(new DrawableCentreHit(h));
|
||||
}
|
||||
|
||||
private void addRimHit(bool strong)
|
||||
@ -220,10 +223,17 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
||||
|
||||
h.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||
|
||||
if (strong)
|
||||
rulesetContainer.Playfield.Add(new DrawableRimHitStrong(h));
|
||||
else
|
||||
rulesetContainer.Playfield.Add(new DrawableRimHit(h));
|
||||
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>
|
||||
|
@ -168,7 +168,6 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
||||
{
|
||||
StartTime = obj.StartTime,
|
||||
Samples = obj.Samples,
|
||||
IsStrong = strong,
|
||||
Duration = endTimeData.Duration,
|
||||
RequiredHits = (int)Math.Max(1, endTimeData.Duration / 1000 * hitMultiplier)
|
||||
};
|
||||
|
@ -7,15 +7,10 @@ namespace osu.Game.Rulesets.Taiko.Judgements
|
||||
{
|
||||
public class TaikoIntermediateSwellJudgement : TaikoJudgement
|
||||
{
|
||||
public override HitResult MaxResult => HitResult.Perfect;
|
||||
public override HitResult MaxResult => HitResult.Great;
|
||||
|
||||
public override bool AffectsCombo => false;
|
||||
|
||||
public TaikoIntermediateSwellJudgement()
|
||||
{
|
||||
Final = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes the numeric result value for the combo portion of the score.
|
||||
/// </summary>
|
||||
|
@ -3,13 +3,8 @@
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Judgements
|
||||
{
|
||||
public class TaikoStrongHitJudgement : TaikoJudgement
|
||||
public class TaikoStrongJudgement : TaikoJudgement
|
||||
{
|
||||
public override bool AffectsCombo => false;
|
||||
|
||||
public TaikoStrongHitJudgement()
|
||||
{
|
||||
Final = true;
|
||||
}
|
||||
}
|
||||
}
|
@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
{
|
||||
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)
|
||||
: 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.Game.Graphics;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Taiko.Judgements;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
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>())
|
||||
{
|
||||
var newTick = new DrawableDrumRollTick(tick);
|
||||
newTick.OnJudgement += onTickJudgement;
|
||||
newTick.OnNewResult += onNewTickResult;
|
||||
|
||||
AddNested(newTick);
|
||||
tickContainer.Add(newTick);
|
||||
@ -61,9 +60,9 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
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++;
|
||||
else
|
||||
rollingHits--;
|
||||
@ -74,7 +73,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
MainPiece.FadeAccent(newColour, 100);
|
||||
}
|
||||
|
||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||
{
|
||||
if (userTriggered)
|
||||
return;
|
||||
@ -84,13 +83,9 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
|
||||
int countHit = NestedHitObjects.Count(o => o.IsHit);
|
||||
if (countHit >= HitObject.RequiredGoodHits)
|
||||
{
|
||||
AddJudgement(new TaikoJudgement { Result = countHit >= HitObject.RequiredGreatHits ? HitResult.Great : HitResult.Good });
|
||||
if (HitObject.IsStrong)
|
||||
AddJudgement(new TaikoStrongHitJudgement());
|
||||
}
|
||||
ApplyResult(r => r.Type = countHit >= HitObject.RequiredGreatHits ? HitResult.Great : HitResult.Good);
|
||||
else
|
||||
AddJudgement(new TaikoJudgement { Result = HitResult.Miss });
|
||||
ApplyResult(r => r.Type = HitResult.Miss);
|
||||
}
|
||||
|
||||
protected override void UpdateState(ArmedState state)
|
||||
@ -103,5 +98,25 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
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.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.Taiko.Judgements;
|
||||
using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
@ -18,24 +17,26 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
FillMode = FillMode.Fit;
|
||||
}
|
||||
|
||||
public override bool DisplayJudgement => false;
|
||||
public override bool DisplayResult => false;
|
||||
|
||||
protected override TaikoPiece CreateMainPiece() => new TickPiece
|
||||
{
|
||||
Filled = HitObject.FirstTick
|
||||
};
|
||||
|
||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||
{
|
||||
if (!userTriggered)
|
||||
{
|
||||
if (timeOffset > HitObject.HitWindow)
|
||||
ApplyResult(r => r.Type = HitResult.Miss);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Math.Abs(timeOffset) > HitObject.HitWindow)
|
||||
return;
|
||||
|
||||
if (!(Math.Abs(timeOffset) < HitObject.HitWindow))
|
||||
return;
|
||||
|
||||
AddJudgement(new TaikoDrumRollTickJudgement { Result = HitResult.Great });
|
||||
if (HitObject.IsStrong)
|
||||
AddJudgement(new TaikoStrongHitJudgement());
|
||||
ApplyResult(r => r.Type = HitResult.Great);
|
||||
}
|
||||
|
||||
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>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.Taiko.Judgements;
|
||||
using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
@ -15,17 +15,14 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
/// <summary>
|
||||
/// A list of keys which can result in hits for this HitObject.
|
||||
/// </summary>
|
||||
protected abstract TaikoAction[] HitActions { get; }
|
||||
public abstract TaikoAction[] HitActions { get; }
|
||||
|
||||
/// <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>
|
||||
protected bool SecondHitAllowed { get; private set; }
|
||||
public TaikoAction? HitAction { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the last key pressed is a valid hit key.
|
||||
/// </summary>
|
||||
private bool validKeyPressed;
|
||||
private bool validActionPressed;
|
||||
|
||||
protected DrawableHit(Hit hit)
|
||||
: base(hit)
|
||||
@ -33,12 +30,12 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
FillMode = FillMode.Fit;
|
||||
}
|
||||
|
||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||
{
|
||||
if (!userTriggered)
|
||||
{
|
||||
if (!HitObject.HitWindows.CanBeHit(timeOffset))
|
||||
AddJudgement(new TaikoJudgement { Result = HitResult.Miss });
|
||||
ApplyResult(r => r.Type = HitResult.Miss);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -46,26 +43,33 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
if (result == HitResult.None)
|
||||
return;
|
||||
|
||||
if (!validKeyPressed || result == HitResult.Miss)
|
||||
AddJudgement(new TaikoJudgement { Result = HitResult.Miss });
|
||||
if (!validActionPressed)
|
||||
ApplyResult(r => r.Type = HitResult.Miss);
|
||||
else
|
||||
{
|
||||
AddJudgement(new TaikoJudgement
|
||||
{
|
||||
Result = result,
|
||||
Final = !HitObject.IsStrong
|
||||
});
|
||||
|
||||
SecondHitAllowed = true;
|
||||
}
|
||||
ApplyResult(r => r.Type = result);
|
||||
}
|
||||
|
||||
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
|
||||
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()
|
||||
@ -86,8 +90,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
switch (State.Value)
|
||||
{
|
||||
case ArmedState.Idle:
|
||||
SecondHitAllowed = false;
|
||||
validKeyPressed = false;
|
||||
validActionPressed = false;
|
||||
|
||||
UnproxyContent();
|
||||
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
|
||||
{
|
||||
protected override TaikoAction[] HitActions { get; } = { TaikoAction.LeftRim, TaikoAction.RightRim };
|
||||
public override TaikoAction[] HitActions { get; } = { TaikoAction.LeftRim, TaikoAction.RightRim };
|
||||
|
||||
public DrawableRimHit(Hit 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
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
@ -12,23 +14,19 @@ using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Rulesets.Taiko.Judgements;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
{
|
||||
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_thin_border = 1f;
|
||||
private const float target_ring_scale = 5f;
|
||||
private const float inner_ring_alpha = 0.65f;
|
||||
|
||||
private readonly List<DrawableSwellTick> ticks = new List<DrawableSwellTick>();
|
||||
|
||||
private readonly Container bodyContainer;
|
||||
private readonly CircularContainer targetRing;
|
||||
private readonly CircularContainer expandingRing;
|
||||
@ -106,6 +104,15 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
});
|
||||
|
||||
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]
|
||||
@ -124,13 +131,17 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
Width *= Parent.RelativeChildSize.X;
|
||||
}
|
||||
|
||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||
{
|
||||
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
|
||||
.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);
|
||||
|
||||
if (Judgements.Count == HitObject.RequiredHits)
|
||||
AddJudgement(new TaikoJudgement { Result = HitResult.Great });
|
||||
if (numHits == HitObject.RequiredHits)
|
||||
ApplyResult(r => r.Type = HitResult.Great);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (timeOffset < 0)
|
||||
return;
|
||||
|
||||
//TODO: THIS IS SHIT AND CAN'T EXIST POST-TAIKO WORLD CUP
|
||||
AddJudgement(Judgements.Count > HitObject.RequiredHits / 2
|
||||
? new TaikoJudgement { Result = HitResult.Good }
|
||||
: new TaikoJudgement { Result = HitResult.Miss });
|
||||
int numHits = 0;
|
||||
|
||||
foreach (var tick in ticks)
|
||||
{
|
||||
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;
|
||||
lastWasCentre = isCentre;
|
||||
|
||||
UpdateJudgement(true);
|
||||
UpdateResult(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());
|
||||
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
|
||||
@ -109,5 +118,13 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
protected override string SampleNamespace => "Taiko";
|
||||
|
||||
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()
|
||||
{
|
||||
base.CreateNestedHitObjects();
|
||||
|
||||
createTicks();
|
||||
|
||||
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);
|
||||
|
||||
base.CreateNestedHitObjects();
|
||||
}
|
||||
|
||||
private void createTicks()
|
||||
|
@ -1,6 +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
|
||||
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Taiko.Judgements;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Objects
|
||||
{
|
||||
public class DrumRollTick : TaikoHitObject
|
||||
@ -20,5 +23,7 @@ namespace osu.Game.Rulesets.Taiko.Objects
|
||||
/// The time allowed to hit this tick.
|
||||
/// </summary>
|
||||
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();
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
// 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 osu.Game.Rulesets.Objects.Types;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Objects
|
||||
@ -15,5 +16,15 @@ namespace osu.Game.Rulesets.Taiko.Objects
|
||||
/// The number of hits required to complete the swell successfully.
|
||||
/// </summary>
|
||||
public int RequiredHits = 10;
|
||||
|
||||
public override bool IsStrong { set => throw new NotSupportedException($"{nameof(Swell)} cannot be a strong hitobject."); }
|
||||
|
||||
protected override void CreateNestedHitObjects()
|
||||
{
|
||||
base.CreateNestedHitObjects();
|
||||
|
||||
for (int i = 0; i < RequiredHits; i++)
|
||||
AddNested(new SwellTick());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user