1
0
mirror of https://github.com/ppy/osu.git synced 2025-02-13 19:53:23 +08:00

Merge pull request #18764 from sw1tchbl4d3r/classic_drumrolls

Make drum rolls and swells optional in taiko
This commit is contained in:
Dean Herbert 2022-09-07 16:12:56 +09:00 committed by GitHub
commit 5b95fdeb92
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 572 additions and 160 deletions

View File

@ -0,0 +1,96 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Extensions.TypeExtensions;
using osu.Framework.Screens;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Replays;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Replays;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Taiko.Objects;
using osu.Game.Scoring;
using osu.Game.Screens.Play;
using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Taiko.Tests.Judgements
{
public class JudgementTest : RateAdjustedBeatmapTestScene
{
private ScoreAccessibleReplayPlayer currentPlayer = null!;
protected List<JudgementResult> JudgementResults { get; private set; } = null!;
protected void AssertJudgementCount(int count)
{
AddAssert($"{count} judgement{(count > 0 ? "s" : "")}", () => JudgementResults, () => Has.Count.EqualTo(count));
}
protected void AssertResult<T>(int index, HitResult expectedResult)
{
AddAssert($"{typeof(T).ReadableName()} ({index}) judged as {expectedResult}",
() => JudgementResults.Where(j => j.HitObject is T).OrderBy(j => j.HitObject.StartTime).ElementAt(index).Type,
() => Is.EqualTo(expectedResult));
}
protected void PerformTest(List<ReplayFrame> frames, Beatmap<TaikoHitObject>? beatmap = null)
{
AddStep("load player", () =>
{
Beatmap.Value = CreateWorkingBeatmap(beatmap);
var p = new ScoreAccessibleReplayPlayer(new Score { Replay = new Replay { Frames = frames } });
p.OnLoadComplete += _ =>
{
p.ScoreProcessor.NewJudgement += result =>
{
if (currentPlayer == p) JudgementResults.Add(result);
};
};
LoadScreen(currentPlayer = p);
JudgementResults = new List<JudgementResult>();
});
AddUntilStep("Beatmap at 0", () => Beatmap.Value.Track.CurrentTime == 0);
AddUntilStep("Wait until player is loaded", () => currentPlayer.IsCurrentScreen());
AddUntilStep("Wait for completion", () => currentPlayer.ScoreProcessor.HasCompleted.Value);
}
protected Beatmap<TaikoHitObject> CreateBeatmap(params TaikoHitObject[] hitObjects)
{
var beatmap = new Beatmap<TaikoHitObject>
{
HitObjects = hitObjects.ToList(),
BeatmapInfo =
{
Difficulty = new BeatmapDifficulty { SliderTickRate = 4 },
Ruleset = new TaikoRuleset().RulesetInfo
},
};
beatmap.ControlPointInfo.Add(0, new EffectControlPoint { ScrollSpeed = 0.1f });
return beatmap;
}
private class ScoreAccessibleReplayPlayer : ReplayPlayer
{
public new ScoreProcessor ScoreProcessor => base.ScoreProcessor;
protected override bool PauseOnFocusLost => false;
public ScoreAccessibleReplayPlayer(Score score)
: base(score, new PlayerConfiguration
{
AllowPause = false,
ShowResults = false,
})
{
}
}
}
}

View File

