Skip to content

Commit 3217075

Browse files
authored
Merge pull request #33982 from bdach/mania-hit-windows
Support mania-specific hit window quirks
2 parents 65cc89a + 9562e83 commit 3217075

File tree

22 files changed

+263
-67
lines changed

22 files changed

+263
-67
lines changed

osu.Game.Rulesets.Catch/Mods/CatchModEasy.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,20 @@
22
// See the LICENCE file in the repository root for full licence text.
33

44
using osu.Framework.Localisation;
5+
using osu.Game.Beatmaps;
56
using osu.Game.Rulesets.Mods;
67

78
namespace osu.Game.Rulesets.Catch.Mods
89
{
910
public class CatchModEasy : ModEasyWithExtraLives
1011
{
1112
public override LocalisableString Description => @"Larger fruits, more forgiving HP drain, less accuracy required, and extra lives!";
13+
14+
public override void ApplyToDifficulty(BeatmapDifficulty difficulty)
15+
{
16+
base.ApplyToDifficulty(difficulty);
17+
18+
difficulty.OverallDifficulty *= ADJUST_RATIO;
19+
}
1220
}
1321
}

osu.Game.Rulesets.Catch/Mods/CatchModHardRock.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public override void ApplyToDifficulty(BeatmapDifficulty difficulty)
2222
{
2323
base.ApplyToDifficulty(difficulty);
2424

25+
difficulty.OverallDifficulty = Math.Min(difficulty.OverallDifficulty * ADJUST_RATIO, 10.0f);
2526
difficulty.CircleSize = Math.Min(difficulty.CircleSize * 1.3f, 10.0f); // CS uses a custom 1.3 ratio.
2627
difficulty.ApproachRate = Math.Min(difficulty.ApproachRate * ADJUST_RATIO, 10.0f);
2728
}

osu.Game.Rulesets.Mania.Tests/ManiaLegacyModConversionTest.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
using NUnit.Framework;
66
using osu.Game.Beatmaps.Legacy;
77
using osu.Game.Rulesets.Mania.Mods;
8-
using osu.Game.Rulesets.Mods;
98
using osu.Game.Tests.Beatmaps;
109

1110
namespace osu.Game.Rulesets.Mania.Tests
@@ -38,7 +37,7 @@ public class ManiaLegacyModConversionTest : LegacyModConversionTest
3837
new object[] { LegacyMods.Key2, new[] { typeof(ManiaModKey2) } },
3938
new object[] { LegacyMods.Mirror, new[] { typeof(ManiaModMirror) } },
4039
new object[] { LegacyMods.HardRock | LegacyMods.DoubleTime, new[] { typeof(ManiaModHardRock), typeof(ManiaModDoubleTime) } },
41-
new object[] { LegacyMods.ScoreV2, new[] { typeof(ModScoreV2) } },
40+
new object[] { LegacyMods.ScoreV2, new[] { typeof(ManiaModScoreV2) } },
4241
};
4342

4443
[TestCaseSource(nameof(mania_mod_mapping))]

osu.Game.Rulesets.Mania.Tests/TestSceneLegacyReplayPlayback.cs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
using osu.Game.Rulesets.Mania.Mods;
1010
using osu.Game.Rulesets.Mania.Objects;
1111
using osu.Game.Rulesets.Mania.Replays;
12-
using osu.Game.Rulesets.Mods;
1312
using osu.Game.Rulesets.Objects;
1413
using osu.Game.Rulesets.Objects.Types;
1514
using osu.Game.Rulesets.Scoring;
@@ -521,14 +520,13 @@ public void TestHitWindowTreatmentWithScoreV2(float overallDifficulty, double hi
521520
ScoreInfo = new ScoreInfo
522521
{
523522
Ruleset = CreateRuleset().RulesetInfo,
524-
Mods = [new ModScoreV2()]
523+
Mods = [new ManiaModScoreV2()]
525524
}
526525
};
527526

