/// <summary> /// Updates the text of the metadata with a new map/mods /// Realigns it so it's in the middle. /// </summary> /// <param name="map"></param> public void UpdateAndAlignMetadata(Map map) { var length = TimeSpan.FromMilliseconds(map.SongLength / ModHelper.GetRateFromMods(ModManager.Mods)); Mode.UpdateValue(ModeHelper.ToShortHand(map.Mode)); Bpm.UpdateValue(((int)(map.Bpm * ModHelper.GetRateFromMods(ModManager.Mods))).ToString(CultureInfo.InvariantCulture)); Length.UpdateValue(length.Hours > 0 ? length.ToString(@"hh\:mm\:ss") : length.ToString(@"mm\:ss")); Difficulty.UpdateValue(StringHelper.AccuracyToString((float) map.DifficultyFromMods(ModManager.Mods)).Replace("%", "")); LNPercentage.UpdateValue(((int) map.LNPercentage).ToString(CultureInfo.InvariantCulture) + "%"); for (var i = 0; i < Items.Count; i++) { var metadata = Items[i]; if (i == 0) { metadata.X = 5; continue; } var previous = Items[i - 1]; metadata.X = previous.X + previous.Width + 5 + 5; } Items.ForEach(x => x.X += (Banner.Width - Items.Last().X) / Items.Count / 2); }
/// <summary> /// Creates all of the main ite /// </summary> private void CreateKeyValueItems() { double performanceRating; switch (Screen.ResultsType) { case ResultScreenType.Gameplay: case ResultScreenType.Replay: if (Screen.ScoreProcessor.Failed) { performanceRating = 0; } else { performanceRating = new RatingProcessorKeys(MapManager.Selected.Value.DifficultyFromMods(Screen.ScoreProcessor.Mods)) .CalculateRating(Screen.ScoreProcessor); } break; case ResultScreenType.Score: performanceRating = Screen.Score.PerformanceRating; break; default: throw new ArgumentOutOfRangeException(); } ResultKeyValueItems = new List <ResultKeyValueItem>() { new ResultKeyValueItem(ResultKeyValueItemType.Vertical, "SCORE RATING", $"{performanceRating:F}"), new ResultKeyValueItem(ResultKeyValueItemType.Vertical, "TOTAL SCORE", $"{Screen.ScoreProcessor.Score:N0}"), new ResultKeyValueItem(ResultKeyValueItemType.Vertical, "ACCURACY", StringHelper.AccuracyToString(Screen.ScoreProcessor.Accuracy)), new ResultKeyValueItem(ResultKeyValueItemType.Vertical, "MAX COMBO", $"{Screen.ScoreProcessor.MaxCombo}x"), }; for (var i = 0; i < ResultKeyValueItems.Count; i++) { var item = ResultKeyValueItems[i]; item.Parent = this; item.Y = TopHorizontalDividerLine.Y + 15; item.X = VerticalDividerLine.X / ResultKeyValueItems.Count * i + 40; } // Add a divider line at the bottom of the key value items var firstItem = ResultKeyValueItems.First(); ResultKeyValueItemDividerLine = new Sprite { Parent = this, Y = firstItem.Y + firstItem.TextValue.Y + firstItem.TextValue.Height + 15, Size = new ScalableVector2(VerticalDividerLine.X, 1), Alpha = 0.45f }; }
/// <summary> /// Creates the accuracy display sprite. /// </summary> private void CreateAccuracyDisplay() { var skin = SkinManager.Skin.Keys[Screen.Map.Mode]; AccuracyDisplay = new NumberDisplay(NumberDisplayType.Accuracy, StringHelper.AccuracyToString(0), new Vector2(skin.AccuracyDisplayScale / 100f, skin.AccuracyDisplayScale / 100f), SkinManager.Skin.Keys[Screen.Map.Mode].AccuracyDisplayPosX) { Parent = Container, Alignment = Alignment.TopRight, }; }
/// <summary> /// Creates the accuracy display sprite. /// </summary> private void CreateAccuracyDisplay() { AccuracyDisplay = new NumberDisplay(NumberDisplayType.Accuracy, StringHelper.AccuracyToString(0), new Vector2(0.45f, 0.45f)) { Parent = Container, Alignment = Alignment.TopRight, }; // Set the position of the accuracy display. AccuracyDisplay.X = -AccuracyDisplay.TotalWidth + SkinManager.Skin.Keys[Screen.Map.Mode].AccuracyDisplayPosX; AccuracyDisplay.Y = SkinManager.Skin.Keys[Screen.Map.Mode].AccuracyDisplayPosY; }
/// <summary> /// Updates the information of the map with a new one. /// </summary> /// <param name="map"></param> public void UpdateWithNewMap(Map map) { Map = map; DifficultyName.Text = map.DifficultyName; var difficulty = (float)map.DifficultyFromMods(ModManager.Mods); TextDifficultyRating.Text = StringHelper.AccuracyToString(difficulty).Replace("%", ""); TextDifficultyRating.Tint = ColorHelper.DifficultyToColor(difficulty); Creator.Text = $"By: {map.Creator}"; }
/// <summary> /// Adds all of the online stats after submitting the score /// </summary> /// <param name="score"></param> private void AddStatsAfterSubmission(ScoreSubmissionResponse score) { if (score.Map.Md5 != MapManager.Selected.Value.Md5Checksum) { return; } Stats = new List <ResultKeyValueItem>() { new ResultKeyValueItem(ResultKeyValueItemType.Horizontal, "MAP RANK:", score.Score.Rank == -1 ? "N/A" : $"#{score.Score.Rank:n0}"), new ResultKeyValueItem(ResultKeyValueItemType.Horizontal, "GLOBAL RANK:", $"#{score.Stats.NewGlobalRank:n0}"), new ResultKeyValueItem(ResultKeyValueItemType.Horizontal, "COUNTRY RANK:", $"#{score.Stats.NewGlobalRank:n0}"), new ResultKeyValueItem(ResultKeyValueItemType.Horizontal, "OVL. RATING:", $"{score.Stats.OverallPerformanceRating:0.00}"), new ResultKeyValueItem(ResultKeyValueItemType.Horizontal, "OVL. ACCURACY:", $"{StringHelper.AccuracyToString((float) score.Stats.OverallAccuracy)}"), }; var totalWidth = 0f; for (var i = 0; i < Stats.Count; i++) { var item = Stats[i]; item.Parent = this; item.Alignment = Alignment.MidLeft; totalWidth += item.Width; item.TextKey.Alpha = 0; item.TextValue.Alpha = 0; item.TextKey.Animations.Add(new Animation(AnimationProperty.Alpha, Easing.Linear, item.TextKey.Alpha, 1, 300)); item.TextValue.Animations.Add(new Animation(AnimationProperty.Alpha, Easing.Linear, item.TextValue.Alpha, 1, 300)); if (i == 0) { continue; } var last = Stats[i - 1]; item.Parent = last; item.X = last.Width + 50; totalWidth += 50; } Stats.First().X = Width / 2f - totalWidth / 2f; }
/// <summary> /// Updates the values and positions of the score and accuracy displays. /// </summary> public void UpdateScoreAndAccuracyDisplays() { // Update score and accuracy displays ScoreDisplay.Value = StringHelper.ScoreToString(Screen.Ruleset.ScoreProcessor.Score); // Grab the old accuracy var oldAcc = AccuracyDisplay.Value; // Update the new accuracy. AccuracyDisplay.Value = StringHelper.AccuracyToString(Screen.Ruleset.ScoreProcessor.Accuracy); // If the old accuracy's length isn't the same, then we need to reposition the sprite // Example: 100.00% to 99.99% needs repositioning. if (oldAcc.Length != AccuracyDisplay.Value.Length) { AccuracyDisplay.X = -AccuracyDisplay.TotalWidth + SkinManager.Skin.Keys[Screen.Map.Mode].AccuracyDisplayPosX; } }
/// <summary> /// Called when the activated modifiers have changed. /// Used for updating difficulty values. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void OnModsChanged(object sender, ModsChangedEventArgs e) { if (Map == null) { return; } var difficulty = (float)Map.DifficultyFromMods(ModManager.Mods); var value = StringHelper.AccuracyToString(difficulty).Replace("%", ""); // Don't bother updating the text if the difficulty value is the same as what's already there if (value == TextDifficultyRating.Text) { return; } TextDifficultyRating.Text = value; TextDifficultyRating.Tint = ColorHelper.DifficultyToColor(difficulty); }
/// <summary> /// Changes discord rich presence to show results. /// </summary> private void ChangeDiscordPresence() { DiscordHelper.Presence.EndTimestamp = 0; // Don't change if we're loading in from a replay file. if (ResultsType == ResultScreenType.Replay || Gameplay.InReplayMode) { DiscordHelper.Presence.Details = "Idle"; DiscordHelper.Presence.State = "In the Menus"; DiscordRpc.UpdatePresence(ref DiscordHelper.Presence); return; } var state = Gameplay.Failed ? "Fail" : "Pass"; var score = $"{ScoreProcessor.Score / 1000}k"; var acc = $"{StringHelper.AccuracyToString(ScoreProcessor.Accuracy)}"; var grade = Gameplay.Failed ? "F" : GradeHelper.GetGradeFromAccuracy(ScoreProcessor.Accuracy).ToString(); var combo = $"{ScoreProcessor.MaxCombo}x"; if (OnlineManager.CurrentGame == null) { DiscordHelper.Presence.State = $"{state}: {grade} {score} {acc} {combo}"; } else { if (OnlineManager.CurrentGame.Ruleset == MultiplayerGameRuleset.Team) { var redTeamAverage = GetTeamAverage(MultiplayerTeam.Red); var blueTeamAverage = GetTeamAverage(MultiplayerTeam.Blue); DiscordHelper.Presence.State = $"Red: {redTeamAverage:0.00} vs. Blue: {blueTeamAverage:0.00}"; } else { DiscordHelper.Presence.State = $"{StringHelper.AddOrdinal(MultiplayerScores.First().Rank)} " + $"Place: {MultiplayerScores.First().RatingProcessor.CalculateRating(ScoreProcessor):0.00} {acc} {grade}"; } } DiscordRpc.UpdatePresence(ref DiscordHelper.Presence); }
/// <summary> /// Calculates score for a given object. Essentially it just calcs for the next Hitstat. /// </summary> internal void CalculateScoreForNextObject(bool setScoreboardValues = true) { if (setScoreboardValues && Type == ScoreboardUserType.Self) { var oldProcessor = Processor; Processor = Screen.Ruleset.StandardizedReplayPlayer.ScoreProcessor; var rating = CalculateRating(); Processor = oldProcessor; Score.Text = $"{StringHelper.RatingToString(rating)} / {StringHelper.AccuracyToString(Processor.Accuracy)}"; Combo.Text = Processor.Combo.ToString("N0") + "x"; SetTintBasedOnHealth(); Scoreboard.TeamBanner?.UpdateAverageRating(); return; } // If the user doesn't have any more judgements then don't update them. if (Judgements.Count - 1 < CurrentJudgement) { return; } var processor = (ScoreProcessorKeys)Processor; processor.CalculateScore(Judgements[CurrentJudgement]); if (setScoreboardValues) { SetTintBasedOnHealth(); var rating = CalculateRating(); Score.Text = $"{rating:0.00} / {StringHelper.AccuracyToString(Processor.Accuracy)}"; Combo.Text = Processor.Combo.ToString("N0") + "x"; Scoreboard.TeamBanner?.UpdateAverageRating(); } CurrentJudgement++; }
/// <summary> /// Changes discord rich presence to show results. /// </summary> private void ChangeDiscordPresence() { DiscordHelper.Presence.EndTimestamp = 0; // Don't change if we're loading in from a replay file. if (ResultsType == ResultScreenType.Replay || Gameplay.InReplayMode) { DiscordHelper.Presence.Details = "Idle"; DiscordHelper.Presence.State = "In the Menus"; DiscordRpc.UpdatePresence(ref DiscordHelper.Presence); return; } var state = Gameplay.Failed ? "Fail" : "Pass"; var score = $"{ScoreProcessor.Score / 1000}k"; var acc = $"{StringHelper.AccuracyToString(ScoreProcessor.Accuracy)}"; var grade = Gameplay.Failed ? "F" : GradeHelper.GetGradeFromAccuracy(ScoreProcessor.Accuracy).ToString(); var combo = $"{ScoreProcessor.MaxCombo}x"; DiscordHelper.Presence.State = $"{state}: {grade} {score} {acc} {combo}"; DiscordRpc.UpdatePresence(ref DiscordHelper.Presence); }
/// <summary> /// Calculates score for a given object. Essentially it just calcs for the next Hitstat. /// </summary> internal void CalculateScoreForNextObject() { if (Type == ScoreboardUserType.Self) { Score.Text = $"{RatingProcessor.CalculateRating(Processor.Accuracy):0.00} / {StringHelper.AccuracyToString(Processor.Accuracy)}"; Combo.Text = Processor.Combo.ToString("N0") + "x"; SetTintBasedOnHealth(); return; } // If the user doesn't have any more judgements then don't update them. if (Judgements.Count - 1 < CurrentJudgement) { return; } var processor = (ScoreProcessorKeys)Processor; processor.CalculateScore(Judgements[CurrentJudgement]); SetTintBasedOnHealth(); Score.Text = $"{RatingProcessor.CalculateRating(Processor.Accuracy):0.00} / {StringHelper.AccuracyToString(Processor.Accuracy)}"; Combo.Text = Processor.Combo.ToString("N0") + "x"; CurrentJudgement++; }
/// <summary> /// Ctor - /// </summary> /// <param name="screen"></param> internal SongInformation(GameplayScreen screen) { Screen = screen; Size = new ScalableVector2(750, 150); Tint = Colors.MainAccentInactive; Alpha = 0; // Create watching text outside of replay mode because other text relies on it. Watching = new SpriteText(Fonts.SourceSansProSemiBold, $"Watching {(screen.InReplayMode ? Screen.LoadedReplay.PlayerName : "")}", 13) { Parent = this, Alignment = Alignment.TopCenter, Y = 25, Alpha = 0 }; Title = new SpriteText(Fonts.SourceSansProSemiBold, $"{Screen.Map.Artist} - {Screen.Map.Title}", 13) { Parent = this, Alignment = Alignment.TopCenter, Y = Watching.Y + TextYSpacing + TextYSpacing, Alpha = 0, }; Difficulty = new SpriteText(Fonts.SourceSansProSemiBold, $"[{Screen.Map.DifficultyName}]", 13) { Parent = this, Alignment = Alignment.TopCenter, Y = Title.Y + TextYSpacing + TextYSpacing * 0.85f, Alpha = 0 }; Creator = new SpriteText(Fonts.SourceSansProSemiBold, $"Mapped By: \"{Screen.Map.Creator}\"", 13) { Parent = this, Alignment = Alignment.TopCenter, Y = Difficulty.Y + TextYSpacing + TextYSpacing * 0.80f, Alpha = 0 }; var difficulty = (float)MapManager.Selected.Value.DifficultyFromMods(ModManager.Mods); Rating = new SpriteText(Fonts.SourceSansProSemiBold, $"Difficulty: {StringHelper.AccuracyToString(difficulty).Replace("%", "")}", 13) { Parent = this, Alignment = Alignment.TopCenter, Y = Creator.Y + TextYSpacing + TextYSpacing * 0.75f, Alpha = 0, Tint = ColorHelper.DifficultyToColor(difficulty) }; // Get a formatted string of the activated mods. var modsString = "Mods: " + (ModManager.CurrentModifiersList.Count > 0 ? $"{ModHelper.GetModsString(ModManager.Mods)}" : "None"); Mods = new SpriteText(Fonts.SourceSansProSemiBold, modsString, 13) { Parent = this, Alignment = Alignment.TopCenter, Y = Rating.Y + TextYSpacing + TextYSpacing * 0.7f, Alpha = 0 }; }
/// <summary> /// Checks if there are new scoreboard users. /// </summary> private void CheckIfNewScoreboardUsers() { if (Screen.IsPlayTesting || StopCheckingForScoreboardUsers) { return; } var mapScores = MapManager.Selected.Value.Scores.Value; if (mapScores == null || mapScores.Count <= 0 || (ScoreboardLeft.Users?.Count < 1 && ScoreboardRight != null && ScoreboardRight.Users.Count < 1)) { return; } for (var i = 0; i < (OnlineManager.CurrentGame == null ? 4 : mapScores.Count) && i < mapScores.Count; i++) { ScoreboardUser user; // For online scores we want to just give them their score in the processor, // since we don't have access to their judgement breakdown. if (mapScores[i].IsOnline) { user = new ScoreboardUser(Screen, ScoreboardUserType.Other, $"{mapScores[i].Name}", new List <Judgement>(), UserInterface.UnknownAvatar, (ModIdentifier)mapScores[i].Mods, mapScores[i]) { Parent = Container, Alignment = Alignment.MidLeft }; if (OnlineManager.CurrentGame != null && OnlineManager.CurrentGame.Ruleset == MultiplayerGameRuleset.Team && OnlineManager.GetTeam(user.LocalScore.PlayerId) == MultiplayerTeam.Blue) { user.Scoreboard = ScoreboardRight; user.X = WindowManager.Width; } else { user.Scoreboard = ScoreboardLeft; } user.SetImage(); var processor = user.Processor as ScoreProcessorKeys; processor.Accuracy = (float)mapScores[i].Accuracy; processor.MaxCombo = mapScores[i].MaxCombo; processor.Score = mapScores[i].TotalScore; user.Score.Text = $"{user.RatingProcessor.CalculateRating(processor.Accuracy):0.00} / {StringHelper.AccuracyToString(processor.Accuracy)}"; user.Combo.Text = $"{processor.MaxCombo}x"; } // Allow the user to play against their own local scores. else { // Decompress score var breakdownHits = GzipHelper.Decompress(mapScores[i].JudgementBreakdown); var judgements = new List <Judgement>(); // Get all of the hit stats for the score. foreach (var hit in breakdownHits) { judgements.Add((Judgement)int.Parse(hit.ToString())); } user = new ScoreboardUser(Screen, ScoreboardUserType.Other, $"{mapScores[i].Name}", judgements, UserInterface.UnknownAvatar, (ModIdentifier)mapScores[i].Mods, mapScores[i]) { Parent = Container, Alignment = Alignment.MidLeft }; if (OnlineManager.CurrentGame != null && OnlineManager.CurrentGame.Ruleset == MultiplayerGameRuleset.Team && OnlineManager.GetTeam(user.LocalScore.PlayerId) == MultiplayerTeam.Blue) { user.Scoreboard = ScoreboardRight; } else { user.Scoreboard = ScoreboardLeft; } user.SetImage(); // Make sure the user's score is updated with the current user. for (var j = 0; j < Screen.Ruleset.ScoreProcessor.TotalJudgementCount && i < judgements.Count; j++) { var processor = user.Processor as ScoreProcessorKeys; processor?.CalculateScore(judgements[i]); } } if (OnlineManager.CurrentGame != null && OnlineManager.CurrentGame.Ruleset == MultiplayerGameRuleset.Team && OnlineManager.GetTeam(user.LocalScore.PlayerId) == MultiplayerTeam.Blue) { ScoreboardRight.Users.Add(user); } else { ScoreboardLeft.Users.Add(user); } } ScoreboardLeft.SetTargetYPositions(); ScoreboardRight?.SetTargetYPositions(); // Re-change the transitioner and pause screen's parent so that they appear on top of the scoreboard // again. if (ProgressBar != null) { ProgressBar.Parent = Container; } Transitioner.Parent = Container; PauseScreen.Parent = Container; StopCheckingForScoreboardUsers = true; Screen.SetRichPresence(); }
/// <inheritdoc /> /// <summary> /// </summary> /// <param name="container"></param> /// <param name="item"></param> /// <param name="index"></param> /// <param name="header"></param> public ResultMultiplayerScoreboardUser(PoolableScrollContainer <ScoreboardUser> container, ScoreboardUser item, int index, ResultMultiplayerScoreboardTableHeader header) : base(container, item, index) { Header = header; Size = new ScalableVector2(container.Width, HEIGHT); Alpha = 0.85f; Button = new ResultMultiplayerScoreboardUserButton(Item, container) { Parent = this, Size = Size, UsePreviousSpriteBatchOptions = true }; // ReSharper disable once ObjectCreationAsStatement var rank = new SpriteTextBitmap(FontsBitmap.GothamRegular, $"{item.Rank}.") { Parent = this, Alignment = Alignment.MidLeft, X = 20, FontSize = 16, Tint = Item.Type == ScoreboardUserType.Self ? Colors.SecondaryAccent : Color.White, UsePreviousSpriteBatchOptions = true }; var avatar = new Sprite { Parent = this, Alignment = Alignment.MidLeft, Size = new ScalableVector2(32, 32), X = 56, Image = item.Avatar.Image, UsePreviousSpriteBatchOptions = true }; avatar.AddBorder(Color.White, 2); var username = new SpriteTextBitmap(FontsBitmap.GothamRegular, item.UsernameRaw) { Parent = this, Alignment = Alignment.MidLeft, X = avatar.X + avatar.Width + 16, FontSize = 16, Tint = Item.Type == ScoreboardUserType.Self ? Colors.SecondaryAccent : Color.White, UsePreviousSpriteBatchOptions = true }; if (item.Processor == null) { return; } CreateData(new Dictionary <string, string> { { "Rating", item.CalculateRating().ToString("00.00") }, { "Grade", "" }, { "Accuracy", StringHelper.AccuracyToString(item.Processor.Accuracy) }, { "Max Combo", item.Processor.MaxCombo + "x" }, { "Marv", item.Processor.CurrentJudgements[Judgement.Marv].ToString() }, { "Perf", item.Processor.CurrentJudgements[Judgement.Perf].ToString() }, { "Great", item.Processor.CurrentJudgements[Judgement.Great].ToString() }, { "Good", item.Processor.CurrentJudgements[Judgement.Good].ToString() }, { "Okay", item.Processor.CurrentJudgements[Judgement.Okay].ToString() }, { "Miss", item.Processor.CurrentJudgements[Judgement.Miss].ToString() }, { "Mods", item.Processor.Mods <= 0 ? "None" : ModHelper.GetModsString(ModHelper.GetModsFromRate(ModHelper.GetRateFromMods(item.Processor.Mods))) } }); // ReSharper disable once ObjectCreationAsStatement new Sprite { Parent = this, Alignment = Alignment.BotLeft, Size = new ScalableVector2(Width, 1), Alpha = 0.3f }; }
/// <summary> /// Creates all of the main ite /// </summary> private void CreateKeyValueItems() { double performanceRating; switch (Screen.ResultsType) { case ResultScreenType.Gameplay: if (Screen.ScoreProcessor.Failed) { performanceRating = 0; } else { performanceRating = new RatingProcessorKeys(MapManager.Selected.Value.DifficultyFromMods(Screen.ScoreProcessor.Mods)).CalculateRating(Screen.Gameplay.Ruleset.StandardizedReplayPlayer.ScoreProcessor); } break; case ResultScreenType.Replay: if (Screen.ScoreProcessor.Failed) { performanceRating = 0; } else { performanceRating = new RatingProcessorKeys(MapManager.Selected.Value.DifficultyFromMods(Screen.ScoreProcessor.Mods)).CalculateRating(Screen.ScoreProcessor); } break; case ResultScreenType.Score: performanceRating = Screen.Score.PerformanceRating; break; default: throw new ArgumentOutOfRangeException(); } ResultKeyValueItem standardized = null; int spacing; const int beginPosition = 40; if (StandardizedProcessor != null || Screen.ResultsType == ResultScreenType.Score && !Screen.Score.IsOnline) { var acc = StandardizedProcessor?.Accuracy ?? Screen.Score.RankedAccuracy; standardized = new ResultKeyValueItem(ResultKeyValueItemType.Vertical, "RANKED ACCURACY", StringHelper.AccuracyToString((float)acc)); spacing = 44; } else { spacing = 100; } ResultKeyValueItems = new List <ResultKeyValueItem>() { new ResultKeyValueItem(ResultKeyValueItemType.Vertical, "SCORE RATING", $"{performanceRating:F}"), new ResultKeyValueItem(ResultKeyValueItemType.Vertical, "TOTAL SCORE", $"{Screen.ScoreProcessor.Score:N0}"), new ResultKeyValueItem(ResultKeyValueItemType.Vertical, "ACCURACY", StringHelper.AccuracyToString(Screen.ScoreProcessor.Accuracy)), }; if (standardized != null) { ResultKeyValueItems.Add(standardized); } ResultKeyValueItems.Add(new ResultKeyValueItem(ResultKeyValueItemType.Vertical, "MAX COMBO", $"{Screen.ScoreProcessor.MaxCombo}x")); for (var i = 0; i < ResultKeyValueItems.Count; i++) { var item = ResultKeyValueItems[i]; item.Parent = this; item.Y = TopHorizontalDividerLine.Y + 15; if (i == 0) { item.X = beginPosition; continue; } item.X = ResultKeyValueItems[i - 1].X + ResultKeyValueItems[i - 1].Width + spacing; } // Add a divider line at the bottom of the key value items var firstItem = ResultKeyValueItems.First(); ResultKeyValueItemDividerLine = new Sprite { Parent = this, Y = firstItem.Y + firstItem.TextValue.Y + firstItem.TextValue.Height + 15, Size = new ScalableVector2(Width, 1), Alpha = 0.45f }; }
/// <summary> /// Checks if there are new scoreboard users. /// </summary> private void CheckIfNewScoreboardUsers() { var mapScores = MapManager.Selected.Value.Scores.Value; if (mapScores == null || mapScores.Count <= 0 || Scoreboard.Users.Count != 1) { return; } for (var i = 0; i < 4 && i < mapScores.Count; i++) { ScoreboardUser user; // For online scores we want to just give them their score in the processor, // since we don't have access to their judgement breakdown. if (mapScores[i].IsOnline) { user = new ScoreboardUser(Screen, ScoreboardUserType.Other, $"{mapScores[i].Name}", new List <Judgement>(), UserInterface.UnknownAvatar, mapScores[i].Mods, mapScores[i]) { Parent = Container, Alignment = Alignment.MidLeft }; user.Scoreboard = Scoreboard; var processor = user.Processor as ScoreProcessorKeys; processor.Accuracy = (float)mapScores[i].Accuracy; processor.MaxCombo = mapScores[i].MaxCombo; processor.Score = mapScores[i].TotalScore; user.Score.Text = $"{user.RatingProcessor.CalculateRating(processor.Accuracy):0.00} / {StringHelper.AccuracyToString(processor.Accuracy)}"; user.Combo.Text = $"{processor.MaxCombo}x"; } // Allow the user to play against their own local scores. else { // Decompress score var breakdownHits = GzipHelper.Decompress(mapScores[i].JudgementBreakdown); var judgements = new List <Judgement>(); // Get all of the hit stats for the score. foreach (var hit in breakdownHits) { judgements.Add((Judgement)int.Parse(hit.ToString())); } user = new ScoreboardUser(Screen, ScoreboardUserType.Other, $"{mapScores[i].Name}", judgements, UserInterface.UnknownAvatar, mapScores[i].Mods, mapScores[i]) { Parent = Container, Alignment = Alignment.MidLeft }; user.Scoreboard = Scoreboard; // Make sure the user's score is updated with the current user. for (var j = 0; j < Screen.Ruleset.ScoreProcessor.TotalJudgementCount && i < judgements.Count; j++) { var processor = user.Processor as ScoreProcessorKeys; processor?.CalculateScore(judgements[i]); } } Scoreboard.Users.Add(user); } Scoreboard.SetTargetYPositions(); // Re-change the transitioner and pause screen's parent so that they appear on top of the scoreboard // again. Transitioner.Parent = Container; PauseScreen.Parent = Container; }
private void UpdateText() { Username.Text = OnlineManager.Status.Value != ConnectionStatus.Connected ? ConfigManager.Username.Value : OnlineManager.Self.OnlineUser.Username; GameMode.Text = ModeHelper.ToShortHand(ConfigManager.SelectedGameMode.Value); switch (OnlineManager.Status.Value) { case ConnectionStatus.Disconnected: Status.Text = "Offline"; LoadingWheel.Visible = false; break; case ConnectionStatus.Connecting: Status.Text = "Connecting. Please Wait!"; LoadingWheel.Visible = true; break; case ConnectionStatus.Connected: Flag.Image = Flags.Get(OnlineManager.Self.OnlineUser.CountryFlag); Username.Tint = Colors.GetUserChatColor(OnlineManager.Self.OnlineUser.UserGroups); Avatar.Border.Tint = Username.Tint; if (OnlineManager.Self.Stats.ContainsKey(ConfigManager.SelectedGameMode.Value)) { var stats = OnlineManager.Self.Stats[ConfigManager.SelectedGameMode.Value]; Status.Text = $"#{stats.Rank:n0} - {stats.OverallPerformanceRating:00.00} ({StringHelper.AccuracyToString((float) stats.OverallAccuracy)})"; } LoadingWheel.Visible = false; break; case ConnectionStatus.Reconnecting: Status.Text = "Reconnecting. Please Wait!"; LoadingWheel.Visible = true; break; default: throw new ArgumentOutOfRangeException(); break; } GameMode.Visible = OnlineManager.Status.Value == ConnectionStatus.Connected; LoadingWheel.X = Status.Width + 10; }