@ -0,0 +1,201 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using NUnit.Framework;
using osu.Game.Rulesets.Replays;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Taiko.Objects;
using osu.Game.Rulesets.Taiko.Replays;
namespace osu.Game.Rulesets.Taiko.Tests.Judgements
{
public class TestSceneDrumRollJudgements : JudgementTest
{
[Test]
public void TestHitAllDrumRoll()
{
const double hit_time = 1000;
PerformTest(new List<ReplayFrame>
{
new TaikoReplayFrame(0),
new TaikoReplayFrame(1000, TaikoAction.LeftCentre),
new TaikoReplayFrame(1001),
new TaikoReplayFrame(2000, TaikoAction.LeftCentre),
new TaikoReplayFrame(2001),
}, CreateBeatmap(new DrumRoll
{
StartTime = hit_time,
Duration = 1000
}));
AssertJudgementCount(3);
AssertResult<DrumRollTick>(0, HitResult.SmallBonus);
AssertResult<DrumRollTick>(1, HitResult.SmallBonus);
AssertResult<DrumRoll>(0, HitResult.IgnoreHit);
}
[Test]
public void TestHitSomeDrumRoll()
{
const double hit_time = 1000;
PerformTest(new List<ReplayFrame>
{
new TaikoReplayFrame(0),
new TaikoReplayFrame(2000, TaikoAction.LeftCentre),
new TaikoReplayFrame(2001),
}, CreateBeatmap(new DrumRoll
{
StartTime = hit_time,
Duration = 1000
}));
AssertJudgementCount(3);
AssertResult<DrumRollTick>(0, HitResult.IgnoreMiss);
AssertResult<DrumRollTick>(1, HitResult.SmallBonus);
AssertResult<DrumRoll>(0, HitResult.IgnoreHit);
}
[Test]
public void TestHitNoneDrumRoll()
{
const double hit_time = 1000;
PerformTest(new List<ReplayFrame>
{
new TaikoReplayFrame(0),
}, CreateBeatmap(new DrumRoll
{
StartTime = hit_time,
Duration = 1000
}));
AssertJudgementCount(3);
AssertResult<DrumRollTick>(0, HitResult.IgnoreMiss);
AssertResult<DrumRollTick>(1, HitResult.IgnoreMiss);
AssertResult<DrumRoll>(0, HitResult.IgnoreHit);
}
[Test]
public void TestHitAllStrongDrumRollWithOneKey()
{
const double hit_time = 1000;
PerformTest(new List<ReplayFrame>
{
new TaikoReplayFrame(0),
new TaikoReplayFrame(1000, TaikoAction.LeftCentre),
new TaikoReplayFrame(1001),
new TaikoReplayFrame(2000, TaikoAction.LeftCentre),
new TaikoReplayFrame(2001),
}, CreateBeatmap(new DrumRoll
{
StartTime = hit_time,
Duration = 1000,
IsStrong = true
}));
AssertJudgementCount(6);
AssertResult<DrumRollTick>(0, HitResult.SmallBonus);
AssertResult<StrongNestedHitObject>(0, HitResult.LargeBonus);
AssertResult<DrumRollTick>(1, HitResult.SmallBonus);
AssertResult<StrongNestedHitObject>(1, HitResult.LargeBonus);
AssertResult<DrumRoll>(0, HitResult.IgnoreHit);
AssertResult<StrongNestedHitObject>(2, HitResult.IgnoreHit);
}
[Test]
public void TestHitSomeStrongDrumRollWithOneKey()
{
const double hit_time = 1000;
PerformTest(new List<ReplayFrame>
{
new TaikoReplayFrame(0),
new TaikoReplayFrame(2000, TaikoAction.LeftCentre),
new TaikoReplayFrame(2001),
}, CreateBeatmap(new DrumRoll
{
StartTime = hit_time,
Duration = 1000,
IsStrong = true
}));
AssertJudgementCount(6);
AssertResult<DrumRollTick>(0, HitResult.IgnoreMiss);
AssertResult<StrongNestedHitObject>(0, HitResult.IgnoreMiss);
AssertResult<DrumRollTick>(1, HitResult.SmallBonus);
AssertResult<StrongNestedHitObject>(1, HitResult.LargeBonus);
AssertResult<DrumRoll>(0, HitResult.IgnoreHit);
AssertResult<StrongNestedHitObject>(2, HitResult.IgnoreHit);
}
[Test]
public void TestHitAllStrongDrumRollWithBothKeys()
{
const double hit_time = 1000;
PerformTest(new List<ReplayFrame>
{
new TaikoReplayFrame(0),
new TaikoReplayFrame(1000, TaikoAction.LeftCentre, TaikoAction.RightCentre),
new TaikoReplayFrame(1001),
new TaikoReplayFrame(2000, TaikoAction.LeftCentre, TaikoAction.RightCentre),
new TaikoReplayFrame(2001),
}, CreateBeatmap(new DrumRoll
{
StartTime = hit_time,
Duration = 1000,
IsStrong = true
}));
AssertJudgementCount(6);
AssertResult<DrumRollTick>(0, HitResult.SmallBonus);
AssertResult<StrongNestedHitObject>(0, HitResult.LargeBonus);
AssertResult<DrumRollTick>(1, HitResult.SmallBonus);
AssertResult<StrongNestedHitObject>(1, HitResult.LargeBonus);
AssertResult<DrumRoll>(0, HitResult.IgnoreHit);
AssertResult<StrongNestedHitObject>(2, HitResult.IgnoreHit);
}
[Test]
public void TestHitSomeStrongDrumRollWithBothKeys()
{
const double hit_time = 1000;
PerformTest(new List<ReplayFrame>
{
new TaikoReplayFrame(0),
new TaikoReplayFrame(2000, TaikoAction.LeftCentre, TaikoAction.RightCentre),
new TaikoReplayFrame(2001),
}, CreateBeatmap(new DrumRoll
{
StartTime = hit_time,
Duration = 1000,
IsStrong = true
}));
AssertJudgementCount(6);
AssertResult<DrumRollTick>(0, HitResult.IgnoreMiss);
AssertResult<StrongNestedHitObject>(0, HitResult.IgnoreMiss);
AssertResult<DrumRollTick>(1, HitResult.SmallBonus);
AssertResult<StrongNestedHitObject>(1, HitResult.LargeBonus);
AssertResult<DrumRoll>(0, HitResult.IgnoreHit);
AssertResult<StrongNestedHitObject>(2, HitResult.IgnoreHit);
}
}
}