528527
RunTest($@"SV2 single note @ OD{overallDifficulty}", beatmap, $@"SV2 {hitOffset}ms @ OD{overallDifficulty} = {expectedResult}", score, [expectedResult]);
529528
}
530529

531-
[Ignore("Tests expected to fail until stable's detailed treatment of hit windows in mania is reproduced.")]
532530
[TestCaseSource(nameof(score_v1_non_convert_test_cases))]
533531
public void TestHitWindowTreatmentWithScoreV1NonConvert(float overallDifficulty, double hitOffset, HitResult expectedResult)
534532
{
@@ -556,7 +554,6 @@ public void TestHitWindowTreatmentWithScoreV1NonConvert(float overallDifficulty,
556554
RunTest($@"SV1 single note @ OD{overallDifficulty}", beatmap, $@"SV1 {hitOffset}ms @ OD{overallDifficulty} = {expectedResult}", score, [expectedResult]);
557555
}
558556

559-
[Ignore("Tests expected to fail until stable's detailed treatment of hit windows in mania is reproduced.")]
560557
[TestCaseSource(nameof(score_v1_convert_test_cases))]
561558
public void TestHitWindowTreatmentWithScoreV1Convert(float overallDifficulty, double hitOffset, HitResult expectedResult)
562559
{
@@ -585,7 +582,6 @@ public void TestHitWindowTreatmentWithScoreV1Convert(float overallDifficulty, do
585582
RunTest($@"SV1 convert single note @ OD{overallDifficulty}", beatmap, $@"SV1 convert {hitOffset}ms @ OD{overallDifficulty} = {expectedResult}", score, [expectedResult]);
586583
}
587584

588-
[Ignore("Tests expected to fail until stable's detailed treatment of hit windows in mania is reproduced.")]
589585
[TestCaseSource(nameof(score_v1_non_convert_hard_rock_test_cases))]
590586
public void TestHitWindowTreatmentWithScoreV1AndHardRockNonConvert(float overallDifficulty, double hitOffset, HitResult expectedResult)
591587
{
@@ -614,7 +610,6 @@ public void TestHitWindowTreatmentWithScoreV1AndHardRockNonConvert(float overall
614610
RunTest($@"SV1+HR single note @ OD{overallDifficulty}", beatmap, $@"SV1+HR {hitOffset}ms @ OD{overallDifficulty} = {expectedResult}", score, [expectedResult]);
615611
}
616612

617-
[Ignore("Tests expected to fail until stable's detailed treatment of hit windows in mania is reproduced.")]
618613
[TestCaseSource(nameof(score_v1_non_convert_easy_test_cases))]
619614
public void TestHitWindowTreatmentWithScoreV1AndEasyNonConvert(float overallDifficulty, double hitOffset, HitResult expectedResult)
620615
{
@@ -643,7 +638,6 @@ public void TestHitWindowTreatmentWithScoreV1AndEasyNonConvert(float overallDiff
643638
RunTest($@"SV1+EZ single note @ OD{overallDifficulty}", beatmap, $@"SV1+EZ {hitOffset}ms @ OD{overallDifficulty} = {expectedResult}", score, [expectedResult]);
644639
}
645640

646-
[Ignore("Tests expected to fail until stable's detailed treatment of hit windows in mania is reproduced.")]
647641
[TestCaseSource(nameof(score_v1_non_convert_double_time_test_cases))]
648642
public void TestHitWindowTreatmentWithScoreV1AndDoubleTimeNonConvert(float overallDifficulty, double hitOffset, HitResult expectedResult)
649643
{
@@ -672,7 +666,6 @@ public void TestHitWindowTreatmentWithScoreV1AndDoubleTimeNonConvert(float overa
672666
RunTest($@"SV1+DT single note @ OD{overallDifficulty}", beatmap, $@"SV1+DT {hitOffset}ms @ OD{overallDifficulty} = {expectedResult}", score, [expectedResult]);
673667
}
674668

675-
[Ignore("Tests expected to fail until stable's detailed treatment of hit windows in mania is reproduced.")]
676669
[TestCaseSource(nameof(score_v1_non_convert_half_time_test_cases))]
677670
public void TestHitWindowTreatmentWithScoreV1AndHalfTimeNonConvert(float overallDifficulty, double hitOffset, HitResult expectedResult)
678671
{

osu.Game.Rulesets.Mania/ManiaRuleset.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ public override IEnumerable<Mod> ConvertFromLegacyMods(LegacyMods mods)
161161
yield return new ManiaModMirror();
162162

163163
if (mods.HasFlag(LegacyMods.ScoreV2))
164-
yield return new ModScoreV2();
164+
yield return new ManiaModScoreV2();
165165
}
166166

167167
public override LegacyMods ConvertToLegacyMods(Mod[] mods)
@@ -296,7 +296,7 @@ public override IEnumerable<Mod> GetModsFor(ModType type)
296296
case ModType.System:
297297
return new Mod[]
298298
{
299-
new ModScoreV2(),
299+
new ManiaModScoreV2(),
300300
};
301301

302302
default:

osu.Game.Rulesets.Mania/Mods/IManiaRateAdjustmentMod.cs

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,10 @@
22
// See the LICENCE file in the repository root for full licence text.
33

44
using osu.Framework.Bindables;
5-
using osu.Game.Beatmaps;
65
using osu.Game.Rulesets.Mania.Objects;
76
using osu.Game.Rulesets.Mania.Scoring;
87
using osu.Game.Rulesets.Mods;
98
using osu.Game.Rulesets.Objects;
10-
using osu.Game.Rulesets.Scoring;
119

1210
namespace osu.Game.Rulesets.Mania.Mods
1311
{
@@ -17,29 +15,21 @@ namespace osu.Game.Rulesets.Mania.Mods
1715
/// <remarks>
1816
/// Historically, in osu!mania, hit windows are expected to adjust relative to the gameplay rate such that the real-world hit window remains the same.
1917
/// </remarks>
20-
public interface IManiaRateAdjustmentMod : IApplicableToDifficulty, IApplicableToHitObject
18+
public interface IManiaRateAdjustmentMod : IApplicableToHitObject
2119
{
2220
BindableNumber<double> SpeedChange { get; }
2321

24-
HitWindows HitWindows { get; set; }
25-
26-
void IApplicableToDifficulty.ApplyToDifficulty(BeatmapDifficulty difficulty)
27-
{
28-
HitWindows = new ManiaHitWindows(SpeedChange.Value);
29-
HitWindows.SetDifficulty(difficulty.OverallDifficulty);
30-
}
31-
3222
void IApplicableToHitObject.ApplyToHitObject(HitObject hitObject)
3323
{
3424
switch (hitObject)
3525
{
3626
case Note:
37-
hitObject.HitWindows = HitWindows;
27+
((ManiaHitWindows)hitObject.HitWindows).SpeedMultiplier = SpeedChange.Value;
3828
break;
3929

4030
case HoldNote hold:
41-
hold.Head.HitWindows = HitWindows;
42-
hold.Tail.HitWindows = HitWindows;
31+
((ManiaHitWindows)hold.Head.HitWindows).SpeedMultiplier = SpeedChange.Value;
32+
((ManiaHitWindows)hold.Tail.HitWindows).SpeedMultiplier = SpeedChange.Value;
4333
break;
4434
}
4535
}
Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,41 @@
11
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
22
// See the LICENCE file in the repository root for full licence text.
33

4+
using osu.Game.Beatmaps;
5+
using osu.Game.Rulesets.Mania.Objects;
6+
using osu.Game.Rulesets.Mania.Scoring;
47
using osu.Game.Rulesets.Mods;
58

69
namespace osu.Game.Rulesets.Mania.Mods
710
{
8-
public class ManiaModClassic : ModClassic
11+
public class ManiaModClassic : ModClassic, IApplicableToBeatmap
912
{
13+
public void ApplyToBeatmap(IBeatmap beatmap)
14+
{
15+
bool isConvert = !beatmap.BeatmapInfo.Ruleset.Equals(new ManiaRuleset().RulesetInfo);
16+
17+
foreach (var ho in beatmap.HitObjects)
18+
{
19+
switch (ho)
20+
{
21+
case Note note:
22+
{
23+
var hitWindows = (ManiaHitWindows)note.HitWindows;
24+
hitWindows.IsConvert = isConvert;
25+
hitWindows.ClassicModActive = true;
26+
break;
27+
}
28+
29+
case HoldNote hold:
30+
{
31+
var headWindows = (ManiaHitWindows)hold.Head.HitWindows;
32+
var tailWindows = (ManiaHitWindows)hold.Tail.HitWindows;
33+
headWindows.IsConvert = tailWindows.IsConvert = isConvert;
34+
headWindows.ClassicModActive = tailWindows.ClassicModActive = true;
35+
break;
36+
}
37+
}
38+
}
39+
}
1040
}
1141
}
Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
22
// See the LICENCE file in the repository root for full licence text.
33

4-
using osu.Game.Rulesets.Mania.Scoring;
54
using osu.Game.Rulesets.Mods;
6-
using osu.Game.Rulesets.Scoring;
75

86
namespace osu.Game.Rulesets.Mania.Mods
97
{
108
public class ManiaModDaycore : ModDaycore, IManiaRateAdjustmentMod
119
{
12-
public HitWindows HitWindows { get; set; } = new ManiaHitWindows();
1310
}
1411
}

osu.Game.Rulesets.Mania/Mods/ManiaModDoubleTime.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
11
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
22
// See the LICENCE file in the repository root for full licence text.
33

4-
using osu.Game.Rulesets.Mania.Scoring;
54
using osu.Game.Rulesets.Mods;
6-
using osu.Game.Rulesets.Scoring;
75

86
namespace osu.Game.Rulesets.Mania.Mods
97
{
108
public class ManiaModDoubleTime : ModDoubleTime, IManiaRateAdjustmentMod
119
{
12-
public HitWindows HitWindows { get; set; } = new ManiaHitWindows();
13-
1410
// For now, all rate-increasing mods should be given a 1x multiplier in mania because it doesn't always
1511
// make the map harder and is more of a personal preference.
1612
// In the future, we can consider adjusting this by experimenting with not applying the hitwindow leniency.

osu.Game.Rulesets.Mania/Mods/ManiaModEasy.cs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,32 @@
22
// See the LICENCE file in the repository root for full licence text.
33

44
using osu.Framework.Localisation;
5+
using osu.Game.Rulesets.Mania.Objects;
6+
using osu.Game.Rulesets.Mania.Scoring;
57
using osu.Game.Rulesets.Mods;
8+
using osu.Game.Rulesets.Objects;
69

710
namespace osu.Game.Rulesets.Mania.Mods
811
{
9-
public class ManiaModEasy : ModEasyWithExtraLives
12+
public class ManiaModEasy : ModEasyWithExtraLives, IApplicableToHitObject
1013
{
1114
public override LocalisableString Description => @"More forgiving HP drain, less accuracy required, and extra lives!";
15+
16+
void IApplicableToHitObject.ApplyToHitObject(HitObject hitObject)
17+
{
18+
const double multiplier = 1 / 1.4;
19+
20+
switch (hitObject)
21+
{
22+
case Note:
23+
((ManiaHitWindows)hitObject.HitWindows).DifficultyMultiplier = multiplier;
24+
break;
25+
26+
case HoldNote hold:
27+
((ManiaHitWindows)hold.Head.HitWindows).DifficultyMultiplier = multiplier;
28+
((ManiaHitWindows)hold.Tail.HitWindows).DifficultyMultiplier = multiplier;
29+
break;
30+
}
31+
}
1232
}
1333
}

0 commit comments

Comments
 (0)