protected void OnGameLoaded() { if (game.State.Mode == GameMode.Tier) { tierState = Context.TierState; } }
public override CriterionState Judge(TierState state) { if (state.Stages[StageIndex] == null || !state.Stages[StageIndex].IsCompleted) { return(CriterionState.Undetermined); } return(state.Stages[StageIndex].MaxCombo >= RequiredCombo ? CriterionState.Passed : CriterionState.Failed); }
public override CriterionState Judge(TierState state) { if (!state.IsCompleted) { return(CriterionState.Undetermined); } return(state.AverageAccuracy >= RequiredAverageAccuracy ? CriterionState.Passed : CriterionState.Failed); }
public override CriterionState Judge(TierState state) { if (!state.IsCompleted) { return(CriterionState.Undetermined); } return(state.Stages.Last().Health / state.Stages.Last().MaxHealth >= RequiredPercentage ? CriterionState.Passed : CriterionState.Failed); }
public override CriterionState Judge(TierState state) { if (!state.IsCompleted) { return(CriterionState.Undetermined); } return(state.MaxCombo >= RequiredTotalCombo ? CriterionState.Passed : CriterionState.Failed); }
public override CriterionState Judge(TierState state) { var count = state.GradeCounts[NoteGrade.Good]; if (count > MaxCount) { return(CriterionState.Failed); } return(state.IsCompleted ? CriterionState.Passed : CriterionState.Undetermined); }
public override CriterionState Judge(TierState state) { if (state.Stages[StageIndex] == null) { return(CriterionState.Undetermined); } var count = state.Stages[StageIndex].GradeCounts[NoteGrade.Bad] + state.Stages[StageIndex].GradeCounts[NoteGrade.Miss]; if (count > MaxCount) { return(CriterionState.Failed); } return(state.Stages[StageIndex].IsCompleted ? CriterionState.Passed : CriterionState.Undetermined); }
public abstract CriterionState Judge(TierState state);
public async UniTask Initialize(bool startAutomatically = true) { ObjectPool = new ObjectPool(this); // Decide game mode var mode = Context.SelectedGameMode; if (mode == GameMode.Unspecified) { if (EditorGameMode != GameMode.Unspecified) { mode = EditorGameMode; } else { throw new Exception("Game mode not specified"); } } if (mode == GameMode.Tier) { var tierState = Context.TierState; if (tierState == null) { await Context.LevelManager.LoadLevelsOfType(LevelType.Tier); tierState = new TierState(MockData.Season.tiers[0]); Context.TierState = tierState; } if (tierState.IsFailed || tierState.IsCompleted) { // Reset tier state tierState = new TierState(tierState.Tier); Context.TierState = tierState; } tierState.CurrentStageIndex++; Level = tierState.Tier.Meta.stages[Context.TierState.CurrentStageIndex].ToLevel(LevelType.Tier); Difficulty = Difficulty.Parse(Level.Meta.charts.Last().type); } else if (mode == GameMode.GlobalCalibration) { // Load global calibration level Level = await Context.LevelManager.LoadOrInstallBuiltInLevel(BuiltInData.GlobalCalibrationModeLevelId, LevelType.Temp); Difficulty = Level.Meta.GetEasiestDifficulty(); // Initialize global calibrator globalCalibrator = new GlobalCalibrator(this); } else { if (Context.SelectedLevel == null && Application.isEditor) { // Load test level await Context.LevelManager.LoadFromMetadataFiles(LevelType.User, new List <string> { $"{Context.UserDataPath}/{EditorDefaultLevelDirectory}/level.json" }); Context.SelectedLevel = Context.LevelManager.LoadedLocalLevels.Values.First(); Context.SelectedDifficulty = Context.SelectedLevel.Meta.GetHardestDifficulty(); } Level = Context.SelectedLevel; Difficulty = Context.SelectedDifficulty; } onGameReadyToLoad.Invoke(this); await Resources.UnloadUnusedAssets(); // Load chart print("Loading chart"); var chartMeta = Level.Meta.GetChartSection(Difficulty.Id); var chartPath = "file://" + Level.Path + chartMeta.path; string chartText; using (var request = UnityWebRequest.Get(chartPath)) { await request.SendWebRequest(); if (request.isNetworkError || request.isHttpError) { Debug.LogError(request.error); throw new Exception($"Failed to download chart from {chartPath}"); } chartText = Encoding.UTF8.GetString(request.downloadHandler.data); } var mods = new HashSet <Mod>(Context.SelectedMods); if (Application.isEditor && EditorForceAutoMod) { mods.Add(Mod.Auto); } Chart = new Chart( chartText, mods.Contains(Mod.FlipX) || mods.Contains(Mod.FlipAll), mods.Contains(Mod.FlipY) || mods.Contains(Mod.FlipAll), true, Context.Player.Settings.UseExperimentalNoteAr, mods.Contains(Mod.Fast) ? 1.5f : (mods.Contains(Mod.Slow) ? 0.75f : 1), camera.orthographicSize ); ChartLength = Chart.Model.note_list.Max(it => it.end_time); foreach (var type in (NoteType[])Enum.GetValues(typeof(NoteType))) { ObjectPool.UpdateNoteObjectCount(type, Chart.MaxSamePageNoteCountByType[type] * 3); } // Load audio print("Loading audio"); AudioListener.pause = false; if (Context.AudioManager == null) { await UniTask.WaitUntil(() => Context.AudioManager != null); } Context.AudioManager.Initialize(); var audioPath = "file://" + Level.Path + Level.Meta.GetMusicPath(Difficulty.Id); var loader = new AudioClipLoader(audioPath); await loader.Load(); if (loader.Error != null) { Debug.LogError(loader.Error); throw new Exception($"Failed to download audio from {audioPath}"); } Music = Context.AudioManager.Load("Level", loader.AudioClip, false, false, true); MusicLength = Music.Length; // Load storyboard StoryboardPath = Level.Path + (chartMeta.storyboard != null ? chartMeta.storyboard.path : "storyboard.json"); if (File.Exists(StoryboardPath)) { // Initialize storyboard // TODO: Why File.ReadAllText() works but not UnityWebRequest? // (UnityWebRequest downloaded text could not be parsed by Newtonsoft.Json) try { var storyboardText = File.ReadAllText(StoryboardPath); Storyboard = new Cytoid.Storyboard.Storyboard(this, storyboardText); Storyboard.Parse(); await Storyboard.Initialize(); print($"Loaded storyboard from {StoryboardPath}"); } catch (Exception e) { Debug.LogError(e); Debug.LogError("Could not load storyboard."); } } // Load hit sound if (Context.Player.Settings.HitSound != "none") { var resource = await Resources.LoadAsync <AudioClip>("Audio/HitSounds/" + Context.Player.Settings.HitSound); Context.AudioManager.Load("HitSound", resource as AudioClip, isResource: true); } // State & config State = new GameState(this, mode, mods); Context.GameState = State; if (Application.isEditor) { Debug.Log("Chart checksum: " + State.ChartChecksum); } Config = new GameConfig(this); // Touch handlers if (mode != GameMode.GlobalCalibration && !State.Mods.Contains(Mod.Auto)) { inputController.EnableInput(); } // System config Application.targetFrameRate = 120; Context.SetAutoRotation(false); // Update last played time Level.Record.LastPlayedDate = DateTimeOffset.UtcNow; Level.SaveRecord(); // Initialize note pool ObjectPool.Initialize(); IsLoaded = true; if (mode != GameMode.GlobalCalibration) { Context.ScreenManager.ChangeScreen(OverlayScreen.Id, ScreenTransition.None); } onGameLoaded.Invoke(this); levelInfoParent.transform.RebuildLayout(); if (startAutomatically) { StartGame(); } }
public override async void OnScreenBecameActive() { base.OnScreenBecameActive(); // TODO: Most code here is the same as the one in ResultScreen.cs. Refactor? gameState = Context.GameState; Context.GameState = null; // Load translucent cover var path = "file://" + gameState.Level.Path + gameState.Level.Meta.background.path; TranslucentCover.Set(await Context.AssetMemory.LoadAsset <Sprite>(path, AssetTag.GameCover)); // Update performance info scoreText.text = Mathf.FloorToInt((float)gameState.Score).ToString("D6"); accuracyText.text = "RESULT_X_ACCURACY".Get((Math.Floor(gameState.Accuracy * 100 * 100) / 100).ToString("0.00")); if (Mathf.Approximately((float)gameState.Accuracy, 1)) { accuracyText.text = "RESULT_FULL_ACCURACY".Get(); } maxComboText.text = "RESULT_X_COMBO".Get(gameState.MaxCombo); if (gameState.GradeCounts[NoteGrade.Bad] == 0 && gameState.GradeCounts[NoteGrade.Miss] == 0) { maxComboText.text = "RESULT_FULL_COMBO".Get(); } var scoreGrade = ScoreGrades.From(gameState.Score); gradeText.text = scoreGrade.ToString(); gradeText.GetComponent <GradientMeshEffect>().SetGradient(scoreGrade.GetGradient()); if (scoreGrade == ScoreGrade.MAX || scoreGrade == ScoreGrade.SSS) { scoreText.GetComponent <GradientMeshEffect>().SetGradient(scoreGrade.GetGradient()); } else { scoreText.GetComponent <GradientMeshEffect>().enabled = false; } standardMetricText.text = $"<b>Perfect</b> {gameState.GradeCounts[NoteGrade.Perfect]} " + $"<b>Great</b> {gameState.GradeCounts[NoteGrade.Great]} " + $"<b>Good</b> {gameState.GradeCounts[NoteGrade.Good]} " + $"<b>Bad</b> {gameState.GradeCounts[NoteGrade.Bad]} " + $"<b>Miss</b> {gameState.GradeCounts[NoteGrade.Miss]}"; advancedMetricText.text = $"<b>Early</b> {gameState.EarlyCount} " + $"<b>Late</b> {gameState.LateCount} " + $"<b>{"RESULT_AVG_TIMING_ERR".Get()}</b> {gameState.AverageTimingError:0.000}s " + $"<b>{"RESULT_STD_TIMING_ERR".Get()}</b> {gameState.StandardTimingError:0.000}s"; if (!Context.Player.Settings.DisplayEarlyLateIndicators) { advancedMetricText.text = ""; } tierState = Context.TierState; modeText.text = tierState.Tier.Meta.name; var stage = tierState.CurrentStage; difficultyBall.SetModel(stage.Difficulty, stage.DifficultyLevel); stageTitleText.text = stage.Level.Meta.title; if (tierState.IsFailed) { retryButton.StartPulsing(); } else { nextStageButton.StartPulsing(); } nextStageButton.State = tierState.IsFailed ? CircleButtonState.GoBack : (tierState.IsCompleted ? CircleButtonState.Finish : CircleButtonState.NextStage); nextStageButton.interactableMonoBehavior.onPointerClick.SetListener(_ => { Context.Haptic(HapticTypes.SoftImpact, true); nextStageButton.StopPulsing(); if (tierState.IsFailed) { GoBack(); } else { if (tierState.IsCompleted) { Finish(); } else { NextStage(); } } }); retryButton.State = CircleButtonState.Retry; retryButton.interactableMonoBehavior.onPointerClick.SetListener(_ => { Context.Haptic(HapticTypes.SoftImpact, true); retryButton.StopPulsing(); Retry(); }); // Update criterion entries foreach (Transform child in criterionEntryHolder.transform) { Destroy(child.gameObject); } foreach (var criterion in Context.TierState.Criteria) { var entry = Instantiate(criterionEntryPrefab, criterionEntryHolder.transform) .GetComponent <CriterionEntry>(); entry.SetModel(criterion.Description, criterion.Judge(Context.TierState)); } criterionEntryHolder.transform.RebuildLayout(); NavigationBackdrop.Instance.Apply(it => { it.IsBlurred = true; it.FadeBrightness(1, 0.8f); }); ProfileWidget.Instance.Enter(); if (tierState.IsFailed) { Toast.Next(Toast.Status.Failure, "TOAST_TIER_FAILED".Get()); } if (!tierState.IsCompleted && !tierState.IsFailed) { proceedToNextStageTime = DateTimeOffset.UtcNow.AddSeconds(IntermissionSeconds); nextBroadcastCountdownTime = DateTimeOffset.UtcNow; } else { proceedToNextStageTime = DateTimeOffset.MaxValue; nextBroadcastCountdownTime = DateTimeOffset.MaxValue; } }
public override async void OnScreenBecameActive() { base.OnScreenBecameActive(); tierState = Context.TierState; if (tierState == null) { tierState = new TierState(MockData.Season.tiers[0]) { Combo = 1, CurrentStageIndex = 0, Health = 1000.0, IsFailed = false, MaxCombo = 1, Stages = new[] { new GameState() } }; tierState.OnComplete(); } Context.TierState = null; nextButton.State = CircleButtonState.Next; nextButton.StartPulsing(); nextButton.interactableMonoBehavior.onPointerClick.SetListener(_ => { Context.Haptic(HapticTypes.SoftImpact, true); nextButton.StopPulsing(); Done(); }); retryButton.State = CircleButtonState.Retry; retryButton.interactableMonoBehavior.onPointerClick.SetListener(_ => { Context.Haptic(HapticTypes.SoftImpact, true); retryButton.StopPulsing(); Retry(); }); // Update performance info scoreText.text = (Mathf.Floor((float)tierState.Completion * 100 * 100) / 100).ToString("0.00") + "%"; accuracyText.text = "RESULT_X_ACCURACY".Get((Math.Floor(tierState.AverageAccuracy * 100 * 100) / 100).ToString("0.00")); if (Mathf.Approximately((float)tierState.AverageAccuracy, 1)) { accuracyText.text = "RESULT_FULL_ACCURACY".Get(); } maxComboText.text = "RESULT_X_COMBO".Get(tierState.MaxCombo); if (tierState.GradeCounts[NoteGrade.Bad] == 0 && tierState.GradeCounts[NoteGrade.Miss] == 0) { maxComboText.text = "RESULT_FULL_COMBO".Get(); } var scoreGrade = ScoreGrades.FromTierCompletion(tierState.Completion); gradeText.text = scoreGrade.ToString(); gradeText.GetComponent <GradientMeshEffect>().SetGradient(scoreGrade.GetGradient()); if (scoreGrade == ScoreGrade.MAX || scoreGrade == ScoreGrade.SSS) { scoreText.GetComponent <GradientMeshEffect>().SetGradient(scoreGrade.GetGradient()); } else { scoreText.GetComponent <GradientMeshEffect>().enabled = false; } standardMetricText.text = $"<b>Perfect</b> {tierState.GradeCounts[NoteGrade.Perfect]} " + $"<b>Great</b> {tierState.GradeCounts[NoteGrade.Great]} " + $"<b>Good</b> {tierState.GradeCounts[NoteGrade.Good]} " + $"<b>Bad</b> {tierState.GradeCounts[NoteGrade.Bad]} " + $"<b>Miss</b> {tierState.GradeCounts[NoteGrade.Miss]}"; advancedMetricText.text = $"<b>Early</b> {tierState.EarlyCount} " + $"<b>Late</b> {tierState.LateCount} " + $"<b>{"RESULT_AVG_TIMING_ERR".Get()}</b> {tierState.AverageTimingError:0.000}s " + $"<b>{"RESULT_STD_TIMING_ERR".Get()}</b> {tierState.StandardTimingError:0.000}s"; if (!Context.Player.Settings.DisplayEarlyLateIndicators) { advancedMetricText.text = ""; } newBestText.text = ""; if (tierState.Completion >= 1) { if (tierState.Tier.completion < 1) { newBestText.text = "TIER_CLEARED".Get(); } else { var historicBest = tierState.Tier.completion; var newBest = tierState.Completion; if (newBest > historicBest) { tierState.Tier.completion = tierState.Completion; // Update cached tier json newBestText.text = $"+{(Mathf.FloorToInt((float) (newBest - historicBest) * 100 * 100) / 100f):0.00}%"; } } } shareButton.onPointerClick.SetListener(_ => StartCoroutine(Share())); gradientPane.SetModel(tierState.Tier); for (var index = 0; index < Math.Min(tierState.Tier.Meta.parsedStages.Count, 3); index++) { var widget = stageResultWidgets[index]; var level = tierState.Tier.Meta.parsedStages[index]; var stageResult = tierState.Stages[index]; widget.difficultyBall.SetModel(Difficulty.Parse(level.Meta.charts.Last().type), level.Meta.charts.Last().difficulty); widget.titleText.text = level.Meta.title; widget.performanceWidget.SetModel(new LevelRecord.Performance { Score = (int)stageResult.Score, Accuracy = stageResult.Accuracy }); } ProfileWidget.Instance.Enter(); upperRightColumn.Enter(); UploadRecord(); }
public override CriterionState Judge(TierState state) { if (!state.IsCompleted) return CriterionState.Undetermined; return state.Stages.Sum(it => it.Score) >= RequiredTotalScore ? CriterionState.Passed : CriterionState.Failed; }