View File

@ -0,0 +1,133 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using NUnit.Framework;
using osu.Game.Rulesets.Replays;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Taiko.Objects;
using osu.Game.Rulesets.Taiko.Replays;
namespace osu.Game.Rulesets.Taiko.Tests.Judgements
{
public class TestSceneHitJudgements : JudgementTest
{
[Test]
public void TestHitCentreHit()
{
const double hit_time = 1000;
PerformTest(new List<ReplayFrame>
{
new TaikoReplayFrame(0),
new TaikoReplayFrame(hit_time, TaikoAction.LeftCentre),
}, CreateBeatmap(new Hit
{
Type = HitType.Centre,
StartTime = hit_time
}));
AssertJudgementCount(1);
AssertResult<Hit>(0, HitResult.Great);
}
[Test]
public void TestHitRimHit()
{
const double hit_time = 1000;
PerformTest(new List<ReplayFrame>
{
new TaikoReplayFrame(0),
new TaikoReplayFrame(hit_time, TaikoAction.LeftRim),
}, CreateBeatmap(new Hit
{
Type = HitType.Rim,
StartTime = hit_time
}));
AssertJudgementCount(1);
AssertResult<Hit>(0, HitResult.Great);
}
[Test]
public void TestMissHit()
{
const double hit_time = 1000;
PerformTest(new List<ReplayFrame>
{
new TaikoReplayFrame(0)
}, CreateBeatmap(new Hit
{
Type = HitType.Centre,
StartTime = hit_time
}));
AssertJudgementCount(1);
AssertResult<Hit>(0, HitResult.Miss);
}
[Test]
public void TestHitStrongHitWithOneKey()
{
const double hit_time = 1000;
PerformTest(new List<ReplayFrame>
{
new TaikoReplayFrame(0),
new TaikoReplayFrame(hit_time, TaikoAction.LeftCentre),
}, CreateBeatmap(new Hit
{
Type = HitType.Centre,
StartTime = hit_time,
IsStrong = true
}));
AssertJudgementCount(2);
AssertResult<Hit>(0, HitResult.Great);
AssertResult<StrongNestedHitObject>(0, HitResult.IgnoreMiss);
}
[Test]
public void TestHitStrongHitWithBothKeys()
{
const double hit_time = 1000;
PerformTest(new List<ReplayFrame>
{
new TaikoReplayFrame(0),
new TaikoReplayFrame(hit_time, TaikoAction.LeftCentre, TaikoAction.RightCentre),
}, CreateBeatmap(new Hit
{
Type = HitType.Centre,
StartTime = hit_time,
IsStrong = true
}));
AssertJudgementCount(2);
AssertResult<Hit>(0, HitResult.Great);
AssertResult<StrongNestedHitObject>(0, HitResult.LargeBonus);
}
[Test]
public void TestMissStrongHit()
{
const double hit_time = 1000;
PerformTest(new List<ReplayFrame>
{
new TaikoReplayFrame(0),
}, CreateBeatmap(new Hit
{
Type = HitType.Centre,
StartTime = hit_time,
IsStrong = true
}));
AssertJudgementCount(2);
AssertResult<Hit>(0, HitResult.Miss);
AssertResult<StrongNestedHitObject>(0, HitResult.IgnoreMiss);
}
}
}

View File

