/// <summary> /// If we're coming from gameplay, the screen gets intiialized this way. /// </summary> /// <exception cref="InvalidOperationException"></exception> private void InitializeIfGameplayType() { if (ResultsType != ResultScreenType.Gameplay) { throw new InvalidOperationException("Cannot call this if ResultsType is not Gameplay"); } // Stop `capturing` the replay. Not sure if this is necessary since update isn't even called and // it wouldn't be capturing anyway. Gameplay.ReplayCapturer.ShouldCapture = false; // Keep the same replay and score processor if the user was watching a replay before, if (Gameplay.InReplayMode) { Replay = Gameplay.LoadedReplay; if (Replay.Mods.HasFlag(ModIdentifier.Autoplay)) { ScoreProcessor = Gameplay.Ruleset.ScoreProcessor; } else if (Gameplay.SpectatorClient != null) { var im = Gameplay.Ruleset.InputManager as KeysInputManager; ScoreProcessor = im.ReplayInputManager.VirtualPlayer.ScoreProcessor; } else { ScoreProcessor = new ScoreProcessorKeys(Replay); } ScoreProcessor.Stats = Gameplay.Ruleset.ScoreProcessor.Stats; // Remove all modifiers that was played during the replay, so the user doesn't still have them // activated when they go back to select. (autoplay is the only exception) if (!ModManager.IsActivated(ModIdentifier.Autoplay)) { ModManager.RemoveAllMods(); } return; } // User has played the map, and wasn't watching a replay, so we can proceed normally. // Set the replay that the user has generated Replay = Gameplay.ReplayCapturer.Replay; Replay.PauseCount = Gameplay.PauseCount; Replay.RandomizeModifierSeed = Gameplay.Map.RandomizeModifierSeed; ScoreProcessor = Gameplay.Ruleset.ScoreProcessor; Replay.FromScoreProcessor(ScoreProcessor); // Remove paused modifier if enabled. if (ModManager.IsActivated(ModIdentifier.Paused)) { ModManager.RemoveMod(ModIdentifier.Paused); } SubmitScore(); }
/// <summary> /// </summary> /// <param name="replay"></param> public ResultScreen(Replay replay) { Replay = replay; ResultsType = ResultScreenType.Replay; ScoreProcessor = new ScoreProcessorKeys(replay); InitializeIfReplayType(); ChangeDiscordPresence(); View = new ResultScreenView(this); }
/// <summary> /// </summary> /// <param name="score"></param> public ResultScreen(Score score) { Score = score; ResultsType = ResultScreenType.Score; Replay = score.ToReplay(); ScoreProcessor = new ScoreProcessorKeys(Replay); InitializeIfScoreType(); View = new ResultScreenView(this); }
/// <summary> /// </summary> /// <param name="replay"></param> /// <param name="map"></param> /// <param name="windows"></param> /// <param name="dontExtend"></param> public VirtualReplayPlayer(Replay replay, Qua map, JudgementWindows windows = null, bool dontExtend = false) { Replay = replay; Map = map; DontExtendReplay = dontExtend; ScoreProcessor = new ScoreProcessorKeys(map, Replay.Mods, windows); ActiveHitObjects = new List <HitObjectInfo>(); ActiveHeldLongNotes = new List <HitObjectInfo>(); map.HitObjects.ForEach(x => ActiveHitObjects.Add(x)); // Add virtual key bindings based on the game mode of the replay. switch (Map.Mode) { case GameMode.Keys4: InputKeyStore = new List <VirtualReplayKeyBinding>() { new VirtualReplayKeyBinding(ReplayKeyPressState.K1), new VirtualReplayKeyBinding(ReplayKeyPressState.K2), new VirtualReplayKeyBinding(ReplayKeyPressState.K3), new VirtualReplayKeyBinding(ReplayKeyPressState.K4), new VirtualReplayKeyBinding(ReplayKeyPressState.K5), }; break; case GameMode.Keys7: InputKeyStore = new List <VirtualReplayKeyBinding>() { new VirtualReplayKeyBinding(ReplayKeyPressState.K1), new VirtualReplayKeyBinding(ReplayKeyPressState.K2), new VirtualReplayKeyBinding(ReplayKeyPressState.K3), new VirtualReplayKeyBinding(ReplayKeyPressState.K4), new VirtualReplayKeyBinding(ReplayKeyPressState.K5), new VirtualReplayKeyBinding(ReplayKeyPressState.K6), new VirtualReplayKeyBinding(ReplayKeyPressState.K7), new VirtualReplayKeyBinding(ReplayKeyPressState.K8), new VirtualReplayKeyBinding(ReplayKeyPressState.K9), }; break; default: throw new ArgumentOutOfRangeException(); } }
/// <inheritdoc /> /// <summary> /// Ctor /// </summary> /// <param name="screen"></param> /// <param name="type"></param> /// <param name="username"></param> /// <param name="judgements"></param> /// <param name="avatar"></param> /// <param name="mods"></param> /// <param name="score"></param> /// <exception cref="T:System.ComponentModel.InvalidEnumArgumentException"></exception> internal ScoreboardUser(GameplayScreen screen, ScoreboardUserType type, string username, List <Judgement> judgements, Texture2D avatar, ModIdentifier mods, Score score = null) { Screen = screen; LocalScore = score; Judgements = judgements; UsernameRaw = username; RatingProcessor = new RatingProcessorKeys(MapManager.Selected.Value.DifficultyFromMods(mods)); Type = type; Size = new ScalableVector2(260, 50); // Set position initially to offscreen X = -Width - 10; // The alpha of the tect - determined by the scoreboard user type. float textAlpha; // Set props based on the type of scoreboard user this is. switch (Type) { case ScoreboardUserType.Self: Image = SkinManager.Skin.Scoreboard; Alpha = 1f; textAlpha = 1f; break; case ScoreboardUserType.Other: Image = SkinManager.Skin.ScoreboardOther; textAlpha = 0.65f; break; default: throw new ArgumentOutOfRangeException(); } switch (Screen.Map.Mode) { case GameMode.Keys4: case GameMode.Keys7: if (screen.IsMultiplayerGame && Type == ScoreboardUserType.Other) { var mp = new ScoreProcessorMultiplayer((MultiplayerHealthType)OnlineManager.CurrentGame.HealthType, OnlineManager.CurrentGame.Lives); Processor = new ScoreProcessorKeys(Screen.Map, mods, mp); } else { Processor = Type == ScoreboardUserType.Other ? new ScoreProcessorKeys(Screen.Map, mods): Screen.Ruleset.ScoreProcessor; } break; default: throw new InvalidEnumArgumentException(); } // Create avatar Avatar = new Sprite() { Parent = this, Size = new ScalableVector2(Height, Height), Alignment = Alignment.MidLeft, Image = avatar, }; RankText = new SpriteTextBitmap(FontsBitmap.GothamRegular, "?.", false) { Parent = this, Alignment = Alignment.MidLeft, FontSize = 19, X = Avatar.X + Avatar.Width + 14, Alpha = textAlpha }; if (Type != ScoreboardUserType.Self) { if (LocalScore != null && (LocalScore.IsOnline || LocalScore.IsMultiplayer)) { // Check to see if we have a Steam avatar for this user cached. if (SteamManager.UserAvatars.ContainsKey((ulong)LocalScore.SteamId)) { Avatar.Image = SteamManager.UserAvatars[(ulong)LocalScore.SteamId]; } else { Avatar.Alpha = 0; Avatar.Image = UserInterface.UnknownAvatar; // Otherwise we need to request for it. SteamManager.SteamUserAvatarLoaded += OnAvatarLoaded; SteamManager.SendAvatarRetrievalRequest((ulong)LocalScore.SteamId); } } else { Avatar.Image = UserInterface.UnknownAvatar; } } // Create username text. Username = new SpriteTextBitmap(FontsBitmap.GothamRegular, GetUsernameFormatted()) { Parent = this, Alignment = Alignment.TopLeft, Alpha = textAlpha, X = RankText.X + RankText.Width + 18, Y = 6, FontSize = 16 }; // Create score text. Score = new SpriteTextBitmap(FontsBitmap.GothamRegular, "0.00", false) { Parent = this, Alignment = Alignment.TopLeft, Alpha = textAlpha, Y = Username.Y + Username.Height + 4, X = Username.X, FontSize = 15 }; // Create score text. Combo = new SpriteTextBitmap(FontsBitmap.GothamRegular, $"{Processor.Combo:N0}x", false) { Parent = this, Alignment = Alignment.MidRight, Alpha = textAlpha, FontSize = 15, X = -5 }; }
/// <summary> /// Recalculates all scores /// </summary> /// <param name="scores"></param> private void Recalculate(JToken scores) { var comparedScores = new List <ComparedScores>(); foreach (var score in scores) { // Make a dummy Qua for this score var qua = new Qua(); var totalObjects = (int)score["count_marv"] + (int)score["count_perf"] + (int)score["count_great"] + (int)score["count_good"] + (int)score["count_okay"] + (int)score["count_miss"]; for (var i = 0; i < totalObjects; i++) { qua.HitObjects.Add(new HitObjectInfo()); } var processor = new ScoreProcessorKeys(qua, 0); for (var i = 0; i < (int)score["count_marv"]; i++) { processor.CalculateScore(Judgement.Marv); } for (var i = 0; i < (int)score["count_perf"]; i++) { processor.CalculateScore(Judgement.Perf); } for (var i = 0; i < (int)score["count_great"]; i++) { processor.CalculateScore(Judgement.Great); } for (var i = 0; i < (int)score["count_good"]; i++) { processor.CalculateScore(Judgement.Good); } for (var i = 0; i < (int)score["count_okay"]; i++) { processor.CalculateScore(Judgement.Okay); } for (var i = 0; i < (int)score["count_miss"]; i++) { processor.CalculateScore(Judgement.Miss); } var difficultyRating = (double)score["performance_rating"] / Math.Pow((double)score["accuracy"] / 98, 6); comparedScores.Add(new ComparedScores($"{score["map"]["artist"]} - {score["map"]["title"]} [{score["map"]["difficulty_name"]}]", (double)score["accuracy"], processor.Accuracy, (double)score["performance_rating"], difficultyRating)); } Console.WriteLine(comparedScores.ToStringTable(new [] { "Map Name", "Difficulty", "Orig. Acc%", "New Acc%", "Orig. Rating", "New Rating", }, u => u.MapName, u => u.DifficultyRating, u => u.OriginalAccuracy, u => u.NewAccuracy, u => u.OriginalRating, u => new RatingProcessorKeys(u.DifficultyRating).CalculateRating(u.NewAccuracy))); }