Additional unlockable methods
This commit is contained in:
parent
7cc431ffbb
commit
598bbb0e06
Binary file not shown.
@ -3,10 +3,10 @@
|
||||
* ch : "Coins here", coin requirement, payable within the heya menu, 1 value : [Coin price]
|
||||
* cs : "Coins shop", coin requirement, payable only within the Medal shop selection screen
|
||||
* cm : "Coins menu", coin requirement, payable only within the song select screen (used only for songs)
|
||||
* dp : "Difficulty pass", count of difficulties pass, unlock check during the results screen, condition 3 values : [Difficulty int (0~4), Clear status (0~2), Number of performances], input 1 value [Plays fitting the condition]
|
||||
* lp : "Level pass", count of level pass, unlock check during the results screen, condition 3 values : [Star rating, Clear status (0~2), Number of performances], input 1 value [Plays fitting the condition]
|
||||
* dp : "Difficulty pass", count of difficulties pass, unlock check during the results screen, condition 3 values : [Difficulty int (0~4), Clear status (0~4), Number of performances], input 1 value [Plays fitting the condition]
|
||||
* lp : "Level pass", count of level pass, unlock check during the results screen, condition 3 values : [Star rating, Clear status (0~4), Number of performances], input 1 value [Plays fitting the condition]
|
||||
* sp : "Song performance", count of a specific song pass, unlock check during the results screen, condition 2 x n values for n songs : [Difficulty int (0~4, if -1 : Any), Clear status (0~2), ...], input 1 value [Count of fullfiled songs], n references for n songs (Song ids)
|
||||
* sg : "Song genre (performance)", count of any song pass within a specific genre folder, unlock check during the results screen, condition 3 x n values for n songs : [Song count, Difficulty int (0~4, if -1 : Any), Clear status (0~2), ...], input 1 value [Count of fullfiled genres], n references for n genres (Genre names)
|
||||
* sg : "Song genre (performance)", count of any song pass within a specific genre folder, unlock check during the results screen, condition 2 x n values for n songs : [Song count, Clear status (0~4), ...], input 1 value [Count of fullfiled genres], n references for n genres (Genre names)
|
||||
|
||||
|
||||
== UnlockType ==
|
||||
|
172
OpenTaiko/src/Common/BestPlayRecords.cs
Normal file
172
OpenTaiko/src/Common/BestPlayRecords.cs
Normal file
@ -0,0 +1,172 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TJAPlayer3
|
||||
{
|
||||
internal class BestPlayRecords
|
||||
{
|
||||
|
||||
public enum EClearStatus
|
||||
{
|
||||
NONE = 0,
|
||||
ASSISTED_CLEAR = 1,
|
||||
CLEAR = 2,
|
||||
FC = 3,
|
||||
PERFECT = 4,
|
||||
TOTAL = 5
|
||||
}
|
||||
|
||||
public class CBestPlayRecord
|
||||
{
|
||||
public string ChartUniqueId = "none";
|
||||
public string ChartGenre = "none";
|
||||
public string Charter = "none";
|
||||
public string Artist = "none";
|
||||
public Int64 PlayMods = 0;
|
||||
public Int64 ChartDifficulty = 3;
|
||||
public Int64 ChartLevel = 8;
|
||||
public Int64 ClearStatus = -1;
|
||||
public Int64 ScoreRank = -1;
|
||||
public Int64 HighScore = 0;
|
||||
public Int64 TowerBestFloor = 0;
|
||||
public List<int> DanExam1 = new List<int> { -1 };
|
||||
public List<int> DanExam2 = new List<int> { -1 };
|
||||
public List<int> DanExam3 = new List<int> { -1 };
|
||||
public List<int> DanExam4 = new List<int> { -1 };
|
||||
public List<int> DanExam5 = new List<int> { -1 };
|
||||
public List<int> DanExam6 = new List<int> { -1 };
|
||||
public List<int> DanExam7 = new List<int> { -1 };
|
||||
public Int64 PlayCount = 1;
|
||||
public Int64 HighScoreGoodCount = 0;
|
||||
public Int64 HighScoreOkCount = 0;
|
||||
public Int64 HighScoreBadCount = 0;
|
||||
public Int64 HighScoreMaxCombo = 0;
|
||||
public Int64 HighScoreRollCount = 0;
|
||||
public Int64 HighScoreADLibCount = 0;
|
||||
public Int64 HighScoreBoomCount = 0;
|
||||
}
|
||||
|
||||
public class CBestPlayStats
|
||||
{
|
||||
public int DistinctPlays = 0;
|
||||
public int DistinctClears = 0;
|
||||
public int DistinctFCs = 0;
|
||||
public int DistinctPerfects = 0;
|
||||
public int SongDistinctPlays = 0;
|
||||
public int SongDistinctClears = 0;
|
||||
public int SongDistinctFCs = 0;
|
||||
public int SongDistinctPerfects = 0;
|
||||
public int[][] ClearStatuses = new int[(int)Difficulty.Total][];
|
||||
public int[][] ScoreRanks = new int[(int)Difficulty.Total][];
|
||||
public Dictionary<int, int> LevelPlays = new Dictionary<int, int>();
|
||||
public Dictionary<int, int> LevelClears = new Dictionary<int, int>();
|
||||
public Dictionary<int, int> LevelFCs = new Dictionary<int, int>();
|
||||
public Dictionary<int, int> LevelPerfects = new Dictionary<int, int>();
|
||||
public Dictionary<string, int> GenrePlays = new Dictionary<string, int>();
|
||||
public Dictionary<string, int> GenreClears = new Dictionary<string, int>();
|
||||
public Dictionary<string, int> GenreFCs = new Dictionary<string, int>();
|
||||
public Dictionary<string, int> GenrePerfects = new Dictionary<string, int>();
|
||||
public Dictionary<string, int> SongGenrePlays = new Dictionary<string, int>();
|
||||
public Dictionary<string, int> SongGenreClears = new Dictionary<string, int>();
|
||||
public Dictionary<string, int> SongGenreFCs = new Dictionary<string, int>();
|
||||
public Dictionary<string, int> SongGenrePerfects = new Dictionary<string, int>();
|
||||
public Dictionary<string, int> CharterPlays = new Dictionary<string, int>();
|
||||
public Dictionary<string, int> CharterClears = new Dictionary<string, int>();
|
||||
public Dictionary<string, int> CharterFCs = new Dictionary<string, int>();
|
||||
public Dictionary<string, int> CharterPerfects = new Dictionary<string, int>();
|
||||
|
||||
public CBestPlayStats()
|
||||
{
|
||||
// 0 : Not clear, 1 : Assisted clear, 2 : Clear, 3 : FC, 4 : Perfect
|
||||
ClearStatuses[0] = new int[(int)EClearStatus.TOTAL] { 0, 0, 0, 0, 0 };
|
||||
ClearStatuses[1] = new int[(int)EClearStatus.TOTAL] { 0, 0, 0, 0, 0 };
|
||||
ClearStatuses[2] = new int[(int)EClearStatus.TOTAL] { 0, 0, 0, 0, 0 };
|
||||
ClearStatuses[3] = new int[(int)EClearStatus.TOTAL] { 0, 0, 0, 0, 0 };
|
||||
ClearStatuses[4] = new int[(int)EClearStatus.TOTAL] { 0, 0, 0, 0, 0 };
|
||||
|
||||
// 0 : None, 1 : E, 2 : D, 3 : C, 4 : B, 5 : A, 6 : S, 7 : Omega
|
||||
ScoreRanks[0] = new int[8] { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
ScoreRanks[1] = new int[8] { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
ScoreRanks[2] = new int[8] { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
ScoreRanks[3] = new int[8] { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
ScoreRanks[4] = new int[8] { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
}
|
||||
}
|
||||
|
||||
static private void InitOrAddDict<T>(Dictionary<T, int> dict, T entry) where T : notnull
|
||||
{
|
||||
if (!dict.ContainsKey(entry))
|
||||
dict[entry] = 0;
|
||||
dict[entry]++;
|
||||
}
|
||||
|
||||
static public CBestPlayStats tGenerateBestPlayStats(
|
||||
Dictionary<string, CBestPlayRecord>.ValueCollection uniqueChartBestPlays,
|
||||
Dictionary<string, CBestPlayRecord>.ValueCollection uniqueSongBestPlays
|
||||
)
|
||||
{
|
||||
CBestPlayStats stats = new CBestPlayStats();
|
||||
|
||||
// Individual charts
|
||||
foreach (CBestPlayRecord record in uniqueChartBestPlays)
|
||||
{
|
||||
Int64 roundedDifficulty = Math.Max((int)Difficulty.Easy, Math.Min((int)Difficulty.Total - 1, record.ChartDifficulty));
|
||||
if (roundedDifficulty <= (int)Difficulty.Edit)
|
||||
{
|
||||
string[] ChartersArr = record.Charter.Split(",", StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||
Int64 roundedScoreRank = Math.Max(0, Math.Min(7, record.ScoreRank + 1));
|
||||
Int64 roundedClearStatus = Math.Max((int)EClearStatus.NONE, Math.Min((int)EClearStatus.PERFECT, record.ClearStatus + 1));
|
||||
|
||||
stats.ScoreRanks[roundedDifficulty][roundedScoreRank]++;
|
||||
stats.ClearStatuses[roundedDifficulty][roundedClearStatus]++;
|
||||
foreach (string Charter in ChartersArr)
|
||||
{
|
||||
InitOrAddDict(stats.CharterPlays, Charter);
|
||||
if (roundedClearStatus >= (int)EClearStatus.CLEAR) InitOrAddDict(stats.CharterClears, Charter);
|
||||
if (roundedClearStatus >= (int)EClearStatus.FC) InitOrAddDict(stats.CharterFCs, Charter);
|
||||
if (roundedClearStatus == (int)EClearStatus.PERFECT) InitOrAddDict(stats.CharterPerfects, Charter);
|
||||
}
|
||||
InitOrAddDict(stats.GenrePlays, record.ChartGenre);
|
||||
if (roundedClearStatus >= (int)EClearStatus.CLEAR) InitOrAddDict(stats.GenreClears, record.ChartGenre);
|
||||
if (roundedClearStatus >= (int)EClearStatus.FC) InitOrAddDict(stats.GenreFCs, record.ChartGenre);
|
||||
if (roundedClearStatus == (int)EClearStatus.PERFECT) InitOrAddDict(stats.GenrePerfects, record.ChartGenre);
|
||||
InitOrAddDict(stats.LevelPlays, (int)record.ChartLevel);
|
||||
if (roundedClearStatus >= (int)EClearStatus.CLEAR) InitOrAddDict(stats.LevelClears, (int)record.ChartLevel);
|
||||
if (roundedClearStatus >= (int)EClearStatus.FC) InitOrAddDict(stats.LevelFCs, (int)record.ChartLevel);
|
||||
if (roundedClearStatus == (int)EClearStatus.PERFECT) InitOrAddDict(stats.LevelPerfects, (int)record.ChartLevel);
|
||||
stats.DistinctPlays++;
|
||||
if (roundedClearStatus >= (int)EClearStatus.CLEAR) stats.DistinctClears++;
|
||||
if (roundedClearStatus >= (int)EClearStatus.FC) stats.DistinctFCs++;
|
||||
if (roundedClearStatus == (int)EClearStatus.PERFECT) stats.DistinctPerfects++;
|
||||
}
|
||||
// TODO: Add Dan and Tower
|
||||
}
|
||||
|
||||
// Individual songs
|
||||
foreach (CBestPlayRecord record in uniqueSongBestPlays)
|
||||
{
|
||||
Int64 roundedDifficulty = Math.Max((int)Difficulty.Easy, Math.Min((int)Difficulty.Total - 1, record.ChartDifficulty));
|
||||
|
||||
if (roundedDifficulty <= (int)Difficulty.Edit)
|
||||
{
|
||||
Int64 roundedClearStatus = Math.Max((int)EClearStatus.NONE, Math.Min((int)EClearStatus.PERFECT, record.ClearStatus + 1));
|
||||
|
||||
InitOrAddDict(stats.SongGenrePlays, record.ChartGenre);
|
||||
if (roundedClearStatus >= (int)EClearStatus.CLEAR) InitOrAddDict(stats.SongGenreClears, record.ChartGenre);
|
||||
if (roundedClearStatus >= (int)EClearStatus.FC) InitOrAddDict(stats.SongGenreFCs, record.ChartGenre);
|
||||
if (roundedClearStatus == (int)EClearStatus.PERFECT) InitOrAddDict(stats.SongGenrePerfects, record.ChartGenre);
|
||||
stats.SongDistinctPlays++;
|
||||
if (roundedClearStatus >= (int)EClearStatus.CLEAR) stats.SongDistinctClears++;
|
||||
if (roundedClearStatus >= (int)EClearStatus.FC) stats.SongDistinctFCs++;
|
||||
if (roundedClearStatus == (int)EClearStatus.PERFECT) stats.SongDistinctPerfects++;
|
||||
}
|
||||
}
|
||||
|
||||
return stats;
|
||||
}
|
||||
}
|
||||
}
|
67
OpenTaiko/src/Common/LogNotification.cs
Normal file
67
OpenTaiko/src/Common/LogNotification.cs
Normal file
@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using FDK;
|
||||
|
||||
namespace TJAPlayer3
|
||||
{
|
||||
internal class LogNotification
|
||||
{
|
||||
private static Queue<CLogNotification> Notifications = new Queue<CLogNotification>();
|
||||
|
||||
public enum ENotificationType
|
||||
{
|
||||
EINFO,
|
||||
ESUCCESS,
|
||||
EWARNING,
|
||||
EERROR,
|
||||
}
|
||||
|
||||
public class CLogNotification
|
||||
{
|
||||
public CLogNotification(ENotificationType nt, string msg)
|
||||
{
|
||||
NotificationType = nt;
|
||||
Message = msg;
|
||||
}
|
||||
|
||||
public ENotificationType NotificationType = ENotificationType.EINFO;
|
||||
public string Message = "";
|
||||
public CCounter LifeTime = new CCounter(0, 1000, 1, TJAPlayer3.Timer);
|
||||
}
|
||||
|
||||
|
||||
public static void PopError(string message)
|
||||
{
|
||||
Notifications.Enqueue(new CLogNotification(ENotificationType.EERROR, message));
|
||||
Trace.TraceError("<Runtime Error>: " + message);
|
||||
}
|
||||
|
||||
public static void PopWarning(string message)
|
||||
{
|
||||
Notifications.Enqueue(new CLogNotification(ENotificationType.EWARNING, message));
|
||||
Trace.TraceWarning("<Runtime Warning>: " + message);
|
||||
}
|
||||
|
||||
public static void PopSuccess(string message)
|
||||
{
|
||||
Notifications.Enqueue(new CLogNotification(ENotificationType.ESUCCESS, message));
|
||||
Trace.TraceInformation("<Runtime Success>: " + message);
|
||||
}
|
||||
|
||||
public static void PopInfo(string message)
|
||||
{
|
||||
Notifications.Enqueue(new CLogNotification(ENotificationType.EINFO, message));
|
||||
Trace.TraceInformation("<Runtime Info>: " + message);
|
||||
}
|
||||
|
||||
public static void Display()
|
||||
{
|
||||
while (Notifications.Count > 0 && Notifications.Peek().LifeTime.IsEnded) Notifications.Dequeue();
|
||||
// Add an optimized method to display the notifications here
|
||||
}
|
||||
}
|
||||
}
|
@ -24,8 +24,13 @@ namespace TJAPlayer3
|
||||
}
|
||||
|
||||
tLoadFile();
|
||||
|
||||
data.bestPlays = DBSaves.GetBestPlaysAsDict(data.SaveId);
|
||||
data.tFactorizeBestPlays();
|
||||
}
|
||||
|
||||
|
||||
|
||||
#region [Medals]
|
||||
|
||||
public void tEarnCoins(int amount)
|
||||
@ -193,7 +198,7 @@ namespace TJAPlayer3
|
||||
public class Data
|
||||
{
|
||||
[JsonProperty("saveId")]
|
||||
public long SaveId = 0;
|
||||
public Int64 SaveId = 0;
|
||||
|
||||
[JsonProperty("name")]
|
||||
public string Name = "プレイヤー1";
|
||||
@ -249,6 +254,80 @@ namespace TJAPlayer3
|
||||
[JsonProperty("standardPasses")]
|
||||
public Dictionary<string, CPassStatus> standardPasses = new Dictionary<string, CPassStatus>();
|
||||
|
||||
[JsonProperty("___unused_00")]
|
||||
public Dictionary<string, BestPlayRecords.CBestPlayRecord> bestPlays = new Dictionary<string, BestPlayRecords.CBestPlayRecord> ();
|
||||
|
||||
[JsonProperty("___unused_01")]
|
||||
public Dictionary<string, BestPlayRecords.CBestPlayRecord> bestPlaysDistinctCharts = new Dictionary<string, BestPlayRecords.CBestPlayRecord>();
|
||||
|
||||
[JsonProperty("___unused_02")]
|
||||
public Dictionary<string, BestPlayRecords.CBestPlayRecord> bestPlaysDistinctSongs = new Dictionary<string, BestPlayRecords.CBestPlayRecord>();
|
||||
|
||||
[JsonProperty("___unused_03")]
|
||||
public BestPlayRecords.CBestPlayStats bestPlaysStats = new BestPlayRecords.CBestPlayStats ();
|
||||
|
||||
#region [Factorize best plays]
|
||||
|
||||
public void tFactorizeBestPlays()
|
||||
{
|
||||
bestPlaysDistinctCharts = new Dictionary<string, BestPlayRecords.CBestPlayRecord>();
|
||||
|
||||
foreach (BestPlayRecords.CBestPlayRecord bestPlay in bestPlays.Values)
|
||||
{
|
||||
string key = bestPlay.ChartUniqueId + bestPlay.ChartDifficulty.ToString();
|
||||
if (!bestPlaysDistinctCharts.ContainsKey(key))
|
||||
{
|
||||
bestPlaysDistinctCharts[key] = bestPlay;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bestPlay.HighScore > bestPlaysDistinctCharts[key].HighScore)
|
||||
{
|
||||
bestPlaysDistinctCharts[key].HighScore = bestPlay.HighScore;
|
||||
bestPlaysDistinctCharts[key].HighScoreGoodCount = bestPlay.HighScoreGoodCount;
|
||||
bestPlaysDistinctCharts[key].HighScoreOkCount = bestPlay.HighScoreOkCount;
|
||||
bestPlaysDistinctCharts[key].HighScoreBadCount = bestPlay.HighScoreBadCount;
|
||||
bestPlaysDistinctCharts[key].HighScoreRollCount = bestPlay.HighScoreRollCount;
|
||||
bestPlaysDistinctCharts[key].HighScoreBoomCount = bestPlay.HighScoreBoomCount;
|
||||
bestPlaysDistinctCharts[key].HighScoreMaxCombo = bestPlay.HighScoreMaxCombo;
|
||||
bestPlaysDistinctCharts[key].HighScoreADLibCount = bestPlay.HighScoreADLibCount;
|
||||
}
|
||||
bestPlaysDistinctCharts[key].ScoreRank = Math.Max(bestPlaysDistinctCharts[key].ScoreRank, bestPlay.ScoreRank);
|
||||
bestPlaysDistinctCharts[key].ClearStatus = Math.Max(bestPlaysDistinctCharts[key].ClearStatus, bestPlay.ClearStatus);
|
||||
}
|
||||
}
|
||||
|
||||
bestPlaysDistinctSongs = new Dictionary<string, BestPlayRecords.CBestPlayRecord>();
|
||||
|
||||
foreach (BestPlayRecords.CBestPlayRecord bestPlay in bestPlaysDistinctCharts.Values)
|
||||
{
|
||||
string key = bestPlay.ChartUniqueId;
|
||||
if (!bestPlaysDistinctSongs.ContainsKey(key))
|
||||
{
|
||||
bestPlaysDistinctSongs[key] = bestPlay;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bestPlay.HighScore > bestPlaysDistinctSongs[key].HighScore)
|
||||
{
|
||||
bestPlaysDistinctSongs[key].HighScore = bestPlay.HighScore;
|
||||
bestPlaysDistinctSongs[key].HighScoreGoodCount = bestPlay.HighScoreGoodCount;
|
||||
bestPlaysDistinctSongs[key].HighScoreOkCount = bestPlay.HighScoreOkCount;
|
||||
bestPlaysDistinctSongs[key].HighScoreBadCount = bestPlay.HighScoreBadCount;
|
||||
bestPlaysDistinctSongs[key].HighScoreRollCount = bestPlay.HighScoreRollCount;
|
||||
bestPlaysDistinctSongs[key].HighScoreBoomCount = bestPlay.HighScoreBoomCount;
|
||||
bestPlaysDistinctSongs[key].HighScoreMaxCombo = bestPlay.HighScoreMaxCombo;
|
||||
bestPlaysDistinctSongs[key].HighScoreADLibCount = bestPlay.HighScoreADLibCount;
|
||||
}
|
||||
bestPlaysDistinctSongs[key].ScoreRank = Math.Max(bestPlaysDistinctSongs[key].ScoreRank, bestPlay.ScoreRank);
|
||||
bestPlaysDistinctSongs[key].ClearStatus = Math.Max(bestPlaysDistinctSongs[key].ClearStatus, bestPlay.ClearStatus);
|
||||
}
|
||||
}
|
||||
|
||||
bestPlaysStats = BestPlayRecords.tGenerateBestPlayStats(bestPlaysDistinctCharts.Values, bestPlaysDistinctSongs.Values);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public Data data = new Data();
|
||||
|
@ -53,7 +53,7 @@ namespace TJAPlayer3
|
||||
|
||||
data[((Int64)reader["NameplateId"]).ToString()] = nu;
|
||||
}
|
||||
|
||||
reader.Close();
|
||||
}
|
||||
}
|
||||
public class NameplateUnlockable
|
||||
|
@ -11,56 +11,103 @@ namespace TJAPlayer3
|
||||
{
|
||||
internal class DBSaves
|
||||
{
|
||||
private static string _savesDBPath = @$"{TJAPlayer3.strEXEのあるフォルダ}Saves.db3";
|
||||
private static string _savesDBFilename = $@"Saves.db3";
|
||||
private static string _savesDBPath = @$"{TJAPlayer3.strEXEのあるフォルダ}{_savesDBFilename}";
|
||||
private static SqliteConnection SavesDBConnection = new SqliteConnection(@$"Data Source={_savesDBPath}");
|
||||
|
||||
public static SqliteConnection GetSavesDBConnection()
|
||||
private static string _DBNotFoundError = @$"The database {_savesDBFilename} was not found or the connection failed";
|
||||
|
||||
public static SqliteConnection? GetSavesDBConnection()
|
||||
{
|
||||
if (SavesDBConnection != null && SavesDBConnection.State == ConnectionState.Closed) SavesDBConnection.Open();
|
||||
return SavesDBConnection;
|
||||
try
|
||||
{
|
||||
if (SavesDBConnection != null && SavesDBConnection.State == ConnectionState.Closed) SavesDBConnection.Open();
|
||||
return SavesDBConnection;
|
||||
}
|
||||
catch
|
||||
{
|
||||
LogNotification.PopError(_DBNotFoundError);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public class CBestPlayRecord
|
||||
public static Int64 GetPlayerSaveId(int player)
|
||||
{
|
||||
public string ChartUniqueId = "none";
|
||||
public string ChartGenre = "none";
|
||||
public string Charter = "none";
|
||||
public string Artist = "none";
|
||||
public Int64 PlayMods = 0;
|
||||
public Int64 ChartDifficulty = 3;
|
||||
public Int64 ChartLevel = 8;
|
||||
public Int64 ClearStatus = -1;
|
||||
public Int64 ScoreRank = -1;
|
||||
public Int64 HighScore = 0;
|
||||
public Int64 TowerBestFloor = 0;
|
||||
public List<int> DanExam1 = new List<int> { -1 };
|
||||
public List<int> DanExam2 = new List<int> { -1 };
|
||||
public List<int> DanExam3 = new List<int> { -1 };
|
||||
public List<int> DanExam4 = new List<int> { -1 };
|
||||
public List<int> DanExam5 = new List<int> { -1 };
|
||||
public List<int> DanExam6 = new List<int> { -1 };
|
||||
public List<int> DanExam7 = new List<int> { -1 };
|
||||
public Int64 PlayCount = 1;
|
||||
public Int64 HighScoreGoodCount = 0;
|
||||
public Int64 HighScoreOkCount = 0;
|
||||
public Int64 HighScoreBadCount = 0;
|
||||
public Int64 HighScoreMaxCombo = 0;
|
||||
public Int64 HighScoreRollCount = 0;
|
||||
public Int64 HighScoreADLibCount = 0;
|
||||
public Int64 HighScoreBoomCount = 0;
|
||||
return TJAPlayer3.SaveFileInstances[TJAPlayer3.GetActualPlayer(player)].data.SaveId;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#region [best_plays Table]
|
||||
|
||||
public static Dictionary<string, BestPlayRecords.CBestPlayRecord> GetBestPlaysAsDict(Int64 saveId)
|
||||
{
|
||||
Dictionary<string, BestPlayRecords.CBestPlayRecord> _bestPlays = new Dictionary<string, BestPlayRecords.CBestPlayRecord>();
|
||||
SqliteConnection? connection = GetSavesDBConnection();
|
||||
if (connection == null) return _bestPlays;
|
||||
|
||||
var command = connection.CreateCommand();
|
||||
command.CommandText =
|
||||
@$"
|
||||
SELECT *
|
||||
FROM best_plays
|
||||
WHERE SaveId={saveId};
|
||||
";
|
||||
SqliteDataReader reader = command.ExecuteReader();
|
||||
while (reader.Read())
|
||||
{
|
||||
BestPlayRecords.CBestPlayRecord record = new BestPlayRecords.CBestPlayRecord();
|
||||
|
||||
record.ChartUniqueId = (string)reader["ChartUniqueId"];
|
||||
record.ChartGenre = (string)reader["ChartGenre"];
|
||||
record.Charter = (string)reader["Charter"];
|
||||
record.Artist = (string)reader["Artist"];
|
||||
record.PlayMods = (Int64)reader["PlayMods"];
|
||||
record.ChartDifficulty = (Int64)reader["ChartDifficulty"]; ;
|
||||
record.ChartLevel = (Int64)reader["ChartLevel"];
|
||||
record.ClearStatus = (Int64)reader["ClearStatus"];
|
||||
record.ScoreRank = (Int64)reader["ScoreRank"];
|
||||
record.HighScore = (Int64)reader["HighScore"];
|
||||
record.TowerBestFloor = (Int64)reader["TowerBestFloor"];
|
||||
record.DanExam1 = JsonConvert.DeserializeObject<List<int>>((string)reader["DanExam1"] ?? "[]") ?? new List<int>();
|
||||
record.DanExam2 = JsonConvert.DeserializeObject<List<int>>((string)reader["DanExam2"] ?? "[]") ?? new List<int>();
|
||||
record.DanExam3 = JsonConvert.DeserializeObject<List<int>>((string)reader["DanExam3"] ?? "[]") ?? new List<int>();
|
||||
record.DanExam4 = JsonConvert.DeserializeObject<List<int>>((string)reader["DanExam4"] ?? "[]") ?? new List<int>();
|
||||
record.DanExam5 = JsonConvert.DeserializeObject<List<int>>((string)reader["DanExam5"] ?? "[]") ?? new List<int>();
|
||||
record.DanExam6 = JsonConvert.DeserializeObject<List<int>>((string)reader["DanExam6"] ?? "[]") ?? new List<int>();
|
||||
record.DanExam7 = JsonConvert.DeserializeObject<List<int>>((string)reader["DanExam7"] ?? "[]") ?? new List<int>();
|
||||
record.PlayCount = (Int64)reader["PlayCount"];
|
||||
record.HighScoreGoodCount = (Int64)reader["HighScoreGoodCount"];
|
||||
record.HighScoreOkCount = (Int64)reader["HighScoreOkCount"];
|
||||
record.HighScoreBadCount = (Int64)reader["HighScoreBadCount"];
|
||||
record.HighScoreMaxCombo = (Int64)reader["HighScoreMaxCombo"];
|
||||
record.HighScoreRollCount = (Int64)reader["HighScoreRollCount"];
|
||||
record.HighScoreADLibCount = (Int64)reader["HighScoreADLibCount"];
|
||||
record.HighScoreBoomCount = (Int64)reader["HighScoreBoomCount"];
|
||||
|
||||
string key = record.ChartUniqueId + record.ChartDifficulty.ToString() + record.PlayMods.ToString();
|
||||
_bestPlays[key] = record;
|
||||
}
|
||||
reader.Close();
|
||||
|
||||
return _bestPlays;
|
||||
}
|
||||
|
||||
public static void RegisterPlay(int player, int clearStatus, int scoreRank)
|
||||
{
|
||||
SqliteConnection connection = GetSavesDBConnection();
|
||||
SqliteConnection? connection = GetSavesDBConnection();
|
||||
if (connection == null) return;
|
||||
|
||||
SaveFile.Data saveData = TJAPlayer3.SaveFileInstances[TJAPlayer3.GetActualPlayer(player)].data;
|
||||
CBestPlayRecord currentPlay = new CBestPlayRecord();
|
||||
BestPlayRecords.CBestPlayRecord currentPlay = new BestPlayRecords.CBestPlayRecord();
|
||||
var choosenSong = TJAPlayer3.stageSongSelect.rChoosenSong;
|
||||
var choosenDifficulty = TJAPlayer3.stageSongSelect.nChoosenSongDifficulty[player];
|
||||
var chartScore = TJAPlayer3.stage演奏ドラム画面.CChartScore[player];
|
||||
List<int>[] danResults = new List<int>[7] { new List<int>(), new List<int>(), new List<int>(), new List<int>(), new List<int>(), new List<int>(), new List<int>() };
|
||||
|
||||
// Do not register the play if Dan/Tower and any mod is ON
|
||||
if ((choosenDifficulty == (int)Difficulty.Tower || choosenDifficulty == (int)Difficulty.Dan) && !ModIcons.tPlayIsStock(player)) return;
|
||||
|
||||
// 1st step: Init best play record class
|
||||
|
||||
{
|
||||
@ -167,6 +214,7 @@ namespace TJAPlayer3
|
||||
}
|
||||
}
|
||||
}
|
||||
reader.Close();
|
||||
}
|
||||
|
||||
// Intermede: Dan results to Dan exams
|
||||
@ -183,6 +231,13 @@ namespace TJAPlayer3
|
||||
}
|
||||
}
|
||||
|
||||
// Intermede: Update locally the play on the save file to reload it without requerying the database
|
||||
{
|
||||
string key = currentPlay.ChartUniqueId + currentPlay.ChartDifficulty.ToString() + currentPlay.PlayMods.ToString();
|
||||
saveData.bestPlays[key] = currentPlay;
|
||||
saveData.tFactorizeBestPlays();
|
||||
}
|
||||
|
||||
// 3rd step: Insert/Update to database
|
||||
{
|
||||
SqliteCommand cmd = connection.CreateCommand();
|
||||
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using Newtonsoft.Json;
|
||||
using static TJAPlayer3.BestPlayRecords;
|
||||
|
||||
namespace TJAPlayer3
|
||||
{
|
||||
@ -15,7 +16,7 @@ namespace TJAPlayer3
|
||||
["dp"] = 3,
|
||||
["lp"] = 3,
|
||||
["sp"] = 2,
|
||||
["sg"] = 3,
|
||||
["sg"] = 2,
|
||||
};
|
||||
|
||||
public class CUnlockConditions
|
||||
@ -94,10 +95,10 @@ namespace TJAPlayer3
|
||||
* ch : "Coins here", coin requirement, payable within the heya menu, 1 value : [Coin price]
|
||||
* cs : "Coins shop", coin requirement, payable only within the Medal shop selection screen
|
||||
* cm : "Coins menu", coin requirement, payable only within the song select screen (used only for songs)
|
||||
* dp : "Difficulty pass", count of difficulties pass, unlock check during the results screen, condition 3 values : [Difficulty int (0~4), Clear status (0~2), Number of performances], input 1 value [Plays fitting the condition]
|
||||
* lp : "Level pass", count of level pass, unlock check during the results screen, condition 3 values : [Star rating, Clear status (0~2), Number of performances], input 1 value [Plays fitting the condition]
|
||||
* sp : "Song performance", count of a specific song pass, unlock check during the results screen, condition 2 x n values for n songs : [Difficulty int (0~4, if -1 : Any), Clear status (0~2), ...], input 1 value [Count of fullfiled songs], n references for n songs (Song ids)
|
||||
* sg : "Song genre (performance)", count of any song pass within a specific genre folder, unlock check during the results screen, condition 3 x n values for n songs : [Song count, Difficulty int (0~4, if -1 : Any), Clear status (0~2), ...], input 1 value [Count of fullfiled genres], n references for n genres (Genre names)
|
||||
* dp : "Difficulty pass", count of difficulties pass, unlock check during the results screen, condition 3 values : [Difficulty int (0~4), Clear status (0~4), Number of performances], input 1 value [Plays fitting the condition]
|
||||
* lp : "Level pass", count of level pass, unlock check during the results screen, condition 3 values : [Star rating, Clear status (0~4), Number of performances], input 1 value [Plays fitting the condition]
|
||||
* sp : "Song performance", count of a specific song pass, unlock check during the results screen, condition 2 x n values for n songs : [Difficulty int (0~4, if -1 : Any), Clear status (0~4), ...], input 1 value [Count of fullfiled songs], n references for n songs (Song ids)
|
||||
* sg : "Song genre (performance)", count of any unique song pass within a specific genre folder, unlock check during the results screen, condition 2 x n values for n songs : [Song count, Clear status (0~4), ...], input 1 value [Count of fullfiled genres], n references for n genres (Genre names)
|
||||
*
|
||||
*
|
||||
*/
|
||||
@ -237,47 +238,32 @@ namespace TJAPlayer3
|
||||
{
|
||||
_aimedDifficulty = this.Values[0]; // Difficulty if dp, Level if lp
|
||||
_aimedStatus = this.Values[1];
|
||||
|
||||
// dp and lp only work for regular (Dan and Tower excluded) charts
|
||||
if (_aimedStatus < (int)EClearStatus.NONE || _aimedStatus >= (int)EClearStatus.TOTAL) return 0;
|
||||
if (this.Condition == "dp" && (_aimedDifficulty < (int)Difficulty.Easy || _aimedDifficulty > (int)Difficulty.Edit)) return 0;
|
||||
}
|
||||
|
||||
var _sf = TJAPlayer3.SaveFileInstances[player].data.standardPasses;
|
||||
if (_sf == null
|
||||
|| _aimedDifficulty < 0
|
||||
|| _aimedStatus < 0
|
||||
|| (this.Condition == "dp" && _aimedDifficulty > 4)
|
||||
|| _aimedStatus > 2)
|
||||
return -1;
|
||||
var bpDistinctCharts = TJAPlayer3.SaveFileInstances[player].data.bestPlaysDistinctCharts;
|
||||
var chartStats = TJAPlayer3.SaveFileInstances[player].data.bestPlaysStats;
|
||||
|
||||
switch (this.Condition)
|
||||
{
|
||||
case "dp":
|
||||
var _table = chartStats.ClearStatuses[_aimedDifficulty];
|
||||
var _ura = chartStats.ClearStatuses[(int)Difficulty.Edit];
|
||||
int _count = 0;
|
||||
foreach (KeyValuePair<string, SaveFile.CPassStatus> cps in _sf)
|
||||
for (int i = _aimedStatus; i < (int)EClearStatus.TOTAL; i++)
|
||||
{
|
||||
var _values = cps.Value.d;
|
||||
if (_values[_aimedDifficulty] >= _aimedStatus)
|
||||
_count++;
|
||||
// Extreme includes Extra
|
||||
if (_aimedDifficulty == 3 && _values[4] >= _aimedStatus)
|
||||
_count++;
|
||||
_count += _table[i];
|
||||
if (_aimedDifficulty == (int)Difficulty.Oni) _count += _ura[i];
|
||||
}
|
||||
return _count;
|
||||
case "lp":
|
||||
_count = 0;
|
||||
foreach (KeyValuePair<string, SaveFile.CPassStatus> cps in _sf)
|
||||
{
|
||||
var _node = CSongDict.tGetNodeFromID(cps.Key);
|
||||
if (_node != null)
|
||||
{
|
||||
var _values = cps.Value.d;
|
||||
var _levels = _node.nLevel;
|
||||
for (int i = 0; i <= (int)Difficulty.Edit; i++)
|
||||
{
|
||||
if (_levels[i] == _aimedDifficulty && _values[i] >= _aimedStatus)
|
||||
_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return _count;
|
||||
if (_aimedStatus == (int)EClearStatus.NONE) return chartStats.LevelPlays.TryGetValue(_aimedDifficulty, out var value) ? value : 0;
|
||||
else if (_aimedStatus <= (int)EClearStatus.CLEAR) return chartStats.LevelClears.TryGetValue(_aimedDifficulty, out var value) ? value : 0;
|
||||
else if (_aimedStatus == (int)EClearStatus.FC) return chartStats.LevelFCs.TryGetValue(_aimedDifficulty, out var value) ? value : 0;
|
||||
else return chartStats.LevelPerfects.TryGetValue(_aimedDifficulty, out var value) ? value : 0;
|
||||
case "sp":
|
||||
_count = 0;
|
||||
for (int i = 0; i < this.Values.Length / this.RequiredArgCount; i++)
|
||||
@ -287,18 +273,24 @@ namespace TJAPlayer3
|
||||
_aimedDifficulty = this.Values[_base];
|
||||
_aimedStatus = this.Values[_base + 1];
|
||||
|
||||
if (_sf.ContainsKey(_songId))
|
||||
if (_aimedDifficulty >= (int)Difficulty.Easy && _aimedDifficulty <= (int)Difficulty.Edit)
|
||||
{
|
||||
var _values = _sf[_songId].d;
|
||||
if (_aimedDifficulty >= 0 && _aimedDifficulty < 4)
|
||||
string key = _songId + _aimedDifficulty.ToString();
|
||||
var _cht = bpDistinctCharts.TryGetValue(key, out var value) ? value : null;
|
||||
if (_cht != null && _cht.ClearStatus >= _aimedStatus) _count++;
|
||||
|
||||
}
|
||||
else if (_aimedDifficulty < (int)Difficulty.Easy)
|
||||
{
|
||||
for (int diff = (int)Difficulty.Easy; diff <= (int)Difficulty.Edit; diff++)
|
||||
{
|
||||
if (_values[_aimedDifficulty] >= _aimedStatus)
|
||||
_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Array.Exists(_values, _v => _v >= _aimedStatus))
|
||||
string key = _songId + diff.ToString();
|
||||
var _cht = bpDistinctCharts.TryGetValue(key, out var value) ? value : null;
|
||||
if (_cht != null && _cht.ClearStatus >= _aimedStatus)
|
||||
{
|
||||
_count++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -310,33 +302,15 @@ namespace TJAPlayer3
|
||||
int _base = i * this.RequiredArgCount;
|
||||
string _genreName = this.Reference[i];
|
||||
int _songCount = this.Values[_base];
|
||||
_aimedDifficulty = this.Values[_base + 1];
|
||||
_aimedStatus = this.Values[_base + 2];
|
||||
int _innerCount = 0;
|
||||
_aimedStatus = this.Values[_base + 1];
|
||||
|
||||
var _songList = CSongDict.tGetNodesByGenreName(_genreName);
|
||||
foreach (string songId in _songList)
|
||||
{
|
||||
_innerCount = 0;
|
||||
if (_sf.ContainsKey(songId))
|
||||
{
|
||||
var _values = _sf[songId].d;
|
||||
if (_aimedDifficulty >= 0 && _aimedDifficulty < 4)
|
||||
{
|
||||
if (_values[_aimedDifficulty] >= _aimedStatus)
|
||||
_innerCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Array.Exists(_values, _v => _v >= _aimedStatus))
|
||||
_innerCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_innerCount >= _songCount)
|
||||
_count++;
|
||||
int _satifsiedCount = 0;
|
||||
if (_aimedStatus == (int)EClearStatus.NONE) _satifsiedCount = chartStats.SongGenrePlays.TryGetValue(_genreName, out var value) ? value : 0;
|
||||
else if (_aimedStatus <= (int)EClearStatus.CLEAR) _satifsiedCount = chartStats.SongGenreClears.TryGetValue(_genreName, out var value) ? value : 0;
|
||||
else if (_aimedStatus == (int)EClearStatus.FC) _satifsiedCount = chartStats.SongGenreFCs.TryGetValue(_genreName, out var value) ? value : 0;
|
||||
else return _satifsiedCount = chartStats.SongGenrePerfects.TryGetValue(_genreName, out var value) ? value : 0;
|
||||
|
||||
if (_satifsiedCount >= _songCount) _count++;
|
||||
}
|
||||
return _count;
|
||||
}
|
||||
|
@ -162,6 +162,20 @@ namespace TJAPlayer3
|
||||
|
||||
#region [Mod flags]
|
||||
|
||||
static public bool tPlayIsStock(int player)
|
||||
{
|
||||
int actual = TJAPlayer3.GetActualPlayer(player);
|
||||
|
||||
if (TJAPlayer3.ConfigIni.nFunMods[actual] != EFunMods.NONE) return false;
|
||||
if (TJAPlayer3.ConfigIni.bJust[actual] != 0) return false;
|
||||
if (TJAPlayer3.ConfigIni.nTimingZones[actual] != 2) return false;
|
||||
if (TJAPlayer3.ConfigIni.n演奏速度 != 20) return false;
|
||||
if (TJAPlayer3.ConfigIni.eRandom[actual] != Eランダムモード.OFF) return false;
|
||||
if (TJAPlayer3.ConfigIni.eSTEALTH[actual] != EStealthMode.OFF) return false;
|
||||
if (TJAPlayer3.ConfigIni.nScrollSpeed[actual] != 9) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
static public Int64 tModsToPlayModsFlags(int player)
|
||||
{
|
||||
byte[] _flags = new byte[8] { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
Loading…
Reference in New Issue
Block a user