diff --git a/fluXis.Game.Tests/Results/TestNewResults.cs b/fluXis.Game.Tests/Results/TestNewResults.cs deleted file mode 100644 index c00a2141..00000000 --- a/fluXis.Game.Tests/Results/TestNewResults.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System.Collections.Generic; -using fluXis.Game.Graphics.Background; -using fluXis.Game.Map; -using fluXis.Game.Online.API; -using fluXis.Game.Online.API.Requests.Scores; -using fluXis.Game.Screens; -using fluXis.Game.Screens.Result; -using fluXis.Shared.API.Responses.Scores; -using fluXis.Shared.Components.Scores; -using fluXis.Shared.Components.Users; -using fluXis.Shared.Scoring; -using fluXis.Shared.Scoring.Enums; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; - -namespace fluXis.Game.Tests.Results; - -public partial class TestNewResults : FluXisTestScene -{ - [BackgroundDependencyLoader] - private void load(MapStore maps) - { - CreateClock(); - - var backgrounds = new GlobalBackground(); - TestDependencies.Cache(backgrounds); - - var score = new ScoreInfo - { - Accuracy = 98.661736f, - Rank = ScoreRank.S, - PerformanceRating = 8, - Score = 1139289, - MaxCombo = 1218, - Flawless = 898, - Perfect = 290, - Great = 30, - Alright = 0, - Okay = 0, - Miss = 0, - Mods = new List { "1.5x" } - }; - - var stack = new FluXisScreenStack(); - - AddRange(new Drawable[] - { - backgrounds, - new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Top = 60 }, - Child = stack - } - }); - - var set = maps.GetFromGuid("9896365c-5541-4612-9f39-5a44aa1012ed"); - var map = set?.Maps[0] ?? maps.MapSets[0].Maps[0]; - - var screen = new SoloResults(map, score, APIUser.Dummy); - screen.SubmitRequest = new SimulatedScoreRequest(score); - stack.Push(screen); - } - - private class SimulatedScoreRequest : ScoreSubmitRequest - { - public SimulatedScoreRequest(ScoreInfo score) - : base(score) - { - Response = new APIResponse(200, "", new ScoreSubmissionStats(new APIScore { PerformanceRating = 7 }, 10, 10, 1, 12, 10, 2)); - } - } -} diff --git a/fluXis.Game.Tests/Results/TestResultsRating.cs b/fluXis.Game.Tests/Results/TestResultsRating.cs deleted file mode 100644 index 929d9ab6..00000000 --- a/fluXis.Game.Tests/Results/TestResultsRating.cs +++ /dev/null @@ -1,22 +0,0 @@ -using fluXis.Game.Online.API; -using fluXis.Game.Screens.Result.UI; -using fluXis.Shared.API.Responses.Scores; -using fluXis.Shared.Components.Scores; -using osu.Framework.Allocation; - -namespace fluXis.Game.Tests.Results; - -public partial class TestResultsRating : FluXisTestScene -{ - [BackgroundDependencyLoader] - private void load() - { - var ratingInfo = new ResultsRatingInfo(true); - Child = ratingInfo; - - AddStep("Unchanged", () => ratingInfo.ScoreResponse = new APIResponse(200, "", new ScoreSubmissionStats(new APIScore(), 10, 10, 1, 10, 10, 1))); - AddStep("Higher", () => ratingInfo.ScoreResponse = new APIResponse(200, "", new ScoreSubmissionStats(new APIScore(), 10, 10, 2, 20, 20, 1))); - AddStep("Lower", () => ratingInfo.ScoreResponse = new APIResponse(200, "", new ScoreSubmissionStats(new APIScore(), 10, 10, 1, 5, 5, 2))); - AddStep("Error", () => ratingInfo.ScoreResponse = new APIResponse(500, "Something went wrong.", null)); - } -} diff --git a/fluXis.Game.Tests/Results/TestResultsScreen.cs b/fluXis.Game.Tests/Results/TestResultsScreen.cs deleted file mode 100644 index 1468f5bf..00000000 --- a/fluXis.Game.Tests/Results/TestResultsScreen.cs +++ /dev/null @@ -1,62 +0,0 @@ -using fluXis.Game.Database.Maps; -using fluXis.Game.Map; -using fluXis.Game.Screens.Result; -using fluXis.Shared.Scoring; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Screens; - -namespace fluXis.Game.Tests.Results; - -public partial class TestResultsScreen : FluXisTestScene -{ - [Resolved] - private MapStore mapStore { get; set; } - - public TestResultsScreen() - { - var screenStack = new ScreenStack - { - RelativeSizeAxes = Axes.Both - }; - - Add(screenStack); - - AddStep("Show results screen", () => - { - RealmMap realmMap; - - if (mapStore.MapSets.Count > 0) - realmMap = mapStore.MapSets[0].Maps[0]; - else - { - realmMap = new RealmMap - { - ID = default, - Difficulty = "Difficulty Name", - Metadata = new RealmMapMetadata - { - Title = "Title", - Artist = "Artist", - Mapper = "Mapper" - }, - MapSet = null, - Status = 0, - OnlineID = 0, - Hash = null, - KeyCount = 0, - Rating = 0 - }; - } - - var map = new MapInfo(new MapMetadata - { - Title = realmMap.Metadata.Title, - Artist = realmMap.Metadata.Artist, - Mapper = realmMap.Metadata.Mapper - }); - - screenStack.Push(new ResultsScreen(realmMap, map, new ScoreInfo(), null, false)); - }); - } -} diff --git a/fluXis.Game.Tests/Screens/TestResults.cs b/fluXis.Game.Tests/Screens/TestResults.cs new file mode 100644 index 00000000..d13d50ac --- /dev/null +++ b/fluXis.Game.Tests/Screens/TestResults.cs @@ -0,0 +1,103 @@ +using System.Collections.Generic; +using fluXis.Game.Database.Maps; +using fluXis.Game.Map; +using fluXis.Game.Online.API; +using fluXis.Game.Online.API.Requests.Scores; +using fluXis.Game.Screens; +using fluXis.Game.Screens.Result; +using fluXis.Shared.API.Responses.Scores; +using fluXis.Shared.Components.Scores; +using fluXis.Shared.Components.Users; +using fluXis.Shared.Scoring; +using fluXis.Shared.Scoring.Enums; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Logging; + +namespace fluXis.Game.Tests.Screens; + +public partial class TestResults : FluXisTestScene +{ + [Resolved] + private MapStore maps { get; set; } + + private FluXisScreenStack stack; + + [BackgroundDependencyLoader] + private void load() + { + CreateClock(); + } + + [SetUp] + public void Setup() => Schedule(() => + { + Children = new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Top = 60 }, + Child = stack = new FluXisScreenStack() + } + }; + }); + + private RealmMap getMap() + { + var set = maps.GetFromGuid("9896365c-5541-4612-9f39-5a44aa1012ed"); + return set?.Maps[0] ?? maps.MapSets[0].Maps[0]; + } + + private ScoreInfo getScore() => new() + { + Accuracy = 98.661736f, + Rank = ScoreRank.S, + PerformanceRating = 8, + Score = 1139289, + MaxCombo = 1218, + Flawless = 898, + Perfect = 290, + Great = 30, + Alright = 0, + Okay = 0, + Miss = 0, + Mods = new List { "1.5x" } + }; + + [Test] + public void FromGameplay() + { + AddStep("Push", () => stack.Push(new SoloResults(getMap(), getScore(), APIUser.Dummy) { ForceFromGameplay = true })); + } + + [Test] + public void Normal() + { + AddStep("Push", () => stack.Push(new SoloResults(getMap(), getScore(), APIUser.Dummy))); + } + + [Test] + public void WithRequest() + { + var score = getScore(); + AddStep("Push With Request", () => stack.Push(new SoloResults(getMap(), score, APIUser.Dummy) { SubmitRequest = new SimulatedScoreRequest(score) })); + } + + [Test] + public void WithRestart() + { + AddStep("Push With Restart", () => stack.Push(new SoloResults(getMap(), getScore(), APIUser.Dummy) { OnRestart = () => Logger.Log("Restart pressed.") })); + } + + private class SimulatedScoreRequest : ScoreSubmitRequest + { + public SimulatedScoreRequest(ScoreInfo score) + : base(score) + { + Response = new APIResponse(200, "", new ScoreSubmissionStats(new APIScore { PerformanceRating = 7 }, 10, 10, 1, 12, 10, 2)); + } + } +} diff --git a/fluXis.Game/Graphics/Drawables/DrawableAvatar.cs b/fluXis.Game/Graphics/Drawables/DrawableAvatar.cs index af36ed98..e5b499e2 100644 --- a/fluXis.Game/Graphics/Drawables/DrawableAvatar.cs +++ b/fluXis.Game/Graphics/Drawables/DrawableAvatar.cs @@ -40,7 +40,7 @@ private void load() private void setTexture() { - if (user != null) // the texture from the online store could still be null + if (user is { ID: >= 0 }) // the texture from the online store could still be null Texture = store.GetAvatar(user.ID) ?? textures.Get("Online/default-avatar"); else Texture = textures.Get("Online/default-avatar"); diff --git a/fluXis.Game/Graphics/Drawables/DrawableBanner.cs b/fluXis.Game/Graphics/Drawables/DrawableBanner.cs index 727bab6b..0dd29fe5 100644 --- a/fluXis.Game/Graphics/Drawables/DrawableBanner.cs +++ b/fluXis.Game/Graphics/Drawables/DrawableBanner.cs @@ -36,7 +36,7 @@ private void load() private void setTexture() { - if (user != null) // the texture from the online store could still be null + if (user is { ID: >= 0 }) // the texture from the online store could still be null Texture = store.GetBanner(user.ID) ?? textures.Get("Online/default-banner"); else Texture = textures.Get("Online/default-banner"); diff --git a/fluXis.Game/Graphics/UserInterface/Text/FluXisTextFlow.cs b/fluXis.Game/Graphics/UserInterface/Text/FluXisTextFlow.cs index 4c999043..5f427cfa 100644 --- a/fluXis.Game/Graphics/UserInterface/Text/FluXisTextFlow.cs +++ b/fluXis.Game/Graphics/UserInterface/Text/FluXisTextFlow.cs @@ -1,5 +1,7 @@ using System; using fluXis.Game.Graphics.Sprites; +using osu.Framework.Extensions.IEnumerableExtensions; +using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; @@ -16,6 +18,8 @@ public FluXisTextFlow(Action defaultCreationParameters = null) { } + public ITextPart AddCustom(Drawable drawable) => AddPart(new TextPartManual(drawable.Yield())); + protected override FluXisSpriteText CreateSpriteText() => new() { FontSize = FontSize, diff --git a/fluXis.Game/Graphics/UserInterface/Text/ForcedHeightText.cs b/fluXis.Game/Graphics/UserInterface/Text/ForcedHeightText.cs new file mode 100644 index 00000000..75729623 --- /dev/null +++ b/fluXis.Game/Graphics/UserInterface/Text/ForcedHeightText.cs @@ -0,0 +1,30 @@ +using fluXis.Game.Graphics.Sprites; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Localisation; + +namespace fluXis.Game.Graphics.UserInterface.Text; + +public partial class ForcedHeightText : CompositeDrawable +{ + public LocalisableString Text { get; init; } + public float WebFontSize { set => FontSize = FluXisSpriteText.GetWebFontSize(value); } + public float FontSize { get; set; } = 20; + public bool Shadow { get; init; } = true; + + [BackgroundDependencyLoader] + private void load() + { + AutoSizeAxes = Axes.X; + + InternalChild = new FluXisSpriteText + { + Text = Text, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + FontSize = FontSize, + Shadow = Shadow + }; + } +} diff --git a/fluXis.Game/Overlay/Settings/Sections/ExperimentsSection.cs b/fluXis.Game/Overlay/Settings/Sections/ExperimentsSection.cs index c5d5e002..78cc3bca 100644 --- a/fluXis.Game/Overlay/Settings/Sections/ExperimentsSection.cs +++ b/fluXis.Game/Overlay/Settings/Sections/ExperimentsSection.cs @@ -31,6 +31,7 @@ private void load(ExperimentConfigManager experiments) new SettingsToggle { Label = "Seeking in replays", + Description = "Might make gameplay with a lot of effects more laggy.", Bindable = experiments.GetBindable(ExperimentConfig.Seeking) } }); diff --git a/fluXis.Game/Screens/Gameplay/GameplayScreen.cs b/fluXis.Game/Screens/Gameplay/GameplayScreen.cs index b0b71876..d2028785 100644 --- a/fluXis.Game/Screens/Gameplay/GameplayScreen.cs +++ b/fluXis.Game/Screens/Gameplay/GameplayScreen.cs @@ -45,6 +45,7 @@ using fluXis.Game.Skinning.Default; using fluXis.Game.Storyboards; using fluXis.Game.Storyboards.Drawables; +using fluXis.Shared.Components.Users; using fluXis.Shared.Replays; using fluXis.Shared.Scoring.Enums; using fluXis.Shared.Utils; @@ -80,6 +81,7 @@ public partial class GameplayScreen : FluXisScreen, IKeyBindingHandler true; public virtual bool SubmitScore => true; protected virtual bool UseGlobalOffset => true; + protected virtual APIUser CurrentPlayer => api.User.Value; protected bool CursorVisible { get; set; } @@ -474,7 +476,7 @@ protected virtual void End() Task.Run(() => { - var player = api.User.Value; + var player = CurrentPlayer; var bestScore = scores.GetCurrentTop(RealmMap.ID); diff --git a/fluXis.Game/Screens/Gameplay/Replays/ReplayGameplayScreen.cs b/fluXis.Game/Screens/Gameplay/Replays/ReplayGameplayScreen.cs index 9ecdb534..f256acfc 100644 --- a/fluXis.Game/Screens/Gameplay/Replays/ReplayGameplayScreen.cs +++ b/fluXis.Game/Screens/Gameplay/Replays/ReplayGameplayScreen.cs @@ -9,6 +9,7 @@ using fluXis.Game.Online.Activity; using fluXis.Game.Screens.Gameplay.Input; using fluXis.Game.Utils.Extensions; +using fluXis.Shared.Components.Users; using fluXis.Shared.Replays; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -22,6 +23,7 @@ public partial class ReplayGameplayScreen : GameplayScreen protected override bool InstantlyExitOnPause => true; public override bool SubmitScore => false; protected override bool UseGlobalOffset => !Config.Get(FluXisSetting.DisableOffsetInReplay); + protected override APIUser CurrentPlayer => replay.GetPlayer(users); [Resolved] private UserCache users { get; set; } diff --git a/fluXis.Game/Screens/Result/Center/ResultsCenter.cs b/fluXis.Game/Screens/Result/Center/ResultsCenter.cs new file mode 100644 index 00000000..2ab064cf --- /dev/null +++ b/fluXis.Game/Screens/Result/Center/ResultsCenter.cs @@ -0,0 +1,82 @@ +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osuTK; + +namespace fluXis.Game.Screens.Result.Center; + +public partial class ResultsCenter : CompositeDrawable +{ + public Vector2 ScreenSpaceRankPosition => rankCenter.ScreenSpaceDrawQuad.Centre; + + private Container rankCenter; + + private ResultsCenterScore score; + private Circle line; + private ResultsCenterStats stats; + + [BackgroundDependencyLoader] + private void load() + { + Width = 480; + RelativeSizeAxes = Axes.Y; + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + + InternalChild = new GridContainer + { + RelativeSizeAxes = Axes.Both, + RowDimensions = new Dimension[] + { + new(), + new(GridSizeMode.AutoSize), + new(GridSizeMode.AutoSize), + new(GridSizeMode.AutoSize), + new(GridSizeMode.AutoSize) + }, + Content = new[] + { + new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + Child = rankCenter = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre + } + } + }, + new Drawable[] { score = new ResultsCenterScore() }, + new Drawable[] { Empty() }, // TODO: mods + new Drawable[] + { + line = new Circle + { + RelativeSizeAxes = Axes.X, + Height = 4, + Alpha = .4f, + Margin = new MarginPadding { Vertical = 36 } + } + }, + new Drawable[] { stats = new ResultsCenterStats() } + } + }; + } + + public override void Show() + { + score.MoveToY(50).MoveToY(0, FluXisScreen.MOVE_DURATION, Easing.OutQuint); + line.MoveToY(50).MoveToY(0, FluXisScreen.MOVE_DURATION, Easing.OutQuint); + stats.MoveToY(50).MoveToY(0, FluXisScreen.MOVE_DURATION, Easing.OutQuint); + } + + public override void Hide() + { + score.MoveToY(50, FluXisScreen.MOVE_DURATION, Easing.OutQuint); + line.MoveToY(50, FluXisScreen.MOVE_DURATION, Easing.OutQuint); + stats.MoveToY(50, FluXisScreen.MOVE_DURATION, Easing.OutQuint); + } +} diff --git a/fluXis.Game/Screens/Result/Center/ResultsCenterScore.cs b/fluXis.Game/Screens/Result/Center/ResultsCenterScore.cs new file mode 100644 index 00000000..ff47a8d8 --- /dev/null +++ b/fluXis.Game/Screens/Result/Center/ResultsCenterScore.cs @@ -0,0 +1,64 @@ +using fluXis.Game.Graphics.UserInterface.Text; +using fluXis.Shared.Scoring; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osuTK; + +namespace fluXis.Game.Screens.Result.Center; + +public partial class ResultsCenterScore : CompositeDrawable +{ + [BackgroundDependencyLoader] + private void load(SoloResults results, ScoreInfo score) + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + Margin = new MarginPadding { Top = 36 }; + + var difference = ""; + + if (results.ComparisonScore != null) + difference = $"{score.Score - results.ComparisonScore.Score:+#0;-#0}"; + + InternalChild = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(14), + Children = new Drawable[] + { + new ForcedHeightText + { + Text = "Score", + WebFontSize = 24, + Height = 18, + Shadow = true, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Alpha = .8f + }, + new ForcedHeightText + { + Text = $"{score.Score:000000}", + WebFontSize = 64, + Height = 48, + Shadow = true, + Anchor = Anchor.Centre, + Origin = Anchor.Centre + }, + new ForcedHeightText + { + Text = difference, + WebFontSize = 24, + Height = 18, + Shadow = true, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Alpha = .6f + } + } + }; + } +} diff --git a/fluXis.Game/Screens/Result/Center/ResultsCenterStats.cs b/fluXis.Game/Screens/Result/Center/ResultsCenterStats.cs new file mode 100644 index 00000000..b2b450dc --- /dev/null +++ b/fluXis.Game/Screens/Result/Center/ResultsCenterStats.cs @@ -0,0 +1,89 @@ +using System; +using fluXis.Game.Database.Maps; +using fluXis.Game.Graphics.Sprites; +using fluXis.Game.Graphics.UserInterface.Text; +using fluXis.Game.Utils; +using fluXis.Shared.Scoring; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osuTK; + +namespace fluXis.Game.Screens.Result.Center; + +public partial class ResultsCenterStats : CompositeDrawable +{ + [BackgroundDependencyLoader] + private void load(RealmMap map, ScoreInfo score) + { + RelativeSizeAxes = Axes.X; + Height = 38; + + InternalChild = new GridContainer + { + RelativeSizeAxes = Axes.Both, + Content = new[] + { + new Drawable[] + { + new Statistic("Accuracy", $"{score.Accuracy.ToStringInvariant("00.00")}%"), + new Statistic("Combo", "", flow => + { + flow.AddText($"{score.MaxCombo}x"); + flow.AddText($"/{map.Filters.NoteCount + map.Filters.LongNoteCount * 2}x", text => + { + text.WebFontSize = 14; + text.Alpha = .6f; + }); + }), + new Statistic("Performance", $"{score.PerformanceRating.ToStringInvariant("0.00")}"), + } + } + }; + } + + private partial class Statistic : FillFlowContainer + { + public Statistic(string title, string value, Action create = null) + { + RelativeSizeAxes = Axes.Both; + Direction = FillDirection.Vertical; + Spacing = new Vector2(8); + + create ??= textFlow => textFlow.AddText(value); + + var flow = new FluXisTextFlow + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + WebFontSize = 24, + Shadow = true + }; + + create.Invoke(flow); + + InternalChildren = new Drawable[] + { + new ForcedHeightText + { + Text = title, + WebFontSize = 16, + Height = 12, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Alpha = .8f, + Shadow = true + }, + new Container + { + AutoSizeAxes = Axes.X, + Height = 18, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Child = flow + } + }; + } + } +} diff --git a/fluXis.Game/Screens/Result/Extended/ExtendedResults.cs b/fluXis.Game/Screens/Result/Extended/ExtendedResults.cs deleted file mode 100644 index 99d44e17..00000000 --- a/fluXis.Game/Screens/Result/Extended/ExtendedResults.cs +++ /dev/null @@ -1,85 +0,0 @@ -using fluXis.Game.Graphics.Sprites; -using fluXis.Game.Screens.Result.Extended.Header; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; - -namespace fluXis.Game.Screens.Result.Extended; - -public partial class ExtendedResults : Container -{ - public const float SPACING = 10; - - [BackgroundDependencyLoader] - private void load() - { - RelativeSizeAxes = Axes.Both; - Anchor = Origin = Anchor.Centre; - - InternalChildren = new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding(50) { Bottom = 100 }, - Child = new GridContainer - { - RelativeSizeAxes = Axes.Both, - RowDimensions = new Dimension[] - { - new(GridSizeMode.Absolute, 120), - new(GridSizeMode.Absolute, SPACING), - new() - }, - Content = new[] - { - new Drawable[] - { - new ExtendedResultsHeader() - }, - new[] { Empty() }, - new Drawable[] - { - new GridContainer - { - RelativeSizeAxes = Axes.Both, - ColumnDimensions = new Dimension[] - { - new(GridSizeMode.Absolute, 500), - new(GridSizeMode.Absolute, SPACING), - new() - }, - Content = new[] - { - new[] - { - new ExtendedResultsInfo(), - Empty(), - new Container - { - RelativeSizeAxes = Axes.Both, - Child = new FluXisSpriteText - { - Text = "Graphs here soon...", - Anchor = Anchor.Centre, - Origin = Anchor.Centre - } - } - } - } - } - } - } - } - }, - new FluXisSpriteText - { - Text = "This is still not finished and will show more info soon\u2122.", - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - WebFontSize = 16, - Y = 10 - } - }; - } -} diff --git a/fluXis.Game/Screens/Result/Extended/ExtendedResultsInfo.cs b/fluXis.Game/Screens/Result/Extended/ExtendedResultsInfo.cs deleted file mode 100644 index 531602fe..00000000 --- a/fluXis.Game/Screens/Result/Extended/ExtendedResultsInfo.cs +++ /dev/null @@ -1,96 +0,0 @@ -using fluXis.Game.Graphics; -using fluXis.Game.Graphics.Sprites; -using fluXis.Game.Graphics.UserInterface.Color; -using fluXis.Game.Skinning; -using fluXis.Game.Utils; -using fluXis.Shared.Scoring; -using fluXis.Shared.Scoring.Enums; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osuTK; - -namespace fluXis.Game.Screens.Result.Extended; - -public partial class ExtendedResultsInfo : CompositeDrawable -{ - [Resolved] - private ScoreInfo score { get; set; } - - [BackgroundDependencyLoader] - private void load(SkinManager skinManager) - { - RelativeSizeAxes = Axes.Both; - CornerRadius = 20; - Masking = true; - EdgeEffect = FluXisStyles.ShadowMedium; - - InternalChildren = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = FluXisColors.Background2 - }, - new FillFlowContainer - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding(40), - Spacing = new Vector2(20), - Children = new Drawable[] - { - new Entry("Accuracy", score.Accuracy.ToStringInvariant("0.00") + "%"), - new Entry("Score", score.Score.ToString("N0")), - new Entry("Max Combo", $"{score.MaxCombo}x"), - // new Entry("Performance Rating", "0pr"), - new Entry("Flawless Ratio", getRatio()), - // new Entry("Raw Score", "1000000"), - new Entry("Flawless", $"{score.Flawless}") { Colour = skinManager.SkinJson.GetColorForJudgement(Judgement.Flawless) }, - new Entry("Perfect", $"{score.Perfect}") { Colour = skinManager.SkinJson.GetColorForJudgement(Judgement.Perfect) }, - new Entry("Great", $"{score.Great}") { Colour = skinManager.SkinJson.GetColorForJudgement(Judgement.Great) }, - new Entry("Alright", $"{score.Alright}") { Colour = skinManager.SkinJson.GetColorForJudgement(Judgement.Alright) }, - new Entry("Okay", $"{score.Okay}") { Colour = skinManager.SkinJson.GetColorForJudgement(Judgement.Okay) }, - new Entry("Miss", $"{score.Miss}") { Colour = skinManager.SkinJson.GetColorForJudgement(Judgement.Miss) } - } - } - }; - } - - private string getRatio() - { - return score.Flawless switch - { - 0 => "0", - > 0 when score.Perfect == 0 => "Full Flawless", - _ => $"{(score.Flawless / (float)score.Perfect).ToStringInvariant("0.0")}:1" - }; - } - - private partial class Entry : CompositeDrawable - { - public Entry(string title, string content) - { - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - - InternalChildren = new Drawable[] - { - new FluXisSpriteText - { - Text = title, - WebFontSize = 20, - Anchor = Anchor.TopLeft, - Origin = Anchor.TopLeft - }, - new FluXisSpriteText - { - Text = content, - WebFontSize = 20, - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight - } - }; - } - } -} diff --git a/fluXis.Game/Screens/Result/Extended/Header/ExtendedResultsHeader.cs b/fluXis.Game/Screens/Result/Extended/Header/ExtendedResultsHeader.cs deleted file mode 100644 index 2e43f76b..00000000 --- a/fluXis.Game/Screens/Result/Extended/Header/ExtendedResultsHeader.cs +++ /dev/null @@ -1,32 +0,0 @@ -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; - -namespace fluXis.Game.Screens.Result.Extended.Header; - -public partial class ExtendedResultsHeader : GridContainer -{ - [BackgroundDependencyLoader] - private void load() - { - RelativeSizeAxes = Axes.Both; - Anchor = Origin = Anchor.Centre; - - ColumnDimensions = new Dimension[] - { - new(), - new(GridSizeMode.Absolute, ExtendedResults.SPACING), - new(GridSizeMode.AutoSize) // buttons - }; - - Content = new[] - { - new[] - { - new HeaderMap(), - /*Empty(), - new HeaderButtons()*/ - } - }; - } -} diff --git a/fluXis.Game/Screens/Result/Extended/Header/HeaderButtons.cs b/fluXis.Game/Screens/Result/Extended/Header/HeaderButtons.cs deleted file mode 100644 index fab4ea9b..00000000 --- a/fluXis.Game/Screens/Result/Extended/Header/HeaderButtons.cs +++ /dev/null @@ -1,7 +0,0 @@ -using osu.Framework.Graphics.Containers; - -namespace fluXis.Game.Screens.Result.Extended.Header; - -public partial class HeaderButtons : CompositeDrawable -{ -} diff --git a/fluXis.Game/Screens/Result/Extended/Header/HeaderMap.cs b/fluXis.Game/Screens/Result/Extended/Header/HeaderMap.cs deleted file mode 100644 index 92be4f90..00000000 --- a/fluXis.Game/Screens/Result/Extended/Header/HeaderMap.cs +++ /dev/null @@ -1,157 +0,0 @@ -using fluXis.Game.Database.Maps; -using fluXis.Game.Graphics; -using fluXis.Game.Graphics.Containers; -using fluXis.Game.Graphics.Sprites; -using fluXis.Game.Graphics.UserInterface; -using fluXis.Game.Graphics.UserInterface.Color; -using fluXis.Game.Map.Drawables; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osuTK; - -namespace fluXis.Game.Screens.Result.Extended.Header; - -public partial class HeaderMap : CompositeDrawable -{ - [Resolved] - private RealmMap map { get; set; } - - [BackgroundDependencyLoader] - private void load() - { - RelativeSizeAxes = Axes.Both; - CornerRadius = 20; - Masking = true; - EdgeEffect = FluXisStyles.ShadowMedium; - - InternalChildren = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = FluXisColors.Background2 - }, - new LoadWrapper - { - RelativeSizeAxes = Axes.Both, - LoadContent = () => new MapBackground(map) - { - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre - }, - OnComplete = d => d.FadeInFromZero(400) - }, - new SectionedGradient - { - RelativeSizeAxes = Axes.Both, - Colour = Colour4.Black, - Alpha = .5f - }, - new SectionedGradient - { - RelativeSizeAxes = Axes.Both, - Colour = map.Metadata.Color, - Alpha = .5f - }, - new FillFlowContainer - { - RelativeSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(10), - Children = new Drawable[] - { - new LoadWrapper - { - Size = new Vector2(120), - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - CornerRadius = 20, - Masking = true, - LoadContent = () => new MapCover(map.MapSet) - { - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre - }, - OnComplete = d => d.FadeInFromZero(400) - }, - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Children = new Drawable[] - { - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(5), - Children = new Drawable[] - { - new FluXisSpriteText - { - Text = $"{map.Metadata.Title}", - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - WebFontSize = 24, - Shadow = true - }, - new FluXisSpriteText - { - Text = $"by {map.Metadata.Artist}", - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - WebFontSize = 18, - Alpha = .8f, - Shadow = true - } - } - }, - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(5), - Children = new Drawable[] - { - new DifficultyChip - { - Size = new Vector2(80, 20), - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Rating = map.Filters.NotesPerSecond, - FontSize = FluXisSpriteText.GetWebFontSize(14), - EdgeEffect = FluXisStyles.ShadowSmall - }, - new FluXisSpriteText - { - Text = $"{map.Difficulty}", - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - WebFontSize = 16, - Alpha = .8f, - Shadow = true - }, - new FluXisSpriteText - { - Text = $"mapped by {map.Metadata.Mapper}", - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - WebFontSize = 14, - Alpha = .6f, - Shadow = true - } - } - } - } - } - } - } - }; - } -} diff --git a/fluXis.Game/Screens/Result/Header/ResultsMap.cs b/fluXis.Game/Screens/Result/Header/ResultsMap.cs new file mode 100644 index 00000000..8626da88 --- /dev/null +++ b/fluXis.Game/Screens/Result/Header/ResultsMap.cs @@ -0,0 +1,97 @@ +using fluXis.Game.Database.Maps; +using fluXis.Game.Graphics; +using fluXis.Game.Graphics.Containers; +using fluXis.Game.Graphics.Sprites; +using fluXis.Game.Map.Drawables; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osuTK; + +namespace fluXis.Game.Screens.Result.Header; + +public partial class ResultsMap : CompositeDrawable +{ + [Resolved] + private RealmMap map { get; set; } + + [BackgroundDependencyLoader] + private void load() + { + AutoSizeAxes = Axes.Both; + + InternalChild = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(12), + Children = new Drawable[] + { + new LoadWrapper + { + Size = new Vector2(88), + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + EdgeEffect = FluXisStyles.ShadowMedium, + CornerRadius = 12, + Masking = true, + LoadContent = () => new MapCover(map.MapSet) + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre + } + }, + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Children = new Drawable[] + { + new FluXisSpriteText + { + Text = map.Metadata.Title, + WebFontSize = 20, + Shadow = true + }, + new FluXisSpriteText + { + Text = map.Metadata.Artist, + WebFontSize = 14, + Shadow = true, + Alpha = .8f + }, + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Margin = new MarginPadding { Top = 4 }, + Spacing = new Vector2(8), + Children = new Drawable[] + { + new DifficultyChip + { + Size = new Vector2(80, 20), + Rating = map.Filters.NotesPerSecond, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + EdgeEffect = FluXisStyles.ShadowSmall + }, + new FluXisSpriteText + { + Text = $"{map.Difficulty}", + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + WebFontSize = 14, + Shadow = true + } + } + } + } + } + } + }; + } +} diff --git a/fluXis.Game/Screens/Result/Header/ResultsPlayer.cs b/fluXis.Game/Screens/Result/Header/ResultsPlayer.cs new file mode 100644 index 00000000..7a42f67c --- /dev/null +++ b/fluXis.Game/Screens/Result/Header/ResultsPlayer.cs @@ -0,0 +1,100 @@ +using fluXis.Game.Graphics; +using fluXis.Game.Graphics.Containers; +using fluXis.Game.Graphics.Drawables; +using fluXis.Game.Graphics.Sprites; +using fluXis.Game.Online.Drawables; +using fluXis.Game.Utils; +using fluXis.Shared.Components.Users; +using fluXis.Shared.Scoring; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osuTK; + +namespace fluXis.Game.Screens.Result.Header; + +public partial class ResultsPlayer : CompositeDrawable +{ + [Resolved] + private ScoreInfo score { get; set; } + + [Resolved] + private APIUser user { get; set; } + + [BackgroundDependencyLoader] + private void load() + { + AutoSizeAxes = Axes.Both; + + var date = TimeUtils.GetFromSeconds(score.Timestamp); + + InternalChild = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(12), + Children = new Drawable[] + { + new LoadWrapper + { + Size = new Vector2(88), + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + EdgeEffect = FluXisStyles.ShadowMedium, + CornerRadius = 12, + Masking = true, + LoadContent = () => new DrawableAvatar(user) + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre + } + }, + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Children = new Drawable[] + { + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Children = new Drawable[] + { + new ClubTag(user.Club) + { + WebFontSize = 16, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Shadow = true + }, + new FluXisSpriteText + { + Text = $" {user.Username}", + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + WebFontSize = 20, + Shadow = true + } + } + }, + new FluXisSpriteText + { + Text = $"{date.Day} {date:MMM} {date.Year} @ {date:HH:mm}", + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + WebFontSize = 14, + Shadow = true, + Alpha = .8f + } + } + } + } + }; + } +} diff --git a/fluXis.Game/Screens/Result/Normal/NormalResults.cs b/fluXis.Game/Screens/Result/Normal/NormalResults.cs deleted file mode 100644 index 9943c0a2..00000000 --- a/fluXis.Game/Screens/Result/Normal/NormalResults.cs +++ /dev/null @@ -1,766 +0,0 @@ -using System.Linq; -using fluXis.Game.Database.Maps; -using fluXis.Game.Graphics; -using fluXis.Game.Graphics.Drawables; -using fluXis.Game.Graphics.Sprites; -using fluXis.Game.Graphics.UserInterface.Color; -using fluXis.Game.Map.Drawables; -using fluXis.Game.Mods.Drawables; -using fluXis.Game.Online.API; -using fluXis.Game.Screens.Result.UI; -using fluXis.Game.Skinning; -using fluXis.Game.Utils; -using fluXis.Shared.API.Responses.Scores; -using fluXis.Shared.Components.Users; -using fluXis.Shared.Scoring; -using fluXis.Shared.Scoring.Enums; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Colour; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osuTK; - -namespace fluXis.Game.Screens.Result.Normal; - -public partial class NormalResults : Container -{ - [Resolved] - private ScoreInfo score { get; set; } - - [Resolved] - private RealmMap map { get; set; } - - [Resolved] - private APIUser player { get; set; } - - [Resolved] - private SoloResults results { get; set; } - - [Resolved] - private SkinManager skins { get; set; } - - private FluXisSpriteText completionText; - private FluXisSpriteText scoreDifferenceText; - - private Container bannerContainer; - private Container avatarContainer; - private FluXisSpriteText playedAt; - - private OnlineStatistic ptrStat; - private OnlineStatistic ovrStat; - private OnlineStatistic rankStat; - private FillFlowContainer onlineStats; - private FluXisSpriteText errorText; - - [BackgroundDependencyLoader] - private void load() - { - RelativeSizeAxes = Axes.Both; - Anchor = Origin = Anchor.Centre; - - InternalChildren = new Drawable[] - { - new Container - { - Size = new Vector2(1250, 700), - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Children = new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.Both, - CornerRadius = 20, - Masking = true, - EdgeEffect = FluXisStyles.ShadowMedium, - Child = new Box - { - RelativeSizeAxes = Axes.Both, - Colour = FluXisColors.Background2 - } - }, - new FillFlowContainer - { - RelativeSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Children = new Drawable[] - { - new Container - { - Size = new Vector2(1300, 100), - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Margin = new MarginPadding { Bottom = 90 }, - Children = new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.Both, - Width = 0.5f, - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - CornerRadius = 20, - Masking = true, - EdgeEffect = FluXisStyles.ShadowSmall, - Children = new[] - { - new MapBackground(map) - { - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre - }, - getGradient(Colour4.Black, false), - getGradient(string.IsNullOrEmpty(map.Metadata.ColorHex) ? Colour4.Black : Colour4.FromHex(map.Metadata.ColorHex), false), - new FillFlowContainer - { - RelativeSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Padding = new MarginPadding { Horizontal = 20, Vertical = 10 }, - Spacing = new Vector2(-3), - Children = new Drawable[] - { - new TruncatingText - { - RelativeSizeAxes = Axes.X, - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Text = map.Difficulty, - Shadow = true, - FontSize = 24 - }, - new FluXisSpriteText - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Text = $"mapped by {map.Metadata.Mapper}", - Alpha = .8f, - Shadow = true, - FontSize = 18 - }, - new DifficultyChip - { - Size = new Vector2(80, 20), - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Margin = new MarginPadding { Top = 5 }, - Rating = map.Filters.NotesPerSecond, - EdgeEffect = FluXisStyles.ShadowSmall - } - } - } - } - }, - new Container - { - RelativeSizeAxes = Axes.Both, - Width = 0.5f, - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - CornerRadius = 20, - Masking = true, - EdgeEffect = FluXisStyles.ShadowSmall, - Children = new[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = FluXisColors.Background3 - }, - bannerContainer = new Container - { - RelativeSizeAxes = Axes.Both, - }, - getGradient(Colour4.Black, true), - new FillFlowContainer - { - AutoSizeAxes = Axes.X, - RelativeSizeAxes = Axes.Y, - Direction = FillDirection.Horizontal, - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - Padding = new MarginPadding(10), - Spacing = new Vector2(10), - Children = new Drawable[] - { - avatarContainer = new Container - { - Size = new Vector2(80), - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - CornerRadius = 10, - Masking = true, - EdgeEffect = FluXisStyles.ShadowSmall - }, - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - Children = new Drawable[] - { - new FluXisSpriteText - { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - Text = "played by", - FontSize = 18, - Shadow = true, - Alpha = .8f - }, - new FluXisSpriteText - { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - Text = player.Username, - FontSize = 28, - Shadow = true - }, - playedAt = new FluXisSpriteText - { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - FontSize = 18, - Shadow = true, - Alpha = .8f - } - } - } - } - } - } - }, - new Container - { - Size = new Vector2(250), - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - CornerRadius = 20, - Masking = true, - EdgeEffect = FluXisStyles.ShadowMedium, - Child = new MapCover(map.MapSet) - { - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre - } - } - } - }, - new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - Height = 80, - Direction = FillDirection.Vertical, - Padding = new MarginPadding { Horizontal = 20 }, - Children = new Drawable[] - { - new TruncatingText - { - MaxWidth = 800, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Text = map.Metadata.Title, - FontSize = 36 - }, - new TruncatingText - { - MaxWidth = 800, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Text = map.Metadata.Artist, - FontSize = 24 - } - } - }, - new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - Height = 310, - Direction = FillDirection.Horizontal, - Children = new Drawable[] - { - new FillFlowContainer - { - Width = 250, - RelativeSizeAxes = Axes.Y, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Direction = FillDirection.Vertical, - Spacing = new Vector2(10), - Children = new Drawable[] - { - new Entry - { - Title = "Accuracy", - Value = $"{score.Accuracy.ToStringInvariant("00.00")}%", - }, - new MaxComboEntry - { - Title = "Max Combo", - MaxCombo = score.MaxCombo, - TotalNotes = map.Filters.NoteCount + map.Filters.LongNoteCount * 2 - }, - new Entry - { - Title = "Performance Rating", - Value = getPerfRatingStr() - }, - new Entry - { - Title = "Scroll Speed", - Value = score.ScrollSpeed.ToStringInvariant("0.0") - } - } - }, - new FillFlowContainer - { - Width = 550, - RelativeSizeAxes = Axes.Y, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Direction = FillDirection.Vertical, - Spacing = new Vector2(20), - Children = new Drawable[] - { - completionText = new FluXisSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - FontSize = 36 - }, - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Spacing = new Vector2(-10), - Children = new Drawable[] - { - new FluXisSpriteText - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Text = "Score", - FontSize = 28, - Colour = FluXisColors.Text2 - }, - new FluXisSpriteText - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Text = score.Score.ToString("0000000"), - FontSize = 68 - }, - scoreDifferenceText = new FluXisSpriteText - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - FontSize = 28 - } - } - }, - new ModList - { - AutoSizeAxes = Axes.X, - Height = 40, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Mods = score.Mods.Select(ModUtils.GetFromAcronym).ToList() - } - } - }, - new FillFlowContainer - { - Width = 250, - RelativeSizeAxes = Axes.Y, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Direction = FillDirection.Vertical, - Spacing = new Vector2(10), - Children = new Drawable[] - { - new Entry - { - Title = "Flawless", - Value = $"{score.Flawless}", - Right = true, - Colour = skins.SkinJson.GetColorForJudgement(Judgement.Flawless) - }, - new Entry - { - Title = "Perfect", - Value = $"{score.Perfect}", - Right = true, - Colour = skins.SkinJson.GetColorForJudgement(Judgement.Perfect) - }, - new Entry - { - Title = "Great", - Value = $"{score.Great}", - Right = true, - Colour = skins.SkinJson.GetColorForJudgement(Judgement.Great) - }, - new Entry - { - Title = "Alright", - Value = $"{score.Alright}", - Right = true, - Colour = skins.SkinJson.GetColorForJudgement(Judgement.Alright) - }, - new Entry - { - Title = "Okay", - Value = $"{score.Okay}", - Right = true, - Colour = skins.SkinJson.GetColorForJudgement(Judgement.Okay) - }, - new Entry - { - Title = "Miss", - Value = $"{score.Miss}", - Right = true, - Colour = skins.SkinJson.GetColorForJudgement(Judgement.Miss) - } - } - } - } - }, - new Container - { - RelativeSizeAxes = Axes.X, - Height = 120, - Children = new Drawable[] - { - onlineStats = new FillFlowContainer - { - RelativeSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Alpha = 0, - Children = new Drawable[] - { - ovrStat = new OnlineStatistic { Title = "Overall Rating" }, - ptrStat = new OnlineStatistic { Title = "Potential Rating" }, - rankStat = new OnlineStatistic { Title = "Global Rank", DisplayAsRank = true } - } - }, - errorText = new FluXisSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Alpha = 0, - Text = "Failed to update statistics!", - FontSize = 24 - } - } - } - } - } - } - }, - new ResultsScrollForMore - { - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre, - Margin = new MarginPadding { Bottom = 60 } - } - }; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - if (score.FullFlawless) - { - completionText.Text = "FULL FLAWLESS"; - completionText.Colour = skins.SkinJson.GetColorForJudgement(Judgement.Flawless); - } - else if (score.FullCombo) - { - completionText.Text = "FULL COMBO"; - completionText.Colour = skins.SkinJson.GetColorForJudgement(Judgement.Perfect); - } - else - { - completionText.Text = "CLEARED"; - completionText.Colour = FluXisColors.Accent2.Lighten(.4f); - } - - if (results.ComparisonScore != null) - { - var difference = score.Score - results.ComparisonScore.Score; - scoreDifferenceText.Text = difference.ToString("+#0;-#0"); - } - - var date = TimeUtils.GetFromSeconds(score.Timestamp); - playedAt.Text = $"{date.Day} {date:MMM} {date.Year} @ {date:HH:mm}"; - - if (results.SubmitRequest is not null) - results.SubmitRequest.Success += _ => updateStats(); - - // this is called here for the case the request is null - updateStats(); - - LoadComponentAsync(new DrawableAvatar(player) - { - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - FillMode = FillMode.Fill - }, avatarContainer.Add); - - LoadComponentAsync(new DrawableBanner(player) - { - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - FillMode = FillMode.Fill - }, bannerContainer.Add); - } - - private void updateStats() - { - if (results.SubmitRequest is not null) - { - var res = results.SubmitRequest.Response; - if (res is null) return; - - if (res.Success) - { - ovrStat.StatChange = res.Data.OverallRating; - ptrStat.StatChange = res.Data.PotentialRating; - rankStat.StatChange = res.Data.Rank; - - onlineStats.FadeIn(200); - } - else - { - errorText.Text = results.SubmitRequest.FailReason?.Message ?? APIRequest.UNKNOWN_ERROR; - errorText.FadeIn(200); - } - } - else - { - errorText.Text = "No ranking data available!"; - errorText.FadeIn(200); - } - } - - private string getPerfRatingStr() - { - var sc = results.SubmitRequest?.Response?.Data?.Score; - var value = 0d; - - if (sc is { PerformanceRating: > 0 }) - value = sc.PerformanceRating; - else if (score.PerformanceRating > 0) - value = score.PerformanceRating; - - return value > 0 ? $"{value.ToStringInvariant("00.00")}pr" : "--.--pr"; - } - - private Drawable getGradient(Colour4 color, bool right) - { - var gradient = ColourInfo.GradientHorizontal(right ? color.Opacity(0) : color, right ? color : color.Opacity(0)); - - return new Container - { - RelativeSizeAxes = Axes.Both, - Alpha = .5f, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Width = .8f, - Colour = gradient, - Anchor = right ? Anchor.CentreLeft : Anchor.CentreRight, - Origin = right ? Anchor.CentreLeft : Anchor.CentreRight - }, - new Box - { - RelativeSizeAxes = Axes.Both, - Width = .2f, - Colour = color, - Anchor = right ? Anchor.CentreRight : Anchor.CentreLeft, - Origin = right ? Anchor.CentreRight : Anchor.CentreLeft - } - } - }; - } - - private partial class Entry : Container - { - public string Title { get; init; } = "Title"; - public string Value { get; init; } = "Value"; - public bool Right { get; init; } - - [BackgroundDependencyLoader] - private void load() - { - Size = new Vector2(190, 40); - Anchor = Anchor.Centre; - Origin = Anchor.Centre; - - InternalChildren = new Drawable[] - { - new CircularContainer - { - Width = 6, - RelativeSizeAxes = Axes.Y, - Anchor = Right ? Anchor.CentreRight : Anchor.CentreLeft, - Origin = Right ? Anchor.CentreRight : Anchor.CentreLeft, - Masking = true, - Child = new Box { RelativeSizeAxes = Axes.Both } - }, - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Anchor = Right ? Anchor.CentreRight : Anchor.CentreLeft, - Origin = Right ? Anchor.CentreRight : Anchor.CentreLeft, - Margin = new MarginPadding { Horizontal = 6 }, - Padding = new MarginPadding { Horizontal = 10 }, - Spacing = new Vector2(-3), - Children = new[] - { - new FluXisSpriteText - { - Anchor = Right ? Anchor.CentreRight : Anchor.CentreLeft, - Origin = Right ? Anchor.CentreRight : Anchor.CentreLeft, - Text = Title, - FontSize = 18, - Alpha = .8f - }, - CreateBottomRow().With(d => - { - d.Anchor = d.Origin = Right ? Anchor.CentreRight : Anchor.CentreLeft; - }) - } - } - }; - } - - protected virtual Drawable CreateBottomRow() - { - return new FluXisSpriteText - { - Anchor = Right ? Anchor.CentreRight : Anchor.CentreLeft, - Origin = Right ? Anchor.CentreRight : Anchor.CentreLeft, - FontSize = 24, - Text = Value - }; - } - } - - private partial class MaxComboEntry : Entry - { - public int MaxCombo { get; init; } - public int TotalNotes { get; init; } - - protected override Drawable CreateBottomRow() - { - return new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Children = new Drawable[] - { - new FluXisSpriteText - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - FontSize = 24, - Text = $"{MaxCombo}" - }, - new FluXisSpriteText - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - FontSize = 18, - Alpha = .8f, - Text = $"/{TotalNotes}x" - } - } - }; - } - } - - private partial class OnlineStatistic : FillFlowContainer - { - public string Title { get; init; } = "Title"; - public bool DisplayAsRank { get; init; } - - public ScoreSubmissionStats.StatisticChange StatChange - { - set - { - var diff = value.Current - value.Previous; - valueText.Text = DisplayAsRank ? $"#{(int)value.Current}" : value.Current.ToStringInvariant("00.00"); - - var negativeColor = Colour4.FromHex("#FF5555"); - var positiveColor = Colour4.FromHex("#55FF55"); - - switch (diff) - { - case > 0: - differenceText.Text = DisplayAsRank ? $"+{diff}" : $"+{diff.ToStringInvariant("00.00")}"; - differenceText.Colour = DisplayAsRank ? negativeColor : positiveColor; - break; - - case < 0: - differenceText.Text = DisplayAsRank ? $"{diff}" : $"{diff.ToStringInvariant("00.00")}"; - differenceText.Colour = DisplayAsRank ? positiveColor : negativeColor; - break; - - default: - differenceText.Text = "KEEP"; - differenceText.Colour = FluXisColors.Text2; - break; - } - } - } - - private FluXisSpriteText valueText; - private FluXisSpriteText differenceText; - - [BackgroundDependencyLoader] - private void load() - { - Width = 200; - RelativeSizeAxes = Axes.Y; - Direction = FillDirection.Vertical; - Anchor = Origin = Anchor.Centre; - Spacing = new Vector2(-5); - - InternalChildren = new Drawable[] - { - new FluXisSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Text = Title, - FontSize = 14, - Alpha = .8f, - Margin = new MarginPadding { Bottom = 2 } - }, - valueText = new FluXisSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - FontSize = 32 - }, - differenceText = new FluXisSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - FontSize = 20 - } - }; - } - } -} diff --git a/fluXis.Game/Screens/Result/ResultsContent.cs b/fluXis.Game/Screens/Result/ResultsContent.cs new file mode 100644 index 00000000..2ea968d0 --- /dev/null +++ b/fluXis.Game/Screens/Result/ResultsContent.cs @@ -0,0 +1,169 @@ +using System; +using fluXis.Game.Screens.Result.Center; +using fluXis.Game.Screens.Result.Sides; +using fluXis.Game.Screens.Result.Sides.Types; +using fluXis.Game.Skinning; +using fluXis.Shared.Scoring; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Utils; +using osuTK; + +namespace fluXis.Game.Screens.Result; + +public partial class ResultsContent : CompositeDrawable +{ + [Resolved] + private SoloResults screen { get; set; } + + [Resolved] + private SkinManager skins { get; set; } + + [Resolved] + private ScoreInfo score { get; set; } + + private bool rankMoveSmoothly; + private bool rankUseCenter; + + private Drawable rank; + private ResultsHeader header; + private ResultsSideList left; + private ResultsCenter center; + private ResultsSideList right; + + [BackgroundDependencyLoader] + private void load(SkinManager skins) + { + RelativeSizeAxes = Axes.Both; + Padding = new MarginPadding(20) { Bottom = 100 }; + + InternalChildren = new[] + { + rank = skins.GetResultsScoreRank(score.Rank).With(d => d.Origin = Anchor.Centre), + new GridContainer + { + RelativeSizeAxes = Axes.Both, + RowDimensions = new Dimension[] + { + new(GridSizeMode.AutoSize), + new() + }, + Content = new[] + { + new Drawable[] + { + header = new ResultsHeader() + }, + new Drawable[] + { + new GridContainer + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding(16), + ColumnDimensions = new Dimension[] + { + new(GridSizeMode.Absolute, 440), + new(), + new(GridSizeMode.Absolute, 440) + }, + Content = new[] + { + new Drawable[] + { + left = new ResultsSideList + { + Children = new Drawable[] + { + new ResultsSideJudgements(skins, score), + new ResultsSideMore(score) + } + }, + center = new ResultsCenter(), + right = new ResultsSideList + { + Children = new Drawable[] + { + new ResultsSideRankings(screen.SubmitRequest) + } + } + } + } + } + } + } + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + ScheduleAfterChildren(() => updateRankPosition(true)); + } + + protected override void Update() + { + base.Update(); + updateRankPosition(!rankMoveSmoothly); + } + + private void updateRankPosition(bool instant) + { + var pos = ToLocalSpace(rankUseCenter ? ScreenSpaceDrawQuad.Centre : center.ScreenSpaceRankPosition); + pos -= new Vector2(Padding.Left, Padding.Right); + + if (rankUseCenter) + pos.Y -= 80; // to account for bottom padding + + if (instant) + { + rank.Position = pos; + return; + } + + rank.X = (float)Interpolation.Lerp(pos.X, rank.X, Math.Exp(-0.01 * Time.Elapsed)); + rank.Y = (float)Interpolation.Lerp(pos.Y, rank.Y, Math.Exp(-0.01 * Time.Elapsed)); + } + + public void Show(bool fromGameplay = false) + { + if (!fromGameplay) + { + rank.ScaleTo(.9f).ScaleTo(1, FluXisScreen.MOVE_DURATION, Easing.OutQuint); + left.MoveToX(-200).MoveToX(0, FluXisScreen.MOVE_DURATION, Easing.OutQuint); + center.Show(); + right.MoveToX(200).MoveToX(0, FluXisScreen.MOVE_DURATION, Easing.OutQuint); + return; + } + + rankMoveSmoothly = true; + rankUseCenter = true; + + header.Hide(); + left.FadeOut(); + center.FadeOut(); + right.FadeOut(); + + rank.FadeOut().ScaleTo(1.8f) + .ScaleTo(1, 2000, Easing.OutQuint).FadeIn(400); + + using (BeginDelayedSequence(2000)) + { + header.MoveToY(-50).MoveToY(0, FluXisScreen.MOVE_DURATION, Easing.OutQuint).FadeIn(FluXisScreen.FADE_DURATION); + left.MoveToX(-200).MoveToX(0, FluXisScreen.MOVE_DURATION, Easing.OutQuint).FadeIn(FluXisScreen.FADE_DURATION); + center.FadeIn(FluXisScreen.FADE_DURATION); + center.Show(); + right.MoveToX(200).MoveToX(0, FluXisScreen.MOVE_DURATION, Easing.OutQuint).FadeIn(FluXisScreen.FADE_DURATION); + } + } + + public override void Hide() + { + rank.ScaleTo(.9f, FluXisScreen.MOVE_DURATION, Easing.OutQuint); + left.MoveToX(-200, FluXisScreen.MOVE_DURATION, Easing.OutQuint); + center.Hide(); + right.MoveToX(200, FluXisScreen.MOVE_DURATION, Easing.OutQuint); + } +} diff --git a/fluXis.Game/Screens/Result/ResultsFooter.cs b/fluXis.Game/Screens/Result/ResultsFooter.cs new file mode 100644 index 00000000..f7ddf990 --- /dev/null +++ b/fluXis.Game/Screens/Result/ResultsFooter.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using fluXis.Game.Graphics.Sprites; +using fluXis.Game.Graphics.UserInterface.Buttons; +using fluXis.Game.Graphics.UserInterface.Color; +using fluXis.Game.Graphics.UserInterface.Footer; +using fluXis.Game.Localization; +using fluXis.Game.UI; + +namespace fluXis.Game.Screens.Result; + +public partial class ResultsFooter : Footer +{ + public Action BackAction { get; init; } + public Action RestartAction { get; init; } + + protected override CornerButton CreateLeftButton() => new() + { + ButtonText = LocalizationStrings.General.Back, + Icon = FontAwesome6.Solid.ChevronLeft, + Action = BackAction + }; + + protected override CornerButton CreateRightButton() + { + if (RestartAction is null) + return null; + + return new CornerButton + { + ButtonText = "Retry", + Corner = Corner.BottomRight, + Icon = FontAwesome6.Solid.RotateRight, + ButtonColor = FluXisColors.Accent2, + Action = RestartAction + }; + } + + protected override IEnumerable CreateButtons() => ArraySegment.Empty; +} diff --git a/fluXis.Game/Screens/Result/ResultsHeader.cs b/fluXis.Game/Screens/Result/ResultsHeader.cs new file mode 100644 index 00000000..5ab9bfbf --- /dev/null +++ b/fluXis.Game/Screens/Result/ResultsHeader.cs @@ -0,0 +1,27 @@ +using fluXis.Game.Screens.Result.Header; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; + +namespace fluXis.Game.Screens.Result; + +public partial class ResultsHeader : CompositeDrawable +{ + [BackgroundDependencyLoader] + private void load() + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + Padding = new MarginPadding(16); + + InternalChildren = new Drawable[] + { + new ResultsMap(), + new ResultsPlayer + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight + } + }; + } +} diff --git a/fluXis.Game/Screens/Result/ResultsScreen.cs b/fluXis.Game/Screens/Result/ResultsScreen.cs deleted file mode 100644 index 0285ec1a..00000000 --- a/fluXis.Game/Screens/Result/ResultsScreen.cs +++ /dev/null @@ -1,227 +0,0 @@ -using fluXis.Game.Database; -using fluXis.Game.Database.Maps; -using fluXis.Game.Database.Score; -using fluXis.Game.Graphics; -using fluXis.Game.Graphics.Drawables; -using fluXis.Game.Graphics.Gamepad; -using fluXis.Game.Graphics.Sprites; -using fluXis.Game.Graphics.UserInterface.Buttons; -using fluXis.Game.Graphics.UserInterface.Color; -using fluXis.Game.Input; -using fluXis.Game.Localization; -using fluXis.Game.Map; -using fluXis.Game.Online.Activity; -using fluXis.Game.Online.API; -using fluXis.Game.Screens.Result.UI; -using fluXis.Shared.API.Responses.Scores; -using fluXis.Shared.Components.Users; -using fluXis.Shared.Scoring; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Colour; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Input.Bindings; -using osu.Framework.Input.Events; -using osu.Framework.Screens; - -namespace fluXis.Game.Screens.Result; - -public partial class ResultsScreen : FluXisScreen, IKeyBindingHandler -{ - public override float Zoom => 1.2f; - public override bool AllowMusicControl => false; - public override UserActivity InitialActivity => new UserActivity.Results(); - - [Resolved] - private FluXisRealm realm { get; set; } - - private readonly RealmMap map; - private readonly MapInfo mapInfo; - private readonly ScoreInfo score; - private readonly APIUser player; - private readonly RealmScore realmScore; - - private Container content; - private ResultsRatingInfo ratingInfo; - private GamepadTooltipBar gamepadTooltips; - private Container buttons; - private CornerButton backButton; - - private readonly bool showPlayData; - - public ResultsScreen(RealmMap map, MapInfo mapInfo, ScoreInfo score, APIUser player, bool showPlayData = true, bool saveScore = true) - { - this.map = map; - this.mapInfo = mapInfo; - this.score = score; - this.showPlayData = showPlayData; - this.player = player; - - if (saveScore) - { - realmScore = new RealmScore(map) - { - PlayerID = player?.ID ?? -1, - Accuracy = score.Accuracy, - Rank = score.Rank, - Score = score.Score, - MaxCombo = score.MaxCombo, - Flawless = score.Flawless, - Perfect = score.Perfect, - Great = score.Great, - Alright = score.Alright, - Okay = score.Okay, - Miss = score.Miss, - Mods = string.Join(' ', score.Mods) - }; - } - } - - [BackgroundDependencyLoader] - private void load() - { - Anchor = Anchor.Centre; - Origin = Anchor.Centre; - - InternalChildren = new Drawable[] - { - content = new Container - { - AutoSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - CornerRadius = 10, - MaskingSmoothness = 0, - Masking = true, - EdgeEffect = FluXisStyles.ShadowMedium, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = FluXisColors.Background2 - }, - new DrawableBanner(player) - { - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre - }, - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientVertical(FluXisColors.Background2.Opacity(.6f), FluXisColors.Background2) - }, - new FillFlowContainer - { - AutoSizeAxes = Axes.Y, - Width = 740, - Direction = FillDirection.Vertical, - Margin = new MarginPadding(20), - Children = new[] - { - new ResultTitle(map) { User = player }, - new ResultScore { Score = score, MapInfo = mapInfo }, - showPlayData ? new ResultHitPoints { MapInfo = mapInfo, Score = score } : Empty(), - ratingInfo = new ResultsRatingInfo(showPlayData) - } - } - } - }, - new Container - { - RelativeSizeAxes = Axes.X, - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - Height = 60, - Children = new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.Both, - Masking = true, - EdgeEffect = FluXisStyles.ShadowMediumNoOffset, - Child = new Box - { - RelativeSizeAxes = Axes.Both, - Colour = FluXisColors.Background2 - } - }, - buttons = new Container - { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - backButton = new CornerButton - { - ButtonText = LocalizationStrings.General.Back, - Icon = FontAwesome6.Solid.ChevronLeft, - Action = this.Exit - } - } - }, - gamepadTooltips = new GamepadTooltipBar - { - ShowBackground = false, - TooltipsLeft = new GamepadTooltip[] - { - new() - { - Text = LocalizationStrings.General.Back, - Icon = "B" - } - } - } - } - } - }; - - GamepadHandler.OnGamepadStatusChanged += onGamepadStatusChanged; - onGamepadStatusChanged(GamepadHandler.GamepadConnected); - - if (realmScore != null && !map.MapSet.AutoImported) - { - realm.RunWrite(r => r.Add(realmScore)); - // OnlineScores.UploadScore(fluxel, score, res => ratingInfo.ScoreResponse = res); - } - else - ratingInfo.ScoreResponse = new APIResponse(400, "Score not submittable.", null); - } - - private void onGamepadStatusChanged(bool status) - { - gamepadTooltips.FadeTo(status ? 1 : 0); - buttons.FadeTo(status ? 0 : 1); - } - - public bool OnPressed(KeyBindingPressEvent e) - { - switch (e.Action) - { - case FluXisGlobalKeybind.Back: - this.Exit(); - return true; - } - - return false; - } - - public void OnReleased(KeyBindingReleaseEvent e) { } - - public override void OnEntering(ScreenTransitionEvent e) - { - content.ScaleTo(0.9f).ScaleTo(1f, 400, Easing.OutQuint); - this.FadeInFromZero(200); - backButton.Show(); - } - - public override bool OnExiting(ScreenExitEvent e) - { - content.ScaleTo(1.1f, 400, Easing.OutQuint); - this.FadeOut(200); - backButton.Hide(); - - return base.OnExiting(e); - } -} diff --git a/fluXis.Game/Screens/Result/Results_Gamepad.cs b/fluXis.Game/Screens/Result/Results_Gamepad.cs deleted file mode 100644 index 64c68678..00000000 --- a/fluXis.Game/Screens/Result/Results_Gamepad.cs +++ /dev/null @@ -1,22 +0,0 @@ -using osu.Framework.Input; -using osu.Framework.Input.Events; -using osu.Framework.Screens; - -namespace fluXis.Game.Screens.Result; - -public partial class ResultsScreen -{ - protected override bool OnJoystickPress(JoystickPressEvent e) => handleGeneric(e); - - private bool handleGeneric(JoystickButtonEvent e) - { - switch (e.Button) - { - case JoystickButton.Button3: // B - this.Exit(); - return true; - } - - return false; - } -} diff --git a/fluXis.Game/Screens/Result/Sides/Presets/ResultsSideDoubleText.cs b/fluXis.Game/Screens/Result/Sides/Presets/ResultsSideDoubleText.cs new file mode 100644 index 00000000..a8a221c0 --- /dev/null +++ b/fluXis.Game/Screens/Result/Sides/Presets/ResultsSideDoubleText.cs @@ -0,0 +1,43 @@ +using fluXis.Game.Graphics.Sprites; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; + +namespace fluXis.Game.Screens.Result.Sides.Presets; + +public partial class ResultsSideDoubleText : CompositeDrawable +{ + private string title { get; } + private string value { get; } + + public ResultsSideDoubleText(string title, string value) + { + this.title = title; + this.value = value; + } + + [BackgroundDependencyLoader] + private void load() + { + RelativeSizeAxes = Axes.X; + Height = 12; + + InternalChildren = new Drawable[] + { + new FluXisSpriteText + { + Text = title, + WebFontSize = 16, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft + }, + new FluXisSpriteText + { + Text = value, + WebFontSize = 16, + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight + } + }; + } +} diff --git a/fluXis.Game/Screens/Result/Sides/ResultsSideContainer.cs b/fluXis.Game/Screens/Result/Sides/ResultsSideContainer.cs new file mode 100644 index 00000000..0d8930c1 --- /dev/null +++ b/fluXis.Game/Screens/Result/Sides/ResultsSideContainer.cs @@ -0,0 +1,61 @@ +using fluXis.Game.Graphics; +using fluXis.Game.Graphics.Sprites; +using fluXis.Game.Graphics.UserInterface.Color; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Localisation; +using osuTK; + +namespace fluXis.Game.Screens.Result.Sides; + +public abstract partial class ResultsSideContainer : CompositeDrawable +{ + protected abstract LocalisableString Title { get; } + + [BackgroundDependencyLoader] + private void load() + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + EdgeEffect = FluXisStyles.ShadowMedium; + CornerRadius = 16; + Masking = true; + + InternalChildren = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = FluXisColors.Background2 + }, + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Spacing = new Vector2(20), + Padding = new MarginPadding(24), + Direction = FillDirection.Vertical, + Children = new[] + { + new Container + { + AutoSizeAxes = Axes.X, + Height = 16, + Child = new FluXisSpriteText + { + Text = Title, + WebFontSize = 20, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft + } + }, + CreateContent() + } + } + }; + } + + protected abstract Drawable CreateContent(); +} diff --git a/fluXis.Game/Screens/Result/Sides/ResultsSideList.cs b/fluXis.Game/Screens/Result/Sides/ResultsSideList.cs new file mode 100644 index 00000000..6e34447a --- /dev/null +++ b/fluXis.Game/Screens/Result/Sides/ResultsSideList.cs @@ -0,0 +1,17 @@ +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osuTK; + +namespace fluXis.Game.Screens.Result.Sides; + +public partial class ResultsSideList : FillFlowContainer +{ + public ResultsSideList() + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + Anchor = Anchor.BottomLeft; + Origin = Anchor.BottomLeft; + Spacing = new Vector2(16); + } +} diff --git a/fluXis.Game/Screens/Result/Sides/Types/ResultsSideJudgements.cs b/fluXis.Game/Screens/Result/Sides/Types/ResultsSideJudgements.cs new file mode 100644 index 00000000..3c8ec304 --- /dev/null +++ b/fluXis.Game/Screens/Result/Sides/Types/ResultsSideJudgements.cs @@ -0,0 +1,41 @@ +using fluXis.Game.Screens.Result.Sides.Presets; +using fluXis.Game.Skinning; +using fluXis.Shared.Scoring; +using fluXis.Shared.Scoring.Enums; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Localisation; +using osuTK; + +namespace fluXis.Game.Screens.Result.Sides.Types; + +public partial class ResultsSideJudgements : ResultsSideContainer +{ + protected override LocalisableString Title => "Judgements"; + + private SkinManager skins { get; } + private ScoreInfo score { get; } + + public ResultsSideJudgements(SkinManager skins, ScoreInfo score) + { + this.score = score; + this.skins = skins; + } + + protected override Drawable CreateContent() => new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(16), + Children = new Drawable[] + { + new ResultsSideDoubleText("Flawless", $"{score.Flawless}") { Colour = skins.SkinJson.GetColorForJudgement(Judgement.Flawless) }, + new ResultsSideDoubleText("Perfect", $"{score.Perfect}") { Colour = skins.SkinJson.GetColorForJudgement(Judgement.Perfect) }, + new ResultsSideDoubleText("Great", $"{score.Great}") { Colour = skins.SkinJson.GetColorForJudgement(Judgement.Great) }, + new ResultsSideDoubleText("Alright", $"{score.Alright}") { Colour = skins.SkinJson.GetColorForJudgement(Judgement.Alright) }, + new ResultsSideDoubleText("Okay", $"{score.Okay}") { Colour = skins.SkinJson.GetColorForJudgement(Judgement.Okay) }, + new ResultsSideDoubleText("Miss", $"{score.Miss}") { Colour = skins.SkinJson.GetColorForJudgement(Judgement.Miss) }, + } + }; +} diff --git a/fluXis.Game/Screens/Result/Sides/Types/ResultsSideMore.cs b/fluXis.Game/Screens/Result/Sides/Types/ResultsSideMore.cs new file mode 100644 index 00000000..75fb3f6a --- /dev/null +++ b/fluXis.Game/Screens/Result/Sides/Types/ResultsSideMore.cs @@ -0,0 +1,39 @@ +using fluXis.Game.Screens.Result.Sides.Presets; +using fluXis.Game.Utils; +using fluXis.Shared.Scoring; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Localisation; +using osuTK; + +namespace fluXis.Game.Screens.Result.Sides.Types; + +public partial class ResultsSideMore : ResultsSideContainer +{ + protected override LocalisableString Title => "More Info"; + + private ScoreInfo score { get; } + + public ResultsSideMore(ScoreInfo score) + { + this.score = score; + } + + protected override Drawable CreateContent() => new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(16), + Children = new Drawable[] + { + new ResultsSideDoubleText("FL:PF Ratio", score.Flawless switch + { + 0 => "0", + > 0 when score.Perfect == 0 => "Full Flawless", + _ => $"{(score.Flawless / (float)score.Perfect).ToStringInvariant("0.0")}:1" + }), + new ResultsSideDoubleText("Scroll Speed", $"{score.ScrollSpeed.ToStringInvariant()}") + } + }; +} diff --git a/fluXis.Game/Screens/Result/Sides/Types/ResultsSideRankings.cs b/fluXis.Game/Screens/Result/Sides/Types/ResultsSideRankings.cs new file mode 100644 index 00000000..8782bb07 --- /dev/null +++ b/fluXis.Game/Screens/Result/Sides/Types/ResultsSideRankings.cs @@ -0,0 +1,108 @@ +using fluXis.Game.Graphics.Sprites; +using fluXis.Game.Graphics.UserInterface.Text; +using fluXis.Game.Online.API.Requests.Scores; +using fluXis.Game.Utils; +using fluXis.Shared.API.Responses.Scores; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Localisation; +using osuTK; + +namespace fluXis.Game.Screens.Result.Sides.Types; + +public partial class ResultsSideRankings : ResultsSideContainer +{ + protected override LocalisableString Title => "Rankings"; + + private ScoreSubmitRequest request { get; } + + public ResultsSideRankings(ScoreSubmitRequest request) + { + this.request = request; + + if (request is null || !request.IsSuccessful) + Alpha = 0; + } + + protected override Drawable CreateContent() + { + if (request is null || !request.IsSuccessful) + return Empty(); + + return new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + Height = 50, + Direction = FillDirection.Horizontal, + Children = new Drawable[] + { + new Statistic("Overall Rating", request.Response.Data.OverallRating), + new Statistic("Potential Rating", request.Response.Data.PotentialRating), + new Statistic("Rank", request.Response.Data.OverallRating, true) + } + }; + } + + private partial class Statistic : FillFlowContainer + { + public Statistic(string title, ScoreSubmissionStats.StatisticChange change, bool asRank = false) + { + RelativeSizeAxes = Axes.Both; + Direction = FillDirection.Vertical; + Spacing = new Vector2(8); + Width = 1f / 3; + + var diff = change.Current - change.Previous; + var value = asRank ? $"#{(int)change.Current}" : change.Current.ToStringInvariant("00.00"); + var difference = "KEEP"; + var color = Colour4.White.Opacity(0.6f); + + var negativeColor = Colour4.FromHex("#FF5555"); + var positiveColor = Colour4.FromHex("#55FF55"); + + switch (diff) + { + case > 0: + difference = asRank ? $"+{diff}" : $"+{diff.ToStringInvariant("00.00")}"; + color = asRank ? negativeColor : positiveColor; + break; + + case < 0: + difference = asRank ? $"{diff}" : $"{diff.ToStringInvariant("00.00")}"; + color = asRank ? positiveColor : negativeColor; + break; + } + + InternalChildren = new Drawable[] + { + new ForcedHeightText + { + Text = title, + WebFontSize = 12, + Height = 10, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Alpha = .8f + }, + new FluXisSpriteText + { + Text = value, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + UseFullGlyphHeight = false, + WebFontSize = 20 + }, + new FluXisSpriteText + { + Text = difference, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + UseFullGlyphHeight = false, + Colour = color, + WebFontSize = 14 + } + }; + } + } +} + diff --git a/fluXis.Game/Screens/Result/SoloResults.cs b/fluXis.Game/Screens/Result/SoloResults.cs index b64b473b..e1825290 100644 --- a/fluXis.Game/Screens/Result/SoloResults.cs +++ b/fluXis.Game/Screens/Result/SoloResults.cs @@ -1,22 +1,12 @@ using System; using fluXis.Game.Database.Maps; -using fluXis.Game.Graphics; -using fluXis.Game.Graphics.Background; -using fluXis.Game.Graphics.Sprites; -using fluXis.Game.Graphics.UserInterface.Buttons; -using fluXis.Game.Graphics.UserInterface.Color; using fluXis.Game.Input; -using fluXis.Game.Localization; using fluXis.Game.Online.API.Requests.Scores; -using fluXis.Game.Screens.Result.Extended; -using fluXis.Game.Screens.Result.Normal; -using fluXis.Game.UI; +using fluXis.Game.Screens.Gameplay; using fluXis.Shared.Components.Users; using fluXis.Shared.Scoring; using osu.Framework.Allocation; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Framework.Screens; @@ -26,11 +16,10 @@ namespace fluXis.Game.Screens.Result; public partial class SoloResults : FluXisScreen, IKeyBindingHandler { public override float Zoom => 1.2f; - public override float BackgroundDim => 0.5f; + public override float BackgroundDim => 0.75f; public override float BackgroundBlur => 0.2f; - [Resolved] - private GlobalBackground backgrounds { get; set; } + public bool ForceFromGameplay { get; init; } public ScoreInfo Score { get; } public RealmMap Map { get; } @@ -42,13 +31,9 @@ public partial class SoloResults : FluXisScreen, IKeyBindingHandler OnRestart?.Invoke() - } - } + BackAction = this.Exit, + RestartAction = OnRestart } }; } protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) => dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); - protected override void LoadComplete() - { - base.LoadComplete(); - - extended.Alpha = 0f; - extended.Y = 100f; - } - - private void setState(bool state) - { - if (extendedState == state) return; - - extendedState = state; - - backgrounds.SetBlur(state ? .5f : .2f, 400); - backgrounds.SetDim(state ? .8f : .5f, 400); - - const float distance = 150; - const float delay = 180; - const float duration = 400; - - normal.Delay(state ? 0 : delay).FadeTo(state ? 0f : 1f, duration / 2).MoveToY(state ? -distance : 0, duration, Easing.Out); - extended.Delay(state ? delay : 0).FadeTo(state ? 1f : 0f, duration / 2).MoveToY(state ? 0 : distance, duration, Easing.Out); - } - - protected override bool OnScroll(ScrollEvent e) - { - setState(e.ScrollDelta.Y < 0); - return true; - } - public override void OnEntering(ScreenTransitionEvent e) { this.FadeOut(); @@ -148,21 +70,16 @@ public override void OnEntering(ScreenTransitionEvent e) using (BeginDelayedSequence(ENTER_DELAY)) { this.FadeInFromZero(FADE_DURATION); - normal.ScaleTo(.8f).ScaleTo(1f, MOVE_DURATION, Easing.OutQuint); - - backButton.Show(); - retryButton.Show(); + content.Show(e.Last is GameplayScreen || ForceFromGameplay); + footer.Show(); } } public override bool OnExiting(ScreenExitEvent e) { this.FadeOut(FADE_DURATION); - normal.ScaleTo(.8f, MOVE_DURATION, Easing.OutQuint); - extended.ScaleTo(.8f, MOVE_DURATION, Easing.OutQuint); - - backButton.Hide(); - retryButton.Hide(); + content.Hide(); + footer.Hide(); return base.OnExiting(e); } diff --git a/fluXis.Game/Screens/Result/UI/ResultHitPoints.cs b/fluXis.Game/Screens/Result/UI/ResultHitPoints.cs deleted file mode 100644 index 303bfaec..00000000 --- a/fluXis.Game/Screens/Result/UI/ResultHitPoints.cs +++ /dev/null @@ -1,260 +0,0 @@ -using System; -using System.Threading.Tasks; -using fluXis.Game.Graphics.Sprites; -using fluXis.Game.Graphics.UserInterface; -using fluXis.Game.Graphics.UserInterface.Color; -using fluXis.Game.Map; -using fluXis.Game.Skinning; -using fluXis.Shared.Scoring; -using fluXis.Shared.Scoring.Enums; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Colour; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Rendering; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Graphics.Textures; -using osu.Framework.Input.Events; -using osu.Framework.Logging; -using osuTK; -using osuTK.Input; -using SixLabors.ImageSharp; -using SixLabors.ImageSharp.Drawing; -using SixLabors.ImageSharp.Drawing.Processing; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing; - -namespace fluXis.Game.Screens.Result.UI; - -public partial class ResultHitPoints : Container -{ - public MapInfo MapInfo { get; set; } - public ScoreInfo Score { get; set; } - - [Resolved] - private SkinManager skinManager { get; set; } - - [Resolved] - private IRenderer renderer { get; set; } - - private const int max_zoom = 4; - - private Container hitResults; - private LoadingIcon loadingIcon; - - private Image image; - private TextureUpload upload; - - [BackgroundDependencyLoader] - private void load() - { - Height = 300; - RelativeSizeAxes = Axes.X; - Margin = new MarginPadding { Top = 10 }; - CornerRadius = 10; - Masking = true; - - AddRangeInternal(new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientVertical(FluXisColors.Background3.Opacity(.4f), FluXisColors.Background3.Opacity(.6f)) - }, - new Container - { - RelativeSizeAxes = Axes.Both, - // Padding = new MarginPadding(10), - Children = new Drawable[] - { - hitResults = new Container - { - RelativeSizeAxes = Axes.Both, - Alpha = 0, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Children = new Drawable[] - { - new Box - { - Height = 2, - Width = 3, - RelativeSizeAxes = Axes.X, - Anchor = Anchor.Centre, - Origin = Anchor.Centre - } - } - }, - loadingIcon = new LoadingIcon - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Size = new Vector2(50), - Alpha = 0 - } - } - } - }); - - Task.Run(() => - { - try { drawSprite(); } - catch (Exception e) - { - Logger.Log($"Failed to draw hitpoints: {e.Message}", LoggingTarget.Runtime, LogLevel.Error); - Logger.Log(e.StackTrace, LoggingTarget.Runtime, LogLevel.Error); - - Schedule(() => - { - var text = new FluXisSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Text = "Failed to draw hitstats..." - }; - - hitResults.Clear(); - hitResults.Add(text); - hitResults.FadeInFromZero(200); - loadingIcon.FadeOut(200); - }); - } - }); - } - - private void drawSprite() - { - Schedule(() => loadingIcon.FadeIn(200)); - - image = new Image(740 * max_zoom, 300 * max_zoom, new Rgba32(0, 0, 0, 0)); - const int padding = 10 * max_zoom; - - foreach (var result in Score.HitResults) - { - var startTime = result.Time - MapInfo.StartTime; - var endTime = MapInfo.EndTime - MapInfo.StartTime; - - var x = (int)((image.Width - padding * 2) * (startTime == endTime ? .5f : startTime / endTime)) + padding; - var y = (int)(image.Height / 2f - result.Difference * max_zoom); - - var colour4 = skinManager.SkinJson.GetColorForJudgement(result.Judgement); - var rgb = new Rgba32(colour4.R, colour4.G, colour4.B); - - const int radius = 3 * max_zoom; - - var poly = new EllipsePolygon(x, y, radius); - var brush = new SolidBrush(new Color(rgb)); - image.Mutate(ctx => ctx.Fill(brush, poly)); - - if (result.Judgement == Judgement.Miss) - { - // draw a semi-transparent line with the width of radius over every transparent pixel in the same x - for (int i = 0; i < radius / 2; i++) - { - for (var y2 = 0; y2 < image.Height; y2++) - { - var pixel = image[x + i, y2]; - - if (pixel.A == 0) - image[x + i, y2] = new Rgba32(colour4.R, colour4.G, colour4.B, .25f); - else - { - var curAlpha = pixel.A / 255f; - var newAlpha = curAlpha + .25f; - image[x + i, y2] = new Rgba32(colour4.R, colour4.G, colour4.B, newAlpha); - } - - pixel = image[x - i, y2]; - - if (pixel.A == 0) - image[x - i, y2] = new Rgba32(colour4.R, colour4.G, colour4.B, .25f); - else - { - var curAlpha = pixel.A / 255f; - var newAlpha = curAlpha + .25f; - image[x + i, y2] = new Rgba32(colour4.R, colour4.G, colour4.B, newAlpha); - } - } - } - } - } - - upload = new TextureUpload(image); - - var sprite = new Sprite - { - RelativeSizeAxes = Axes.Both, - Texture = renderer.CreateTexture(image.Width, image.Height, true), - }; - - sprite.Texture.BypassTextureUploadQueueing = true; - sprite.Texture.SetData(upload); - - Schedule(() => - { - hitResults.Add(sprite); - hitResults.FadeInFromZero(200, Easing.OutQuint); - loadingIcon.FadeOut(200); - }); - } - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - - image?.Dispose(); - upload?.Dispose(); - } - - protected override bool OnDragStart(DragStartEvent e) - { - return e.Button == MouseButton.Left; - } - - protected override void OnDrag(DragEvent e) - { - if (e.Button == MouseButton.Left) - { - float maxX = hitResults.DrawWidth / 2f * hitResults.Scale.X; - hitResults.X += e.Delta.X; - hitResults.X = MathHelper.Clamp(hitResults.X, -maxX, maxX); - - float maxY = hitResults.DrawHeight / 2f * hitResults.Scale.Y; - hitResults.Y += e.Delta.Y; - hitResults.Y = MathHelper.Clamp(hitResults.Y, -maxY, maxY); - } - } - - protected override bool OnScroll(ScrollEvent e) - { - var scale = MathHelper.Clamp(hitResults.Scale.X + e.ScrollDelta.Y / 2f, 1f, max_zoom); - hitResults.ScaleTo(scale, 100, Easing.OutQuint); - float maxX = hitResults.DrawWidth / 2f * scale; - float maxY = hitResults.DrawHeight / 2f * scale; - - if (Math.Abs(hitResults.X) >= maxX) - { - hitResults.MoveToX(MathHelper.Clamp(hitResults.X, -maxX, maxX), 100, Easing.OutQuint); - } - - if (Math.Abs(hitResults.Y) >= maxY) - { - hitResults.MoveToY(MathHelper.Clamp(hitResults.Y, -maxY, maxY), 100, Easing.OutQuint); - } - - return true; - } - - protected override bool OnMouseDown(MouseDownEvent e) - { - if (e.Button == MouseButton.Right) - { - hitResults.ScaleTo(1f, 200, Easing.OutQuint); - hitResults.MoveTo(Vector2.Zero, 200, Easing.OutQuint); - return true; - } - - return false; - } -} diff --git a/fluXis.Game/Screens/Result/UI/ResultJudgement.cs b/fluXis.Game/Screens/Result/UI/ResultJudgement.cs deleted file mode 100644 index 1ffab580..00000000 --- a/fluXis.Game/Screens/Result/UI/ResultJudgement.cs +++ /dev/null @@ -1,38 +0,0 @@ -using fluXis.Game.Graphics.Sprites; -using fluXis.Game.Skinning; -using fluXis.Shared.Scoring.Enums; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osuTK; - -namespace fluXis.Game.Screens.Result.UI; - -public partial class ResultJudgement : FillFlowContainer -{ - public Judgement Judgement { get; init; } - public new int Count { get; init; } - - [BackgroundDependencyLoader] - private void load(SkinManager skinManager) - { - Direction = FillDirection.Horizontal; - AutoSizeAxes = Axes.Both; - Spacing = new Vector2(5, 0); - - AddRange(new Drawable[] - { - new FluXisSpriteText - { - Text = Judgement.ToString(), - FontSize = 24, - Colour = skinManager.SkinJson.GetColorForJudgement(Judgement) - }, - new FluXisSpriteText - { - Text = Count.ToString(), - FontSize = 24 - } - }); - } -} diff --git a/fluXis.Game/Screens/Result/UI/ResultScore.cs b/fluXis.Game/Screens/Result/UI/ResultScore.cs deleted file mode 100644 index 8fde5cec..00000000 --- a/fluXis.Game/Screens/Result/UI/ResultScore.cs +++ /dev/null @@ -1,110 +0,0 @@ -using fluXis.Game.Graphics.Sprites; -using fluXis.Game.Map; -using fluXis.Game.Skinning; -using fluXis.Shared.Scoring; -using fluXis.Shared.Scoring.Enums; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osuTK; -using osuTK.Graphics; - -namespace fluXis.Game.Screens.Result.UI; - -public partial class ResultScore : FillFlowContainer -{ - public MapInfo MapInfo { get; init; } - public ScoreInfo Score { get; init; } - - private FluXisSpriteText scoreText; - private FluXisSpriteText accuracyText; - private FluXisSpriteText comboText; - - private int score = 0; - private float accuracy = 0; - private int combo = 0; - - [BackgroundDependencyLoader] - private void load(SkinManager skinManager) - { - AutoSizeAxes = Axes.Both; - Direction = FillDirection.Vertical; - Anchor = Anchor.TopCentre; - Origin = Anchor.TopCentre; - Spacing = new Vector2(0, -20); - - AddRange(new Drawable[] - { - scoreText = new FluXisSpriteText - { - FontSize = 80, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre - }, - accuracyText = new FluXisSpriteText - { - FontSize = 40, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre - }, - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Spacing = new Vector2(10, 0), - Margin = new MarginPadding { Top = 20 }, - Children = new Drawable[] - { - new ResultJudgement { Judgement = Judgement.Flawless, Count = Score.Flawless }, - new ResultJudgement { Judgement = Judgement.Perfect, Count = Score.Perfect }, - new ResultJudgement { Judgement = Judgement.Great, Count = Score.Great }, - new ResultJudgement { Judgement = Judgement.Alright, Count = Score.Alright }, - new ResultJudgement { Judgement = Judgement.Okay, Count = Score.Okay }, - new ResultJudgement { Judgement = Judgement.Miss, Count = Score.Miss } - } - }, - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Spacing = new Vector2(10, 0), - Margin = new MarginPadding { Top = 15 }, - Children = new[] - { - new FluXisSpriteText - { - FontSize = 24, - Text = "Max Combo" - }, - comboText = new FluXisSpriteText - { - FontSize = 24, - Colour = Score.FullFlawless ? skinManager.SkinJson.GetColorForJudgement(Judgement.Flawless) : Score.FullCombo ? skinManager.SkinJson.GetColorForJudgement(Judgement.Great) : Color4.White - } - } - } - }); - } - - protected override void LoadComplete() - { - this.TransformTo(nameof(score), Score.Score, 1000, Easing.OutQuint); - this.TransformTo(nameof(accuracy), Score.Accuracy, 800, Easing.OutQuint); - this.TransformTo(nameof(combo), Score.MaxCombo, 800, Easing.OutQuint); - - base.LoadComplete(); - } - - protected override void Update() - { - scoreText.Text = score.ToString().PadLeft(7, "0"[0]); - accuracyText.Text = $"{Score.Rank} - {accuracy:00.00}%".Replace(",", "."); - comboText.Text = $"{combo}/{MapInfo.MaxCombo}"; - - base.Update(); - } -} diff --git a/fluXis.Game/Screens/Result/UI/ResultTitle.cs b/fluXis.Game/Screens/Result/UI/ResultTitle.cs deleted file mode 100644 index c0d45166..00000000 --- a/fluXis.Game/Screens/Result/UI/ResultTitle.cs +++ /dev/null @@ -1,146 +0,0 @@ -using fluXis.Game.Database.Maps; -using fluXis.Game.Graphics.Drawables; -using fluXis.Game.Graphics.Sprites; -using fluXis.Game.Graphics.UserInterface.Color; -using fluXis.Game.Map.Drawables; -using fluXis.Shared.Components.Users; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osuTK; - -namespace fluXis.Game.Screens.Result.UI; - -public partial class ResultTitle : Container -{ - private readonly RealmMap map; - public APIUser User { get; init; } - - public ResultTitle(RealmMap map) - { - this.map = map; - } - - [BackgroundDependencyLoader] - private void load() - { - AutoSizeAxes = Axes.Y; - RelativeSizeAxes = Axes.X; - - InternalChild = new GridContainer - { - ColumnDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize), - new Dimension(GridSizeMode.AutoSize), - new Dimension(), - new Dimension(GridSizeMode.AutoSize) - }, - RowDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize) - }, - AutoSizeAxes = Axes.Y, - RelativeSizeAxes = Axes.X, - Content = new[] - { - new[] - { - new Container - { - Size = new Vector2(80), - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Margin = new MarginPadding { Right = 10 }, - CornerRadius = 10, - Masking = true, - Child = new MapCover(map.MapSet) - { - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre - } - }, - new Container - { - AutoSizeAxes = Axes.Y, - Width = 500, - Y = -2, - Children = new Drawable[] - { - new TruncatingText - { - Text = map.Metadata.Title, - FontSize = 40, - RelativeSizeAxes = Axes.X - }, - new TruncatingText - { - Text = map.Metadata.Artist, - FontSize = 26, - Colour = FluXisColors.Text2, - RelativeSizeAxes = Axes.X, - Margin = new MarginPadding { Top = 33 } - }, - new TruncatingText - { - Text = $"[{map.Difficulty}] mapped by {map.Metadata.Mapper}", - FontSize = 22, - Colour = FluXisColors.Text2, - RelativeSizeAxes = Axes.X, - Margin = new MarginPadding { Top = 58 } - } - } - }, - Empty(), - new Container - { - AutoSizeAxes = Axes.Both, - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - Children = new Drawable[] - { - new Container - { - Margin = new MarginPadding { Right = 60 }, - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - AutoSizeAxes = Axes.Both, - Children = new Drawable[] - { - new FluXisSpriteText - { - Text = "Played by", - FontSize = 16, - Colour = FluXisColors.Text2, - Anchor = Anchor.CentreRight, - Origin = Anchor.BottomRight - }, - new FluXisSpriteText - { - Text = User?.Username ?? "Guest", - FontSize = 22, - Anchor = Anchor.CentreRight, - Origin = Anchor.TopRight - } - } - }, - new Container - { - AutoSizeAxes = Axes.Both, - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - CornerRadius = 10, - Masking = true, - Child = new DrawableAvatar(User) - { - Size = new Vector2(50) - } - } - } - } - } - } - }; - } -} diff --git a/fluXis.Game/Screens/Result/UI/ResultsRatingInfo.cs b/fluXis.Game/Screens/Result/UI/ResultsRatingInfo.cs deleted file mode 100644 index 7b83fca1..00000000 --- a/fluXis.Game/Screens/Result/UI/ResultsRatingInfo.cs +++ /dev/null @@ -1,194 +0,0 @@ -using fluXis.Game.Graphics.Sprites; -using fluXis.Game.Graphics.UserInterface; -using fluXis.Game.Graphics.UserInterface.Color; -using fluXis.Game.Online.API; -using fluXis.Shared.API.Responses.Scores; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osuTK; - -namespace fluXis.Game.Screens.Result.UI; - -public partial class ResultsRatingInfo : Container -{ - private readonly bool showPlayData; - - public APIResponse ScoreResponse - { - set => Schedule(() => - { - if (!showPlayData) - return; - - loadingIcon.FadeOut(200); - ratingContainer.FadeOut(); - text.FadeOut(); - - if (!value.Success) - { - text.Text = value.Message; - text.FadeIn(200); - return; - } - - /*var ovrc = value.Data.OverallRatingChange; - var pvrc = value.Data.PotentialRatingChange; - - ovr.Text = value.Data.OverallRating.ToStringInvariant(); - pvr.Text = value.Data.PotentialRating.ToStringInvariant(); - - switch (ovrc) - { - case > 0: - ovrChange.Colour = Colour4.FromHex("#55FF55"); - ovrChange.Text = "+" + ovrc.ToStringInvariant("0.00"); - break; - - case < 0: - ovrChange.Colour = Colour4.FromHex("#FF5555"); - ovrChange.Text = ovrc.ToStringInvariant("0.00"); - break; - - default: - ovrChange.Colour = FluXisColors.Text2; - ovrChange.Text = "SAME"; - break; - }*/ - - /*switch (pvrc) - { - case > 0: - pvrChange.Colour = Colour4.FromHex("#55FF55"); - pvrChange.Text = "+" + pvrc.ToStringInvariant("0.00"); - break; - - case < 0: - pvrChange.Colour = Colour4.FromHex("#FF5555"); - pvrChange.Text = pvrc.ToStringInvariant("0.00"); - break; - - default: - pvrChange.Colour = FluXisColors.Text2; - pvrChange.Text = "KEEP"; - break; - }*/ - - ratingContainer.FadeIn(200); - }); - } - - private FluXisSpriteText text; - private LoadingIcon loadingIcon; - private FillFlowContainer ratingContainer; - private FluXisSpriteText ovr; - private FluXisSpriteText ovrChange; - private FluXisSpriteText pvr; - private FluXisSpriteText pvrChange; - - public ResultsRatingInfo(bool showPlayData) - { - this.showPlayData = showPlayData; - } - - [BackgroundDependencyLoader] - private void load() - { - RelativeSizeAxes = Axes.X; - Height = 80; - - Children = new Drawable[] - { - text = new FluXisSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Text = showPlayData ? "" : "Rating data not available!", - Alpha = showPlayData ? 0 : 1 - }, - loadingIcon = new LoadingIcon - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Size = new Vector2(40), - Alpha = showPlayData ? 1 : 0 - }, - ratingContainer = new FillFlowContainer - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(10), - Alpha = 0, - Children = new Drawable[] - { - new Container - { - Width = 200, - AutoSizeAxes = Axes.Y, - Children = new Drawable[] - { - new FluXisSpriteText - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Text = "Overall Rating", - FontSize = 14, - Colour = FluXisColors.Text2 - }, - ovr = new FluXisSpriteText - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Text = "0.00", - FontSize = 32, - Y = 10 - }, - ovrChange = new FluXisSpriteText - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Text = "", - FontSize = 20, - Y = 38 - } - } - }, - new Container - { - Width = 200, - AutoSizeAxes = Axes.Y, - Children = new Drawable[] - { - new FluXisSpriteText - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Text = "Potential Rating", - FontSize = 14, - Colour = FluXisColors.Text2 - }, - pvr = new FluXisSpriteText - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Text = "0.00", - FontSize = 32, - Y = 10 - }, - pvrChange = new FluXisSpriteText - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Text = "", - FontSize = 20, - Y = 38 - } - } - } - } - } - }; - } -} diff --git a/fluXis.Game/Screens/Result/UI/ResultsScrollForMore.cs b/fluXis.Game/Screens/Result/UI/ResultsScrollForMore.cs deleted file mode 100644 index 5dafbfc5..00000000 --- a/fluXis.Game/Screens/Result/UI/ResultsScrollForMore.cs +++ /dev/null @@ -1,54 +0,0 @@ -using fluXis.Game.Graphics.Sprites; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Sprites; -using osuTK; - -namespace fluXis.Game.Screens.Result.UI; - -public partial class ResultsScrollForMore : CompositeDrawable -{ - [BackgroundDependencyLoader] - private void load() - { - AutoSizeAxes = Axes.X; - Height = 100; // maybe figure out a way to make this dynamic - - InternalChild = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(10), - Children = new Drawable[] - { - new SpriteIcon - { - Icon = FontAwesome.Solid.AngleDoubleDown, - Size = new Vector2(25), - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Shadow = true - }, - new FluXisSpriteText - { - Text = "Scroll down for more", - WebFontSize = 20, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Shadow = true - }, - new SpriteIcon - { - Icon = FontAwesome.Solid.AngleDoubleDown, - Size = new Vector2(25), - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Shadow = true - } - } - }; - } -} diff --git a/fluXis.Game/Screens/Select/Info/Scores/ScoreListEntry.cs b/fluXis.Game/Screens/Select/Info/Scores/ScoreListEntry.cs index 056bd30b..d15a9df4 100644 --- a/fluXis.Game/Screens/Select/Info/Scores/ScoreListEntry.cs +++ b/fluXis.Game/Screens/Select/Info/Scores/ScoreListEntry.cs @@ -15,6 +15,7 @@ using fluXis.Game.Overlay.User; using fluXis.Game.Skinning; using fluXis.Game.Utils; +using fluXis.Game.Utils.Extensions; using fluXis.Shared.Components.Users; using fluXis.Shared.Scoring; using fluXis.Shared.Scoring.Enums; @@ -362,31 +363,7 @@ protected override void LoadComplete() .MoveToX(0, 500, Easing.OutQuint).FadeIn(400); if (ScoreInfo.Rank == ScoreRank.X) - { - const float len = 1000; - - var colors = new[] - { - Colour4.FromHSL(0, 1, .66f), - Colour4.FromHSL(60 / 360f, 1, .66f), - Colour4.FromHSL(120 / 360f, 1, .66f), - Colour4.FromHSL(180 / 360f, 1, .66f), - Colour4.FromHSL(240 / 360f, 1, .66f), - Colour4.FromHSL(300 / 360f, 1, .66f), - }; - - rankBackground.Colour = colors[0]; - - var seq = rankBackground.FadeColour(colors[1], len); - - for (var i = 2; i < colors.Length + 2; i++) - { - var col = colors[i % colors.Length]; - seq.Then().FadeColour(col, len); - } - - seq.Loop(); - } + rankBackground.Rainbow(); } protected override void Update() diff --git a/fluXis.Game/Skinning/Custom/CustomSkin.cs b/fluXis.Game/Skinning/Custom/CustomSkin.cs index 692286e0..fb4331f0 100644 --- a/fluXis.Game/Skinning/Custom/CustomSkin.cs +++ b/fluXis.Game/Skinning/Custom/CustomSkin.cs @@ -264,6 +264,8 @@ public AbstractJudgementText GetJudgement(Judgement judgement, bool isLate) return null; } + public Drawable GetResultsScoreRank(ScoreRank rank) => null; + public Sample GetHitSample() => samples.Get("Samples/Gameplay/hit"); public Sample[] GetMissSamples() diff --git a/fluXis.Game/Skinning/Default/DefaultSkin.cs b/fluXis.Game/Skinning/Default/DefaultSkin.cs index e2002b9b..74f035ea 100644 --- a/fluXis.Game/Skinning/Default/DefaultSkin.cs +++ b/fluXis.Game/Skinning/Default/DefaultSkin.cs @@ -8,6 +8,7 @@ using fluXis.Game.Skinning.Default.Judgements; using fluXis.Game.Skinning.Default.Lighting; using fluXis.Game.Skinning.Default.Receptor; +using fluXis.Game.Skinning.Default.Results; using fluXis.Game.Skinning.Default.Stage; using fluXis.Game.Skinning.Json; using fluXis.Shared.Scoring.Enums; @@ -104,6 +105,8 @@ public Drawable GetReceptor(int lane, int keyCount, bool down) public Drawable GetHitLine() => new DefaultHitLine(SkinJson); public AbstractJudgementText GetJudgement(Judgement judgement, bool isLate) => new DefaultJudgementText(judgement, isLate); + public Drawable GetResultsScoreRank(ScoreRank rank) => new DefaultResultsRank(rank); + public Sample GetHitSample() => samples.Get("Gameplay/hitsound"); public Sample[] GetMissSamples() => new[] { samples.Get("Gameplay/combobreak") }; public Sample GetFailSample() => samples.Get("Gameplay/fail"); diff --git a/fluXis.Game/Skinning/Default/Results/DefaultResultsRank.cs b/fluXis.Game/Skinning/Default/Results/DefaultResultsRank.cs new file mode 100644 index 00000000..77deac5d --- /dev/null +++ b/fluXis.Game/Skinning/Default/Results/DefaultResultsRank.cs @@ -0,0 +1,74 @@ +using fluXis.Game.Utils.Extensions; +using fluXis.Shared.Scoring.Enums; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; +using osuTK; + +namespace fluXis.Game.Skinning.Default.Results; + +public partial class DefaultResultsRank : CompositeDrawable +{ + private ScoreRank rank { get; } + + private Sprite inner; + private Sprite mid; + private Sprite outer; + private Sprite rankSpr; + + public DefaultResultsRank(ScoreRank rank) + { + this.rank = rank; + } + + [BackgroundDependencyLoader] + private void load(TextureStore textures) + { + InternalChildren = new Drawable[] + { + outer = new Sprite + { + Size = new Vector2(1800), + Texture = textures.Get("Results/outer-circle"), + Origin = Anchor.Centre, + Blending = BlendingParameters.Additive, + Alpha = .3f + }, + mid = new Sprite + { + Size = new Vector2(400), + Texture = textures.Get("Results/circle"), + Origin = Anchor.Centre, + Blending = BlendingParameters.Additive, + Alpha = .3f + }, + inner = new Sprite + { + Size = new Vector2(320), + Texture = textures.Get("Results/inner-circle"), + Origin = Anchor.Centre, + Blending = BlendingParameters.Additive, + Alpha = .3f + }, + rankSpr = new Sprite + { + Size = new Vector2(160), + Texture = textures.Get($"Results/rank-{rank.ToString().ToLower()}"), + Origin = Anchor.Centre + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + outer.Spin(20000, RotationDirection.Clockwise); + mid.Spin(12000, RotationDirection.Clockwise); + inner.Spin(10000, RotationDirection.Clockwise); + + if (rank == ScoreRank.X) + rankSpr.Rainbow(); + } +} diff --git a/fluXis.Game/Skinning/ISkin.cs b/fluXis.Game/Skinning/ISkin.cs index afb7b936..b42c43d1 100644 --- a/fluXis.Game/Skinning/ISkin.cs +++ b/fluXis.Game/Skinning/ISkin.cs @@ -39,6 +39,8 @@ public interface ISkin : IDisposable public AbstractJudgementText GetJudgement(Judgement judgement, bool isLate); + public Drawable GetResultsScoreRank(ScoreRank rank); + public Sample GetHitSample(); public Sample[] GetMissSamples(); public Sample GetFailSample(); diff --git a/fluXis.Game/Skinning/SkinManager.cs b/fluXis.Game/Skinning/SkinManager.cs index 9937cf37..8275f992 100644 --- a/fluXis.Game/Skinning/SkinManager.cs +++ b/fluXis.Game/Skinning/SkinManager.cs @@ -281,6 +281,8 @@ private ISkin loadSkin(string folder) public Drawable GetHitLine() => currentSkin.GetHitLine() ?? defaultSkin.GetHitLine(); public AbstractJudgementText GetJudgement(Judgement judgement, bool isLate) => currentSkin.GetJudgement(judgement, isLate) ?? defaultSkin.GetJudgement(judgement, isLate); + public Drawable GetResultsScoreRank(ScoreRank rank) => currentSkin.GetResultsScoreRank(rank) ?? defaultSkin.GetResultsScoreRank(rank); + public Sample GetHitSample() => currentSkin.GetHitSample() ?? defaultSkin.GetHitSample(); public Sample[] GetMissSamples() => currentSkin.GetMissSamples() ?? defaultSkin.GetMissSamples(); public Sample GetFailSample() => currentSkin.GetFailSample() ?? defaultSkin.GetFailSample(); diff --git a/fluXis.Game/Utils/Extensions/DrawableExtensions.cs b/fluXis.Game/Utils/Extensions/DrawableExtensions.cs index d718e753..c0028382 100644 --- a/fluXis.Game/Utils/Extensions/DrawableExtensions.cs +++ b/fluXis.Game/Utils/Extensions/DrawableExtensions.cs @@ -40,6 +40,39 @@ public static void Vibrate(this Drawable target, double duration, float magnitud .Then().MoveToX(0, duration / 2, Easing.InSine); } + public static void Rainbow(this Drawable drawable) + { + const float len = 800; + + var colors = new[] + { + Colour4.FromHSL(0, 1, .66f), + Colour4.FromHSL(30 / 360f, 1, .66f), + Colour4.FromHSL(60 / 360f, 1, .66f), + Colour4.FromHSL(90 / 360f, 1, .66f), + Colour4.FromHSL(120 / 360f, 1, .66f), + Colour4.FromHSL(150 / 360f, 1, .66f), + Colour4.FromHSL(180 / 360f, 1, .66f), + Colour4.FromHSL(210 / 360f, 1, .66f), + Colour4.FromHSL(240 / 360f, 1, .66f), + Colour4.FromHSL(270 / 360f, 1, .66f), + Colour4.FromHSL(300 / 360f, 1, .66f), + Colour4.FromHSL(330 / 360f, 1, .66f), + }; + + drawable.Colour = colors[0]; + + var seq = drawable.FadeColour(colors[1], len); + + for (var i = 2; i < colors.Length + 2; i++) + { + var col = colors[i % colors.Length]; + seq.Then().FadeColour(col, len); + } + + seq.Loop(); + } + public static void RunOnUpdate(this Drawable _, Scheduler scheduler, Action action) { if (ThreadSafety.IsUpdateThread) diff --git a/fluXis.Resources/Textures/Results/circle.png b/fluXis.Resources/Textures/Results/circle.png new file mode 100644 index 00000000..4b225192 Binary files /dev/null and b/fluXis.Resources/Textures/Results/circle.png differ diff --git a/fluXis.Resources/Textures/Results/inner-circle.png b/fluXis.Resources/Textures/Results/inner-circle.png new file mode 100644 index 00000000..d34593d8 Binary files /dev/null and b/fluXis.Resources/Textures/Results/inner-circle.png differ diff --git a/fluXis.Resources/Textures/Results/outer-circle.png b/fluXis.Resources/Textures/Results/outer-circle.png new file mode 100644 index 00000000..51bdcf93 Binary files /dev/null and b/fluXis.Resources/Textures/Results/outer-circle.png differ diff --git a/fluXis.Resources/Textures/Results/rank-a.png b/fluXis.Resources/Textures/Results/rank-a.png new file mode 100644 index 00000000..e9e6247e Binary files /dev/null and b/fluXis.Resources/Textures/Results/rank-a.png differ diff --git a/fluXis.Resources/Textures/Results/rank-aa.png b/fluXis.Resources/Textures/Results/rank-aa.png new file mode 100644 index 00000000..95315f44 Binary files /dev/null and b/fluXis.Resources/Textures/Results/rank-aa.png differ diff --git a/fluXis.Resources/Textures/Results/rank-b.png b/fluXis.Resources/Textures/Results/rank-b.png new file mode 100644 index 00000000..08bac64c Binary files /dev/null and b/fluXis.Resources/Textures/Results/rank-b.png differ diff --git a/fluXis.Resources/Textures/Results/rank-c.png b/fluXis.Resources/Textures/Results/rank-c.png new file mode 100644 index 00000000..2974380d Binary files /dev/null and b/fluXis.Resources/Textures/Results/rank-c.png differ diff --git a/fluXis.Resources/Textures/Results/rank-d.png b/fluXis.Resources/Textures/Results/rank-d.png new file mode 100644 index 00000000..7249dbc0 Binary files /dev/null and b/fluXis.Resources/Textures/Results/rank-d.png differ diff --git a/fluXis.Resources/Textures/Results/rank-s.png b/fluXis.Resources/Textures/Results/rank-s.png new file mode 100644 index 00000000..76bf0dd1 Binary files /dev/null and b/fluXis.Resources/Textures/Results/rank-s.png differ diff --git a/fluXis.Resources/Textures/Results/rank-ss.png b/fluXis.Resources/Textures/Results/rank-ss.png new file mode 100644 index 00000000..2d1cdd32 Binary files /dev/null and b/fluXis.Resources/Textures/Results/rank-ss.png differ diff --git a/fluXis.Resources/Textures/Results/rank-x.png b/fluXis.Resources/Textures/Results/rank-x.png new file mode 100644 index 00000000..5563c2a0 Binary files /dev/null and b/fluXis.Resources/Textures/Results/rank-x.png differ