@ -0,0 +1,118 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using osu.Game.Rulesets.Replays;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Taiko.Objects;
using osu.Game.Rulesets.Taiko.Replays;
namespace osu.Game.Rulesets.Taiko.Tests.Judgements
{
public class TestSceneSwellJudgements : JudgementTest
{
[Test]
public void TestHitAllSwell()
{
const double hit_time = 1000;
Swell swell = new Swell
{
StartTime = hit_time,
Duration = 1000,
RequiredHits = 10
};
List<ReplayFrame> frames = new List<ReplayFrame>
{
new TaikoReplayFrame(0),
new TaikoReplayFrame(2001),
};
for (int i = 0; i < swell.RequiredHits; i++)
{
double frameTime = 1000 + i * 50;
frames.Add(new TaikoReplayFrame(frameTime, i % 2 == 0 ? TaikoAction.LeftCentre : TaikoAction.LeftRim));
frames.Add(new TaikoReplayFrame(frameTime + 10));
}
PerformTest(frames, CreateBeatmap(swell));
AssertJudgementCount(11);
for (int i = 0; i < swell.RequiredHits; i++)
AssertResult<SwellTick>(i, HitResult.IgnoreHit);
AssertResult<Swell>(0, HitResult.LargeBonus);
}
[Test]
public void TestHitSomeSwell()
{
const double hit_time = 1000;
Swell swell = new Swell
{
StartTime = hit_time,
Duration = 1000,
RequiredHits = 10
};
List<ReplayFrame> frames = new List<ReplayFrame>
{
new TaikoReplayFrame(0),
new TaikoReplayFrame(2001),
};
for (int i = 0; i < swell.RequiredHits / 2; i++)
{
double frameTime = 1000 + i * 50;
frames.Add(new TaikoReplayFrame(frameTime, i % 2 == 0 ? TaikoAction.LeftCentre : TaikoAction.LeftRim));
frames.Add(new TaikoReplayFrame(frameTime + 10));
}
PerformTest(frames, CreateBeatmap(swell));
AssertJudgementCount(11);
for (int i = 0; i < swell.RequiredHits / 2; i++)
AssertResult<SwellTick>(i, HitResult.IgnoreHit);
for (int i = swell.RequiredHits / 2; i < swell.RequiredHits; i++)
AssertResult<SwellTick>(i, HitResult.IgnoreMiss);
AssertResult<Swell>(0, HitResult.IgnoreMiss);
}
[Test]
public void TestHitNoneSwell()
{
const double hit_time = 1000;
Swell swell = new Swell
{
StartTime = hit_time,
Duration = 1000,
RequiredHits = 10
};
List<ReplayFrame> frames = new List<ReplayFrame>
{
new TaikoReplayFrame(0),
new TaikoReplayFrame(2001),
};
PerformTest(frames, CreateBeatmap(swell));
AssertJudgementCount(11);
for (int i = 0; i < swell.RequiredHits; i++)
AssertResult<SwellTick>(i, HitResult.IgnoreMiss);
AssertResult<Swell>(0, HitResult.IgnoreMiss);
AddAssert("all tick offsets are 0", () => JudgementResults.Where(r => r.HitObject is SwellTick).All(r => r.TimeOffset == 0));
}
}
}

View File

@ -25,11 +25,11 @@ namespace osu.Game.Rulesets.Taiko.Tests.Mods
[TestCase(false)]
[TestCase(true)]
public void TestDrumRoll(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new DrumRoll { StartTime = 1000, EndTime = 3000 }), shouldMiss);
public void TestDrumRoll(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new DrumRoll { StartTime = 1000, EndTime = 3000 }, false), shouldMiss);
[TestCase(false)]
[TestCase(true)]
public void TestSwell(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new Swell { StartTime = 1000, EndTime = 3000 }), shouldMiss);
public void TestSwell(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new Swell { StartTime = 1000, EndTime = 3000 }, false), shouldMiss);
private class TestTaikoRuleset : TaikoRuleset
{

View File

@ -112,7 +112,6 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
assertStateAfterResult(new JudgementResult(new Hit(), new TaikoJudgement()) { Type = HitResult.Great }, TaikoMascotAnimationState.Idle);
assertStateAfterResult(new JudgementResult(new Hit(), new TaikoJudgement()) { Type = HitResult.Miss }, TaikoMascotAnimationState.Fail);
assertStateAfterResult(new JudgementResult(new DrumRoll(), new TaikoDrumRollJudgement()) { Type = HitResult.Great }, TaikoMascotAnimationState.Idle);
assertStateAfterResult(new JudgementResult(new Hit(), new TaikoJudgement()) { Type = HitResult.Ok }, TaikoMascotAnimationState.Idle);
}

