diff --git a/Sunrise.Server.Tests/Services/ScoreService/ScoreServiceSubmitScoreTests.cs b/Sunrise.Server.Tests/Services/ScoreService/ScoreServiceSubmitScoreTests.cs index 8f95d01a..b875f157 100644 --- a/Sunrise.Server.Tests/Services/ScoreService/ScoreServiceSubmitScoreTests.cs +++ b/Sunrise.Server.Tests/Services/ScoreService/ScoreServiceSubmitScoreTests.cs @@ -1756,4 +1756,58 @@ public async Task TestUserRankingWhenBothUsersHaveSamePpAndUserBSubmitsHigherPpM Assert.Equal(1, userStatsAFinal!.BestGlobalRank); Assert.Equal(1, userStatsBFinal!.BestGlobalRank); } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public async Task TestMedalNotAwardedWithDifficultyReducingMods(bool hasNonEligibleMod) + { + // Arrange + var scoreService = Scope.ServiceProvider.GetRequiredService(); + + var (session, user) = await CreateTestSession(); + + var (replay, beatmapId) = GetValidTestReplay(); + + var score = replay.GetScore(); + score.BeatmapId = beatmapId; + score.GameMode = GameMode.Standard; + score.Mods = hasNonEligibleMod ? Mods.HalfTime : Mods.None; + + score.EnrichWithSessionData(session); + + var beatmapSet = _mocker.Beatmap.GetRandomBeatmapSet(); + var beatmap = beatmapSet.Beatmaps.First() ?? throw new Exception("Beatmap is null"); + beatmap.EnrichWithScoreData(score); + beatmap.DifficultyRating = 1.5; + + await _mocker.Beatmap.MockBeatmapSet(beatmapSet); + + // Act + var resultString = await scoreService.SubmitScore( + session, + score.ToScoreString(user.Username), + score.BeatmapHash, + _mocker.GetRandomInteger(), + _mocker.GetRandomInteger(), + _mocker.GetRandomString(), + session.Attributes.UserHash, + _replayService.GenerateReplayFormFile(), + null + ); + + // Assert + Assert.DoesNotContain("error", resultString); + + var userUnlockedMedals = await Database.Users.Medals.GetUserMedals(session.UserId); + + if (hasNonEligibleMod) + { + Assert.DoesNotContain(userUnlockedMedals, m => m.MedalId == 1); + } + else + { + Assert.Contains(userUnlockedMedals, m => m.MedalId == 1); + } + } } \ No newline at end of file diff --git a/Sunrise.Shared/Database/Seeders/MedalSeeder.cs b/Sunrise.Shared/Database/Seeders/MedalSeeder.cs index ce22be53..200e5f5e 100644 --- a/Sunrise.Shared/Database/Seeders/MedalSeeder.cs +++ b/Sunrise.Shared/Database/Seeders/MedalSeeder.cs @@ -1,4 +1,4 @@ -using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; using osu.Shared; using Sunrise.Shared.Database.Models; using Sunrise.Shared.Database.Models.Users; @@ -98,7 +98,8 @@ private static string FormatModIntroductionCondition(Mods mode) private static string FormatDifficultyRatingPassCondition(int difficultyRating) { - return $"{nameof(MedalConditionContext.beatmap)}.{nameof(Beatmap.DifficultyRating)} >= {difficultyRating} && {nameof(MedalConditionContext.beatmap)}.{nameof(Beatmap.DifficultyRating)} < {difficultyRating + 1}"; + var noReducingMods = (int)(Mods.Easy | Mods.NoFail | Mods.HalfTime); + return $"{nameof(MedalConditionContext.beatmap)}.{nameof(Beatmap.DifficultyRating)} >= {difficultyRating} && {nameof(MedalConditionContext.beatmap)}.{nameof(Beatmap.DifficultyRating)} < {difficultyRating + 1} && ({nameof(MedalConditionContext.score)}.{nameof(Score.Mods)} & {noReducingMods}) == 0"; } private static string FormatDifficultyRatingFullComboCondition(int difficultyRating)