Files
ichni_Official/Assets/Scripts/Menu/ChapterSelection/ChapterSelectionUnit.cs

208 lines
7.0 KiB
C#
Raw Normal View History

2025-06-03 02:42:28 -04:00
using System;
using System.Collections;
using System.Collections.Generic;
2025-06-06 10:14:55 -04:00
using System.Linq;
using AK.Wwise;
2025-08-22 14:54:40 -04:00
using Ichni.RhythmGame;
2025-06-03 02:42:28 -04:00
using Sirenix.OdinInspector;
2026-03-14 03:13:10 -04:00
using SLSUtilities.WwiseAssistance;
2025-06-03 02:42:28 -04:00
using UnityEngine;
2025-06-14 14:42:49 -04:00
using UnityEngine.Serialization;
2025-06-03 02:42:28 -04:00
namespace Ichni.Menu
{
[CreateAssetMenu(fileName = "DefaultChapter", menuName = "Ichni/UI/ChapterSelectionUnit", order = 0)]
2025-08-11 14:04:06 -04:00
public partial class ChapterSelectionUnit : SerializedScriptableObject
2025-06-03 02:42:28 -04:00
{
public string chapterIndex;
public string chapterName;
public string chapterSubtitle;
public Color themeColor;
public Sprite avatar;
2025-06-06 10:14:55 -04:00
public Switch chapterSwitch;
/// <summary>
/// 章节剧情入口与选曲入口共用的内容解锁规则。
/// 留空表示章节从新档开始即可访问;需要锁定时请使用 <see cref="UnlockRequirement"/>
/// 并遵守 <see cref="UnlockSaveModule.KeyNamingRule"/> 中的下划线 Key 规则。
/// </summary>
[LabelText("Unlock Requirement")]
public UnlockRequirement unlockRequirement = new UnlockRequirement();
2025-08-11 14:04:06 -04:00
[Searchable]
2025-06-03 02:42:28 -04:00
public List<SongItemData> songs = new List<SongItemData>();
2025-06-06 10:14:55 -04:00
[Button]
public void SetUpDefaultDifficulties()
{
foreach (SongItemData song in songs)
{
if (song.difficultyDataList.All(d => d.difficultyName != "Easy"))
2025-06-06 10:14:55 -04:00
{
2025-07-26 04:20:25 -04:00
song.difficultyDataList.Add(new DifficultyData(
0, "Easy", "Easy", 0, "",
2025-06-06 10:14:55 -04:00
new Color(0f, 0.7f, 0.2f, 1f)));
}
if (song.difficultyDataList.All(d => d.difficultyName != "Hard"))
{
2025-07-26 04:20:25 -04:00
song.difficultyDataList.Add(new DifficultyData(
1, "Hard", "Hard", 0, "",
2025-06-06 10:14:55 -04:00
new Color(1f, 0.2f, 0.2f, 1f)));
}
}
2025-07-10 08:42:30 -04:00
}
[Button]
public void SelectSwitch()
{
2026-03-14 03:13:10 -04:00
AudioManager.SetSwitch(chapterSwitch);
2025-06-06 10:14:55 -04:00
}
2025-06-03 02:42:28 -04:00
}
2025-08-11 14:04:06 -04:00
public partial class ChapterSelectionUnit
{
2025-08-22 14:54:40 -04:00
public (int, int, int, int, int) GetChapterSaveInfo()
{
int beatmapCount = 0;
int finishedSongCount = 0;
int finishedBeatmapCount = 0;
int fullComboCount = 0;
int allPerfectCount = 0;
2025-08-22 14:54:40 -04:00
foreach (SongItemData song in songs)
{
if (GameSaveManager.instance.SongSaveModule.songStatusSaves.TryGetValue(song.songName, out var songStatus))
{
bool thisSongFinished = false;
foreach (DifficultyData difficulty in song.difficultyDataList)
2025-08-22 14:54:40 -04:00
{
if (difficulty == null || difficulty.saveDifficultyId < 0)
{
continue;
}
2025-08-22 14:54:40 -04:00
beatmapCount++;
if (!songStatus.TryGetBeatmapSave(difficulty.saveDifficultyId, out BeatmapSave beatmapSave))
{
continue;
}
2025-08-22 14:54:40 -04:00
if (!beatmapSave.IsEmpty())
{
thisSongFinished = true;
finishedBeatmapCount++;
2025-08-22 14:54:40 -04:00
if (beatmapSave.isFullCombo)
{
fullComboCount++;
}
2025-08-22 14:54:40 -04:00
if (beatmapSave.isAllPerfect)
{
allPerfectCount++;
}
}
}
2025-08-22 14:54:40 -04:00
if (thisSongFinished)
{
finishedSongCount++;
}
}
}
2025-08-22 14:54:40 -04:00
return (beatmapCount, finishedSongCount, finishedBeatmapCount, fullComboCount, allPerfectCount);
}
2025-08-11 14:04:06 -04:00
}
2025-06-03 02:42:28 -04:00
[InlineProperty]
[Serializable]
public class SongItemData
{
2025-08-11 14:04:06 -04:00
[FoldoutGroup("$songName", false)]
2025-06-03 02:42:28 -04:00
public string songName;
2025-06-03 02:42:28 -04:00
[FoldoutGroup("$songName")]
public string displaySongName;
2025-06-03 02:42:28 -04:00
[FoldoutGroup("$songName")]
2025-07-21 05:42:20 -04:00
public string composer;
2025-06-03 02:42:28 -04:00
[FoldoutGroup("$songName")]
2025-06-06 10:14:55 -04:00
public Switch songSwitch;
2025-06-03 02:42:28 -04:00
[FoldoutGroup("$songName")]
2025-07-21 05:42:20 -04:00
public Sprite illustration;
2025-06-03 02:42:28 -04:00
[FoldoutGroup("$songName")]
public string illustratorName;
2025-06-03 02:42:28 -04:00
[FoldoutGroup("$songName")]
public string additionalInformation;
2025-06-03 02:42:28 -04:00
[FoldoutGroup("$songName")]
public List<DifficultyData> difficultyDataList;
/// <summary>
/// 歌曲自身的内容解锁规则。章节是否开放由 <see cref="ChapterSelectionUnit.unlockRequirement"/> 单独判断;
/// 真正进入歌曲时两者必须同时满足。
/// </summary>
[FoldoutGroup("$songName")]
[LabelText("Unlock Requirement")]
public UnlockRequirement unlockRequirement = new UnlockRequirement();
2025-06-03 02:42:28 -04:00
}
2025-06-03 02:42:28 -04:00
[Serializable]
public class DifficultyData
{
/// <summary>
/// 歌曲成绩的稳定 ID不等同于选曲 UI 的难度列表位置。
/// 发布后不要更改或复用既有 ID新增难度必须使用从未分配过的非负 ID。
/// </summary>
[FormerlySerializedAs("difficultyIndex")]
public int saveDifficultyId;
2025-06-03 02:42:28 -04:00
public string difficultyName;
public string displayDifficultyName;
2025-06-14 14:42:49 -04:00
public int difficultyValue;
2025-07-21 05:42:20 -04:00
public string charterName;
2025-06-03 02:42:28 -04:00
public Color color;
2025-08-11 14:04:06 -04:00
public bool isAvailable;
public bool ForceFullScreenJudge = false;
[MinValue(1)]
[Tooltip("仅当 Note、Timing 或判定规则变化导致成绩不可与旧谱面比较时递增UI、文本、封面和音量调整不递增。")]
public int chartRevision = 1;
2025-08-11 14:04:06 -04:00
public DifficultyData()
{
2025-08-11 14:04:06 -04:00
}
public DifficultyData(int saveDifficultyId, string difficultyName, string displayDifficultyName, int difficultyValue, string charterName, Color color, bool ForceFullScreenJudge = false)
2025-06-03 02:42:28 -04:00
{
this.saveDifficultyId = saveDifficultyId;
2025-06-03 02:42:28 -04:00
this.difficultyName = difficultyName;
this.displayDifficultyName = displayDifficultyName;
2025-07-21 05:42:20 -04:00
this.charterName = charterName;
2025-06-14 14:42:49 -04:00
this.difficultyValue = difficultyValue;
2025-06-03 02:42:28 -04:00
this.color = color;
2025-08-11 14:04:06 -04:00
this.isAvailable = true;
this.ForceFullScreenJudge = ForceFullScreenJudge;
2025-06-03 02:42:28 -04:00
}
2025-07-21 05:42:20 -04:00
public string GetDifficultyName()
{
return string.IsNullOrEmpty(displayDifficultyName) ? difficultyName : displayDifficultyName;
}
/// <summary>
/// 返回合法的 Revision。配置侧始终至少使用 10 只会被视为未初始化值并被钳制。
/// </summary>
public int GetChartRevision()
{
return Mathf.Max(1, chartRevision);
}
2025-06-03 02:42:28 -04:00
}
}