View File

@ -1,38 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System.Linq;
using NUnit.Framework;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Taiko.Objects;
namespace osu.Game.Rulesets.Taiko.Tests
{
public class TestSceneDrumRollJudgements : TestSceneTaikoPlayer
{
[Test]
public void TestStrongDrumRollFullyJudgedOnKilled()
{
AddUntilStep("gameplay finished", () => Player.ScoreProcessor.HasCompleted.Value);
AddAssert("all judgements are misses", () => Player.Results.All(r => r.Type == r.Judgement.MinResult));
}
protected override bool Autoplay => false;
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new Beatmap<TaikoHitObject>
{
BeatmapInfo = { Ruleset = new TaikoRuleset().RulesetInfo },
HitObjects =
{
new DrumRoll
{
StartTime = 1000,
Duration = 1000,
IsStrong = true
}
}
};
}
}

View File

@ -1,42 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System.Linq;
using NUnit.Framework;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Taiko.Objects;
namespace osu.Game.Rulesets.Taiko.Tests
{
public class TestSceneSwellJudgements : TestSceneTaikoPlayer
{
[Test]
public void TestZeroTickTimeOffsets()
{
AddUntilStep("gameplay finished", () => Player.ScoreProcessor.HasCompleted.Value);
AddAssert("all tick offsets are 0", () => Player.Results.Where(r => r.HitObject is SwellTick).All(r => r.TimeOffset == 0));
}
protected override bool Autoplay => true;
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
{
var beatmap = new Beatmap<TaikoHitObject>
{
BeatmapInfo = { Ruleset = new TaikoRuleset().RulesetInfo },
HitObjects =
{
new Swell
{
StartTime = 1000,
Duration = 1000,
}
}
};
return beatmap;
}
}
}

View File

@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
};
[Test]
public void TestSpinnerDoesFail()
public void TestSwellDoesNotFail()
{
bool judged = false;
AddStep("Setup judgements", () =>
@ -47,7 +47,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
Player.ScoreProcessor.NewJudgement += _ => judged = true;
});
AddUntilStep("swell judged", () => judged);
AddAssert("failed", () => Player.GameplayState.HasFailed);
AddAssert("not failed", () => !Player.GameplayState.HasFailed);
}
}
}

View File

@ -1,25 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Taiko.Judgements
{
public class TaikoDrumRollJudgement : TaikoJudgement
{
protected override double HealthIncreaseFor(HitResult result)
{
// Drum rolls can be ignored with no health penalty
switch (result)
{
case HitResult.Miss:
return 0;
default:
return base.HealthIncreaseFor(result);
}
}
}
}

View File

@ -9,18 +9,8 @@ namespace osu.Game.Rulesets.Taiko.Judgements
{
public class TaikoDrumRollTickJudgement : TaikoJudgement
{
public override HitResult MaxResult => HitResult.SmallTickHit;
public override HitResult MaxResult => HitResult.SmallBonus;
protected override double HealthIncreaseFor(HitResult result)
{
switch (result)
{
case HitResult.SmallTickHit:
return 0.15;
default:
return 0;
}
}
protected override double HealthIncreaseFor(HitResult result) => 0;
}
}

View File

@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Taiko.Judgements
{
public class TaikoStrongJudgement : TaikoJudgement
{
public override HitResult MaxResult => HitResult.SmallBonus;
public override HitResult MaxResult => HitResult.LargeBonus;
// MainObject already changes the HP
protected override double HealthIncreaseFor(HitResult result) => 0;

View File

@ -9,11 +9,13 @@ namespace osu.Game.Rulesets.Taiko.Judgements
{
public class TaikoSwellJudgement : TaikoJudgement
{
public override HitResult MaxResult => HitResult.LargeBonus;
protected override double HealthIncreaseFor(HitResult result)
{
switch (result)
{
case HitResult.Miss:
case HitResult.IgnoreMiss:
return -0.65;
default:

View File

@ -4,7 +4,6 @@
#nullable disable
using System;
using System.Linq;
using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Utils;
@ -17,7 +16,6 @@ using osu.Framework.Graphics.Primitives;
using osu.Framework.Input.Events;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Taiko.Skinning.Default;
using osu.Game.Skinning;
using osuTK;
@ -43,6 +41,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
private Color4 colourIdle;
private Color4 colourEngaged;
public override bool DisplayResult => false;
public DrawableDrumRoll()
: this(null)
{
@ -143,14 +143,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
if (timeOffset < 0)
return;
int countHit = NestedHitObjects.Count(o => o.IsHit);
if (countHit >= HitObject.RequiredGoodHits)
{
ApplyResult(r => r.Type = countHit >= HitObject.RequiredGreatHits ? HitResult.Great : HitResult.Ok);
}
else
ApplyResult(r => r.Type = r.Judgement.MinResult);
ApplyResult(r => r.Type = r.Judgement.MaxResult);
}
protected override void UpdateHitStateTransforms(ArmedState state)

View File

@ -16,7 +16,6 @@ using osuTK.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Events;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Taiko.Skinning.Default;
using osu.Game.Skinning;
@ -39,6 +38,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
private readonly CircularContainer targetRing;
private readonly CircularContainer expandingRing;
public override bool DisplayResult => false;
public DrawableSwell()
: this(null)
{
@ -201,7 +202,7 @@ 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 (numHits == HitObject.RequiredHits)
ApplyResult(r => r.Type = HitResult.Great);
ApplyResult(r => r.Type = r.Judgement.MaxResult);
}
else
{
@ -222,7 +223,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
tick.TriggerResult(false);
}
ApplyResult(r => r.Type = numHits > HitObject.RequiredHits / 2 ? HitResult.Ok : r.Judgement.MinResult);
ApplyResult(r => r.Type = numHits == HitObject.RequiredHits ? r.Judgement.MaxResult : r.Judgement.MinResult);
}
}

View File

@ -4,7 +4,6 @@
#nullable disable
using osu.Game.Rulesets.Objects.Types;
using System;
using System.Threading;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
@ -12,7 +11,6 @@ using osu.Game.Beatmaps.Formats;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Taiko.Judgements;
using osuTK;
namespace osu.Game.Rulesets.Taiko.Objects
@ -42,24 +40,12 @@ namespace osu.Game.Rulesets.Taiko.Objects
/// </summary>
public int TickRate = 1;
/// <summary>
/// Number of drum roll ticks required for a "Good" hit.
/// </summary>
public double RequiredGoodHits { get; protected set; }
/// <summary>
/// Number of drum roll ticks required for a "Great" hit.
/// </summary>
public double RequiredGreatHits { get; protected set; }
/// <summary>
/// The length (in milliseconds) between ticks of this drumroll.
/// <para>Half of this value is the hit window of the ticks.</para>
/// </summary>
private double tickSpacing = 100;
private float overallDifficulty = BeatmapDifficulty.DEFAULT_DIFFICULTY;
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, IBeatmapDifficultyInfo difficulty)
{
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
@ -70,16 +56,12 @@ namespace osu.Game.Rulesets.Taiko.Objects
Velocity = scoringDistance / timingPoint.BeatLength;
tickSpacing = timingPoint.BeatLength / TickRate;
overallDifficulty = difficulty.OverallDifficulty;
}
protected override void CreateNestedHitObjects(CancellationToken cancellationToken)
{
createTicks(cancellationToken);
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(cancellationToken);
}
@ -106,7 +88,7 @@ namespace osu.Game.Rulesets.Taiko.Objects
}
}
public override Judgement CreateJudgement() => new TaikoDrumRollJudgement();
public override Judgement CreateJudgement() => new IgnoreJudgement();
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
@ -114,6 +96,8 @@ namespace osu.Game.Rulesets.Taiko.Objects
public class StrongNestedHit : StrongNestedHitObject
{
// The strong hit of the drum roll doesn't actually provide any score.
public override Judgement CreateJudgement() => new IgnoreJudgement();
}
#region LegacyBeatmapEncoder

View File

@ -199,11 +199,8 @@ namespace osu.Game.Rulesets.Taiko
{
switch (result)
{
case HitResult.SmallTickHit:
return "drum tick";
case HitResult.SmallBonus:
return "strong bonus";
return "bonus";
}
return base.GetDisplayNameForHitResult(result);

View File

@ -317,6 +317,9 @@ namespace osu.Game.Rulesets.Taiko.UI
break;
default:
if (!result.Type.IsScorable())
break;
judgementContainer.Add(judgementPools[result.Type].Get(j =>
{
j.Apply(result, judgedObject);