mirror of
https://github.com/zkldi/Tachi.git
synced 2026-09-30 02:48:01 +03:00
1219 lines
63 KiB
Diff
1219 lines
63 KiB
Diff
diff --git a/Scripts/WF-Profiles.lua b/Scripts/WF-Profiles.lua
|
|
index 2c87831..6b62c0c 100644
|
|
--- a/Scripts/WF-Profiles.lua
|
|
+++ b/Scripts/WF-Profiles.lua
|
|
@@ -16,19 +16,26 @@
|
|
-- HERE IT IS BOYS. IT'S THE HASH CACHE #HASHCASH
|
|
WF.HashCache = {}
|
|
|
|
+-- HERE IT IS BOYS. IT'S THE ZKLDI CACHE #ZCACHE
|
|
+-- we hijack this process to create useful chart info ourselves
|
|
+-- i'm too lazy to write my own proper sm parser
|
|
+-- and sm sucks
|
|
+-- sorry not sorry
|
|
+WF.ZkldiDump = {};
|
|
+
|
|
WF.InitPlayerProfiles = function()
|
|
- -- these will always be indexed by player number
|
|
+ -- these will always be indexed by player number
|
|
WF.PlayerProfileStats = {}
|
|
|
|
-- there will be some checks for the validity of a profile when loaded, and if it's found to be invalid, set a
|
|
-- flag to indicate not to try to save anything
|
|
- WF.ProfileInvalid = {false,false}
|
|
+ WF.ProfileInvalid = { false, false }
|
|
|
|
-- this is just my own variable to keep track of how many songs has been played per player
|
|
- WF.CurrentSessionSongsPlayed = {0,0}
|
|
+ WF.CurrentSessionSongsPlayed = { 0, 0 }
|
|
|
|
-- subtitle to appear under name on profile card
|
|
- WF.ProfileCardSubtitle = {"",""}
|
|
+ WF.ProfileCardSubtitle = { "", "" }
|
|
end
|
|
WF.InitPlayerProfiles()
|
|
|
|
@@ -151,17 +158,17 @@ WF.NewPlayerProfileSongStats = function()
|
|
BestPercentDP = 0,
|
|
BestPercentDP_ITG = 0,
|
|
Cleared_ITG = nil,
|
|
- BestFAPlusCounts = {0,0,0},
|
|
+ BestFAPlusCounts = { 0, 0, 0 },
|
|
TotalSteps = 0,
|
|
TotalHolds = 0,
|
|
TotalRolls = 0,
|
|
TotalMines = 0,
|
|
BestPlay = {
|
|
DateObtained = "0000-00-00 00:00:00",
|
|
- Judgments = {0,0,0,0,0,0,0,0,0},
|
|
- FAPlus = {0,0},
|
|
- LifeBarVals = {1000,1000,1000},
|
|
- ScoreAtLifeEmpty = {0,0,0},
|
|
+ Judgments = { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
|
+ FAPlus = { 0, 0 },
|
|
+ LifeBarVals = { 1000, 1000, 1000 },
|
|
+ ScoreAtLifeEmpty = { 0, 0, 0 },
|
|
SignificantMods = {}
|
|
}
|
|
}
|
|
@@ -191,7 +198,7 @@ WF.MergePlayerProfileSongStats = function(stats1, stats2)
|
|
|
|
-- exit if hash and rate aren't the same (no reason to ever merge in this case, so catch it here and log it)
|
|
if (not ((not iscourse) and stats1.ChartHash == stats2.ChartHash and stats1.RateMod == stats2.RateMod))
|
|
- and (not ((iscourse) and stats1.CourseID == stats2.CourseID and stats1.RateMod == stats2.RateMod)) then
|
|
+ and (not ((iscourse) and stats1.CourseID == stats2.CourseID and stats1.RateMod == stats2.RateMod)) then
|
|
Trace(string.format("Stats merge error:\nhash/id 1: %s\nrate 1: %s\nhash/id 2: %s\nrate 2:%s",
|
|
iscourse and stats1.CourseID or stats1.ChartHash, stats1.RateMod,
|
|
iscourse and stats2.CourseID or stats2.ChartHash, stats2.RateMod))
|
|
@@ -250,8 +257,8 @@ WF.ConsolidateProfileSongAndCourseStats = function(pn)
|
|
-- first loop through and reassign bad hashes; this needs to be done in a separate loop
|
|
for score in ivalues(stats) do
|
|
if (WF.HashCache) and (score.ChartHash) and (score.ChartHash ~= "") and (score.ChartID)
|
|
- and (score.ChartID ~= "") and (WF.HashCache[score.ChartID])
|
|
- and (score.ChartHash ~= WF.HashCache[score.ChartID]) then
|
|
+ and (score.ChartID ~= "") and (WF.HashCache[score.ChartID])
|
|
+ and (score.ChartHash ~= WF.HashCache[score.ChartID]) then
|
|
score.ChartHash = WF.HashCache[score.ChartID]
|
|
end
|
|
end
|
|
@@ -305,7 +312,7 @@ end
|
|
WF.AddPlayerProfileSongStatsFromSteps = function(song, steps, rate, hash, pn)
|
|
-- create a new stats object with information from the song and steps passed (and optional rate mod),
|
|
-- and add it to the player profile stats table.
|
|
- local player = "PlayerNumber_P"..pn
|
|
+ local player = "PlayerNumber_P" .. pn
|
|
|
|
if not song then
|
|
song = (not GAMESTATE:IsCourseMode()) and GAMESTATE:GetCurrentSong() or GAMESTATE:GetCurrentCourse()
|
|
@@ -323,7 +330,7 @@ WF.AddPlayerProfileSongStatsFromSteps = function(song, steps, rate, hash, pn)
|
|
WF.SongStatsUpdateChartAttributes(stats, song, steps, hash, pn)
|
|
stats.RateMod = rate
|
|
stats.PlayCount = 0
|
|
-
|
|
+
|
|
WF.AddSongStatsToProfile(stats, pn)
|
|
return stats
|
|
end
|
|
@@ -339,7 +346,7 @@ WF.SavePlayerProfileStats = function(pn)
|
|
local stats = WF.PlayerProfileStats[pn]
|
|
if (not stats) or stats == {} then return end
|
|
|
|
- local dir = PROFILEMAN:GetProfileDir("ProfileSlot_Player"..pn)
|
|
+ local dir = PROFILEMAN:GetProfileDir("ProfileSlot_Player" .. pn)
|
|
if (not dir) or dir == "" then return end
|
|
|
|
-- table for all sections of the file
|
|
@@ -347,7 +354,8 @@ WF.SavePlayerProfileStats = function(pn)
|
|
|
|
-- first, the general stats
|
|
local statsstr = string.format("#STATS\n%s\n%d\n%d\n%d\n%d,%d,%d,%d,%d,%d\n%d,%d\n%d,%d\n%d,%d\n%s\n%s",
|
|
- GetThemeVersion(), stats.SkillLv, stats.SongsPlayed, stats.CoursesPlayed, stats.TotalTapJudgments[1], stats.TotalTapJudgments[2],
|
|
+ GetThemeVersion(), stats.SkillLv, stats.SongsPlayed, stats.CoursesPlayed, stats.TotalTapJudgments[1],
|
|
+ stats.TotalTapJudgments[2],
|
|
stats.TotalTapJudgments[3], stats.TotalTapJudgments[4], stats.TotalTapJudgments[5], stats.TotalTapJudgments[6],
|
|
stats.TotalHolds[1], stats.TotalHolds[2], stats.TotalHolds[3], stats.TotalHolds[4],
|
|
stats.TotalMines[1], stats.TotalMines[2], stats.LastSongPlayed, stats.LastPlayedDate)
|
|
@@ -357,7 +365,7 @@ WF.SavePlayerProfileStats = function(pn)
|
|
for chart in ivalues(stats.SongStats) do
|
|
-- first, the general stats for the chart
|
|
local hash = chart.ChartHash and chart.ChartHash or "-"
|
|
- local itgdp = tostring(chart.BestPercentDP_ITG)..(chart.Cleared_ITG or "")
|
|
+ local itgdp = tostring(chart.BestPercentDP_ITG) .. (chart.Cleared_ITG or "")
|
|
table.insert(ft, string.format("#SONG\n%s\n%s\n%s\n%s\n%s\n%s\n%d\n%d\n%d\n%d\n%s\n%d,%d,%d\n%d\n%d,%d,%d",
|
|
chart.SongFullTitle, chart.SongArtist, chart.BPM, hash, chart.ChartID, chart.RateMod,
|
|
chart.DifficultyRating, chart.PlayCount, chart.BestClearType, chart.BestPercentDP, itgdp,
|
|
@@ -380,7 +388,7 @@ WF.SavePlayerProfileStats = function(pn)
|
|
-- repeat above for courses
|
|
for course in ivalues(stats.CourseStats) do
|
|
-- first, the general stats for the course
|
|
- local itgdp = tostring(course.BestPercentDP_ITG)..(course.Cleared_ITG or "")
|
|
+ local itgdp = tostring(course.BestPercentDP_ITG) .. (course.Cleared_ITG or "")
|
|
table.insert(ft, string.format("#COURSE\n%s\n%s\n%s\n%s\n%d\n%d\n%d\n%d\n%s\n%d,%d,%d\n%d\n%d,%d,%d",
|
|
course.CourseTitle, course.BPM, course.CourseID, course.RateMod,
|
|
course.DifficultyRating, course.PlayCount, course.BestClearType, course.BestPercentDP, itgdp,
|
|
@@ -409,16 +417,16 @@ WF.SavePlayerProfileStats = function(pn)
|
|
|
|
-- write file
|
|
local fstr = table.concat(ft, "\n")
|
|
- if File.Write(dir.."/PlayerStats.wfs",fstr) then
|
|
- Trace("Player "..pn.." profile stats saved.")
|
|
+ if File.Write(dir .. "/PlayerStats.wfs", fstr) then
|
|
+ Trace("Player " .. pn .. " profile stats saved.")
|
|
else
|
|
- SM("Player "..pn.." profile stats failed to save!")
|
|
+ SM("Player " .. pn .. " profile stats failed to save!")
|
|
end
|
|
end
|
|
|
|
WF.LoadPlayerProfileStats = function(pn)
|
|
-- Load all the stats from the main stats file
|
|
- local dir = PROFILEMAN:GetProfileDir("ProfileSlot_Player"..pn)
|
|
+ local dir = PROFILEMAN:GetProfileDir("ProfileSlot_Player" .. pn)
|
|
WF.ProfileCardSubtitle[pn] = ""
|
|
if (not dir) or dir == "" then
|
|
-- nil the stats here and exit; this essentially means a guest profile is being used
|
|
@@ -429,24 +437,24 @@ WF.LoadPlayerProfileStats = function(pn)
|
|
local stats = WF.ProfileStatsTemplate()
|
|
|
|
-- get subtitle for profile card
|
|
- if FILEMAN:DoesFileExist(dir.."/subtitle.txt") then
|
|
- WF.ProfileCardSubtitle[pn] = File.Read(dir.."/subtitle.txt")
|
|
+ if FILEMAN:DoesFileExist(dir .. "/subtitle.txt") then
|
|
+ WF.ProfileCardSubtitle[pn] = File.Read(dir .. "/subtitle.txt")
|
|
-- some light processing, since who knows what people will write in there
|
|
WF.ProfileCardSubtitle[pn] = (WF.ProfileCardSubtitle[pn]:gsub("[\r\f\n]", " ")):sub(1, 20)
|
|
else
|
|
- File.Write(dir.."/subtitle.txt", "")
|
|
+ File.Write(dir .. "/subtitle.txt", "")
|
|
end
|
|
|
|
- if not FILEMAN:DoesFileExist(dir.."/PlayerStats.wfs") then
|
|
+ if not FILEMAN:DoesFileExist(dir .. "/PlayerStats.wfs") then
|
|
-- file has not been created; just return
|
|
WF.PlayerProfileStats[pn] = stats
|
|
return
|
|
end
|
|
|
|
- local sfile = File.Read(dir.."/PlayerStats.wfs")
|
|
+ local sfile = File.Read(dir .. "/PlayerStats.wfs")
|
|
if not sfile then
|
|
-- error loading file
|
|
- SM("Error loading stats for player "..pn.."!")
|
|
+ SM("Error loading stats for player " .. pn .. "!")
|
|
WF.PlayerProfileStats[pn] = nil
|
|
return
|
|
end
|
|
@@ -501,8 +509,8 @@ WF.LoadPlayerProfileStats = function(pn)
|
|
stats.ForceImportCourses = true -- force course import since they weren't available before
|
|
|
|
-- back up old player stats file
|
|
- if not FILEMAN:DoesFileExist(dir.."/PlayerStats_062") then
|
|
- File.Write(dir.."/PlayerStats_062", sfile)
|
|
+ if not FILEMAN:DoesFileExist(dir .. "/PlayerStats_062") then
|
|
+ File.Write(dir .. "/PlayerStats_062", sfile)
|
|
end
|
|
-- back up ecfa stats file if exists
|
|
BackUpECFA2021Stats(dir)
|
|
@@ -520,11 +528,11 @@ WF.LoadPlayerProfileStats = function(pn)
|
|
elseif l == 5 then
|
|
-- judgment counts
|
|
local judges = line:split_tonumber()
|
|
- stats.TotalTapJudgments = {judges[1],judges[2],judges[3],judges[4],judges[5],judges[6]}
|
|
+ stats.TotalTapJudgments = { judges[1], judges[2], judges[3], judges[4], judges[5], judges[6] }
|
|
elseif l == 6 then
|
|
-- holds
|
|
local holds = line:split_tonumber()
|
|
- stats.TotalHolds = {holds[1],holds[2],0,0}
|
|
+ stats.TotalHolds = { holds[1], holds[2], 0, 0 }
|
|
elseif l == 7 then
|
|
-- rolls
|
|
local rolls = line:split_tonumber()
|
|
@@ -533,7 +541,7 @@ WF.LoadPlayerProfileStats = function(pn)
|
|
elseif l == 8 then
|
|
-- mines
|
|
local mines = line:split_tonumber()
|
|
- stats.TotalMines = {mines[1],mines[2]}
|
|
+ stats.TotalMines = { mines[1], mines[2] }
|
|
elseif l == 9 then
|
|
-- last song played
|
|
stats.LastSongPlayed = line
|
|
@@ -597,7 +605,7 @@ WF.LoadPlayerProfileStats = function(pn)
|
|
elseif l == 12 then
|
|
-- high fa+ counts
|
|
local counts = line:split_tonumber()
|
|
- song.BestFAPlusCounts = {counts[1],counts[2],counts[3]}
|
|
+ song.BestFAPlusCounts = { counts[1], counts[2], counts[3] }
|
|
elseif l == 13 then
|
|
-- total steps
|
|
song.TotalSteps = tonumber(line)
|
|
@@ -614,7 +622,7 @@ WF.LoadPlayerProfileStats = function(pn)
|
|
elseif l == 16 then
|
|
-- tap judgments
|
|
local counts = line:split_tonumber()
|
|
- song.BestPlay.Judgments = {counts[1],counts[2],counts[3],counts[4],counts[5],counts[6],0,0,0}
|
|
+ song.BestPlay.Judgments = { counts[1], counts[2], counts[3], counts[4], counts[5], counts[6], 0, 0, 0 }
|
|
elseif l == 17 then
|
|
-- hold judgments
|
|
local held = line:split_tonumber()
|
|
@@ -626,15 +634,15 @@ WF.LoadPlayerProfileStats = function(pn)
|
|
elseif l == 19 then
|
|
-- fa+
|
|
local counts = line:split_tonumber()
|
|
- song.BestPlay.FAPlus = {counts[1],counts[2]}
|
|
+ song.BestPlay.FAPlus = { counts[1], counts[2] }
|
|
elseif l == 20 then
|
|
-- lifebar vals
|
|
local vals = line:split_tonumber()
|
|
- song.BestPlay.LifeBarVals = {vals[1],vals[2],vals[3]}
|
|
+ song.BestPlay.LifeBarVals = { vals[1], vals[2], vals[3] }
|
|
elseif l == 21 then
|
|
-- score at life empty
|
|
local vals = line:split_tonumber()
|
|
- song.BestPlay.ScoreAtLifeEmpty = {vals[1],vals[2],vals[3]}
|
|
+ song.BestPlay.ScoreAtLifeEmpty = { vals[1], vals[2], vals[3] }
|
|
elseif l == 22 then
|
|
-- significant mods
|
|
local mods = split(",", line)
|
|
@@ -662,7 +670,7 @@ WF.LoadPlayerProfileStats = function(pn)
|
|
WF.PreloadClearsAndGrades(pn)
|
|
end
|
|
|
|
- Trace("Player "..pn.." profile stats loaded.")
|
|
+ Trace("Player " .. pn .. " profile stats loaded.")
|
|
end
|
|
|
|
WF.CalculateClearTypeAndGradeCounts = function(pn)
|
|
@@ -670,12 +678,12 @@ WF.CalculateClearTypeAndGradeCounts = function(pn)
|
|
local stats = WF.PlayerProfileStats[pn]
|
|
if not stats then return end
|
|
|
|
- stats.ClearTypeCounts = {0,0,0,0,0,0,0,0, 0} -- last index here is basically a dummy for unplayed
|
|
- stats.GradeCounts = {0,0,0,0,0,0,0}
|
|
- stats.GradeCounts_ITG = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
|
|
- stats.CourseClearTypeCounts = {0,0,0,0,0,0,0,0, 0}
|
|
- stats.CourseGradeCounts = {0,0,0,0,0,0,0}
|
|
- stats.CourseGradeCounts_ITG = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
|
|
+ stats.ClearTypeCounts = { 0, 0, 0, 0, 0, 0, 0, 0, 0 } -- last index here is basically a dummy for unplayed
|
|
+ stats.GradeCounts = { 0, 0, 0, 0, 0, 0, 0 }
|
|
+ stats.GradeCounts_ITG = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
|
|
+ stats.CourseClearTypeCounts = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }
|
|
+ stats.CourseGradeCounts = { 0, 0, 0, 0, 0, 0, 0 }
|
|
+ stats.CourseGradeCounts_ITG = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
|
|
|
|
for song in ivalues(stats.SongStats) do
|
|
stats.ClearTypeCounts[song.BestClearType] = stats.ClearTypeCounts[song.BestClearType] + 1
|
|
@@ -703,15 +711,15 @@ WF.ProfileStatsTemplate = function()
|
|
SkillLv = 0,
|
|
SongsPlayed = 0,
|
|
CoursesPlayed = 0,
|
|
- TotalTapJudgments = {0,0,0,0,0,0},
|
|
- TotalHolds = {0,0,0,0},
|
|
- TotalMines = {0,0},
|
|
+ TotalTapJudgments = { 0, 0, 0, 0, 0, 0 },
|
|
+ TotalHolds = { 0, 0, 0, 0 },
|
|
+ TotalMines = { 0, 0 },
|
|
LastSongPlayed = "3D Movie Maker/Bistro Evil Theme",
|
|
LastPlayedDate = WF.DateString(),
|
|
|
|
- ClearTypeCounts = {0,0,0,0,0,0,0,0},
|
|
- GradeCounts = {0,0,0,0,0,0,0},
|
|
- SessionAchievements = {0,0,0,0,0,0,0},
|
|
+ ClearTypeCounts = { 0, 0, 0, 0, 0, 0, 0, 0 },
|
|
+ GradeCounts = { 0, 0, 0, 0, 0, 0, 0 },
|
|
+ SessionAchievements = { 0, 0, 0, 0, 0, 0, 0 },
|
|
|
|
GroupClearsAndGrades = {},
|
|
|
|
@@ -738,10 +746,10 @@ WF.WriteDetailedHighScoreStats = function(pn, hsitem, filenameext, filename, cou
|
|
local song, steps, detailed
|
|
if not courseind then
|
|
song = GAMESTATE:GetCurrentSong()
|
|
- steps = GAMESTATE:GetCurrentSteps("PlayerNumber_P"..pn)
|
|
- detailed = SL["P"..pn].Stages.Stats[SL.Global.Stages.PlayedThisGame + 1].detailed_judgments
|
|
+ steps = GAMESTATE:GetCurrentSteps("PlayerNumber_P" .. pn)
|
|
+ detailed = SL["P" .. pn].Stages.Stats[SL.Global.Stages.PlayedThisGame + 1].detailed_judgments
|
|
else
|
|
- local te = GAMESTATE:GetCurrentTrail("PlayerNumber_P"..pn):GetTrailEntry(courseind-1)
|
|
+ local te = GAMESTATE:GetCurrentTrail("PlayerNumber_P" .. pn):GetTrailEntry(courseind - 1)
|
|
song = te:GetSong()
|
|
steps = te:GetSteps()
|
|
detailed = WF.DetailedJudgmentsPerSongInCourse[pn][courseind]
|
|
@@ -751,7 +759,7 @@ WF.WriteDetailedHighScoreStats = function(pn, hsitem, filenameext, filename, cou
|
|
|
|
local hashorid = hsitem and (hsitem.ChartHash and hsitem.ChartHash or hsitem.ChartID)
|
|
|
|
- local abbrev = {Miss = "M", Held = "H", LetGo = "D", HitMine = "N"}
|
|
+ local abbrev = { Miss = "M", Held = "H", LetGo = "D", HitMine = "N" }
|
|
|
|
-- file string will be built from a table to avoid using .. which is bad on performance
|
|
local ft = {}
|
|
@@ -759,7 +767,7 @@ WF.WriteDetailedHighScoreStats = function(pn, hsitem, filenameext, filename, cou
|
|
if not hsitem then
|
|
-- create a dummy (haha dummy!!!! HHHASHAHAHAHHSH) hsitem from steps if none is passed in
|
|
-- steps can be passed in as an argument, which is useful for courses
|
|
- local player = "PlayerNumber_P"..pn
|
|
+ local player = "PlayerNumber_P" .. pn
|
|
hsitem = WF.NewPlayerProfileSongStats()
|
|
local id = WF.GetStepsID(song, steps)
|
|
hashorid = WF.HashCache[id]
|
|
@@ -774,14 +782,15 @@ WF.WriteDetailedHighScoreStats = function(pn, hsitem, filenameext, filename, cou
|
|
end
|
|
|
|
local fname = filename or LookupIdentifier(hashorid, hsitem.RateMod):gsub("/", "]]][[[")
|
|
- if filenameext then fname = fname..filenameext end
|
|
- local fullpath = PROFILEMAN:GetProfileDir("ProfileSlot_Player"..pn).."/detailed/"..fname
|
|
+ if filenameext then fname = fname .. filenameext end
|
|
+ local fullpath = PROFILEMAN:GetProfileDir("ProfileSlot_Player" .. pn) .. "/detailed/" .. fname
|
|
|
|
-- general info
|
|
local smods = (#hsitem.BestPlay.SignificantMods > 0) and table.concat(hsitem.BestPlay.SignificantMods, ",") or "-"
|
|
local songstr = string.format("%s\n%s\n%s\n%s\n%s\n%d\n%s\n%s\n%d\n%d\n%d\n%d\n%d\n%d\n%s",
|
|
GetThemeVersion(), hsitem.SongFullTitle, hsitem.SongArtist, hsitem.BPM, hsitem.ChartID, hsitem.DifficultyRating,
|
|
- hsitem.BestPlay.DateObtained, hsitem.RateMod, hsitem.TotalSteps, hsitem.TotalHolds, hsitem.BestPlay.Judgments[7],
|
|
+ hsitem.BestPlay.DateObtained, hsitem.RateMod, hsitem.TotalSteps, hsitem.TotalHolds, hsitem.BestPlay.Judgments[7]
|
|
+ ,
|
|
hsitem.TotalRolls, hsitem.BestPlay.Judgments[8], hsitem.TotalMines, smods)
|
|
table.insert(ft, songstr)
|
|
|
|
@@ -792,7 +801,7 @@ WF.WriteDetailedHighScoreStats = function(pn, hsitem, filenameext, filename, cou
|
|
local off = (#judge == 3 or judge[2] == "Miss") and abbrev[judge[2]] or string.format("%f", judge[4])
|
|
table.insert(ft, string.format("%f;%s;%s", judge[1], off, p))
|
|
end
|
|
-
|
|
+
|
|
table.insert(ft, "")
|
|
|
|
local fstr = table.concat(ft, "\n")
|
|
@@ -813,7 +822,7 @@ WF.WriteDetailedHighScoreStatsFromCourseList = function(pn, filenameext, list)
|
|
-- don't ever use the word leveraged in that way, it's really dumb ok
|
|
local count = 0
|
|
for ind in ivalues(list) do
|
|
- if WF.WriteDetailedHighScoreStats(pn, nil, filenameext, nil, ind) then
|
|
+ if WF.WriteDetailedHighScoreStats(pn, nil, filenameext, nil, ind) then
|
|
count = count + 1
|
|
end
|
|
end
|
|
@@ -829,18 +838,18 @@ WF.WriteAllDetailedHighScoresForCourse = function(pn, wfuslist, itguslist)
|
|
|
|
-- save each individual file to saved directory
|
|
for i = 1, #WF.DetailedJudgmentsPerSongInCourse[pn] do
|
|
- local te = GAMESTATE:GetCurrentTrail("PlayerNumber_P"..pn):GetTrailEntry(i-1)
|
|
+ local te = GAMESTATE:GetCurrentTrail("PlayerNumber_P" .. pn):GetTrailEntry(i - 1)
|
|
local song = te:GetSong()
|
|
local steps = te:GetSteps()
|
|
local songtitle = (song:GetDisplayMainTitle():gsub("[^A-Z^a-z^0-9]", ""))
|
|
- if (not songtitle) or (songtitle == "") then
|
|
- songtitle = (song:GetTranslitMainTitle():gsub("[^A-Z^a-z^0-9]", ""))
|
|
- end
|
|
- if (not songtitle) or (songtitle == "") then songtitle = "UnknownSong" end
|
|
- local diff = THEME:GetString("Difficulty",
|
|
- ToEnumShortString(steps:GetDifficulty()))
|
|
- local datestr = (WF.DateTimeString():gsub(":", ""):gsub(" ", "_"))
|
|
- local fname = "/saved/"..songtitle.."_"..diff.."_"..datestr
|
|
+ if (not songtitle) or (songtitle == "") then
|
|
+ songtitle = (song:GetTranslitMainTitle():gsub("[^A-Z^a-z^0-9]", ""))
|
|
+ end
|
|
+ if (not songtitle) or (songtitle == "") then songtitle = "UnknownSong" end
|
|
+ local diff = THEME:GetString("Difficulty",
|
|
+ ToEnumShortString(steps:GetDifficulty()))
|
|
+ local datestr = (WF.DateTimeString():gsub(":", ""):gsub(" ", "_"))
|
|
+ local fname = "/saved/" .. songtitle .. "_" .. diff .. "_" .. datestr
|
|
|
|
if WF.WriteDetailedHighScoreStats(pn, nil, nil, fname, i) then
|
|
count = count + 1
|
|
@@ -932,7 +941,7 @@ WF.MergeMachineProfileSongStats = function(stats1, stats2)
|
|
local newstats = WF.NewMachineProfileSongStats()
|
|
|
|
if (not ((not iscourse) and stats1.ChartHash == stats2.ChartHash and stats1.RateMod == stats2.RateMod))
|
|
- and (not ((iscourse) and stats1.CourseID == stats2.CourseID and stats1.RateMod == stats2.RateMod)) then
|
|
+ and (not ((iscourse) and stats1.CourseID == stats2.CourseID and stats1.RateMod == stats2.RateMod)) then
|
|
Trace(string.format("Stats merge error:\nhash/id 1: %s\nrate 1: %s\nhash/id 2: %s\nrate 2:%s",
|
|
(not iscourse) and stats1.ChartHash or stats1.CourseID, stats1.RateMod,
|
|
(not iscourse) and stats2.ChartHash or stats2.CourseID, stats2.RateMod))
|
|
@@ -996,7 +1005,7 @@ WF.SongStatsUpdateChartAttributes = function(stats, song, steps, hash, pn)
|
|
-- a player song stats object, meaning step counts etc will need to be updated too.
|
|
local iscourse = (stats.CourseTitle ~= nil) -- if course, "song" is course and "steps" is trail
|
|
local player
|
|
- if pn then player = "PlayerNumber_P"..pn end
|
|
+ if pn then player = "PlayerNumber_P" .. pn end
|
|
local id = WF.GetItemID(song, steps)
|
|
|
|
-- generate hash if one isn't passed in (better to not parse again if we don't need to)
|
|
@@ -1053,7 +1062,7 @@ WF.AddMachineProfileSongStatsFromSteps = function(song, steps, rate, hash, playe
|
|
WF.SongStatsUpdateChartAttributes(stats, song, steps, hash)
|
|
stats.RateMod = rate
|
|
stats.PlayCount = 0
|
|
-
|
|
+
|
|
WF.AddSongStatsToProfile(stats)
|
|
return stats
|
|
end
|
|
@@ -1127,11 +1136,11 @@ WF.SaveMachineProfileStats = function()
|
|
song.BPM, hash, song.ChartID, song.RateMod, song.DifficultyRating, song.PlayCount))
|
|
for score in ivalues(song.HighScoreList) do
|
|
table.insert(ft, string.format("$SCORE\n%s\n%s\n%s\n%s\n%d", score.PlayerFullName, score.PlayerHSName,
|
|
- score.PlayerGuid, score.DateObtained, score.PercentDP))
|
|
+ score.PlayerGuid, score.DateObtained, score.PercentDP))
|
|
end
|
|
for score in ivalues(song.HighScoreList_ITG) do
|
|
table.insert(ft, string.format("$ITG\n%s\n%s\n%s\n%s\n%d", score.PlayerFullName, score.PlayerHSName,
|
|
- score.PlayerGuid, score.DateObtained, score.PercentDP))
|
|
+ score.PlayerGuid, score.DateObtained, score.PercentDP))
|
|
end
|
|
end
|
|
|
|
@@ -1141,11 +1150,11 @@ WF.SaveMachineProfileStats = function()
|
|
course.BPM, course.CourseID, course.RateMod, course.DifficultyRating, course.PlayCount))
|
|
for score in ivalues(course.HighScoreList) do
|
|
table.insert(ft, string.format("$SCORE\n%s\n%s\n%s\n%s\n%d", score.PlayerFullName, score.PlayerHSName,
|
|
- score.PlayerGuid, score.DateObtained, score.PercentDP))
|
|
+ score.PlayerGuid, score.DateObtained, score.PercentDP))
|
|
end
|
|
for score in ivalues(course.HighScoreList_ITG) do
|
|
table.insert(ft, string.format("$ITG\n%s\n%s\n%s\n%s\n%d", score.PlayerFullName, score.PlayerHSName,
|
|
- score.PlayerGuid, score.DateObtained, score.PercentDP))
|
|
+ score.PlayerGuid, score.DateObtained, score.PercentDP))
|
|
end
|
|
end
|
|
|
|
@@ -1153,7 +1162,7 @@ WF.SaveMachineProfileStats = function()
|
|
|
|
-- write to file
|
|
local fstr = table.concat(ft, "\n")
|
|
- if File.Write(dir.."/MachineStats.wfm",fstr) then
|
|
+ if File.Write(dir .. "/MachineStats.wfm", fstr) then
|
|
Trace("Machine profile stats saved.")
|
|
else
|
|
SM("Machine profile stats failed to save!")
|
|
@@ -1176,12 +1185,12 @@ WF.LoadMachineProfileStats = function()
|
|
|
|
WF.MachineProfileStats = WF.MachineProfileStatsTemplate()
|
|
|
|
- if not FILEMAN:DoesFileExist(dir.."/MachineStats.wfm") then
|
|
+ if not FILEMAN:DoesFileExist(dir .. "/MachineStats.wfm") then
|
|
-- file has not been created; just return
|
|
return
|
|
end
|
|
|
|
- local sfile = File.Read(dir.."/MachineStats.wfm")
|
|
+ local sfile = File.Read(dir .. "/MachineStats.wfm")
|
|
if not sfile then
|
|
-- error loading file
|
|
SM("Error loading stats for machine profile!")
|
|
@@ -1251,7 +1260,7 @@ WF.LoadMachineProfileStats = function()
|
|
score.PercentDP = tonumber(line)
|
|
-- insert into corresponding table
|
|
local ext = (token == "ITG") and "_ITG" or ""
|
|
- curstats["HighScoreList"..ext][#curstats["HighScoreList"..ext]+1] = score
|
|
+ curstats["HighScoreList" .. ext][#curstats["HighScoreList" .. ext] + 1] = score
|
|
end
|
|
end
|
|
end
|
|
@@ -1269,7 +1278,7 @@ end
|
|
WF.FindProfileSongStats = function(hashorid, rate, pn)
|
|
-- pass in either a hash or a chart id. simple logic will determine which to use.
|
|
local identifier = hashorid:match("/") and "ChartID" or "ChartHash"
|
|
-
|
|
+
|
|
-- pass no pn for machine profile
|
|
local stats = pn ~= nil and WF.PlayerProfileStats[pn] or WF.MachineProfileStats
|
|
if not stats then return end
|
|
@@ -1421,13 +1430,13 @@ WF.UpdateProfilesOnEvaluation = function(hashes)
|
|
local pn = tonumber(player:sub(-1))
|
|
local steps = (not iscourse) and GAMESTATE:GetCurrentSteps(player) or GAMESTATE:GetCurrentTrail(player)
|
|
allitems[pn] = {}
|
|
- table.insert(allitems[pn], {song, steps})
|
|
+ table.insert(allitems[pn], { song, steps })
|
|
if iscourse then
|
|
for i = 1, WF.CurrentSongInCourse do
|
|
- local te = steps:GetTrailEntry(i-1)
|
|
+ local te = steps:GetTrailEntry(i - 1)
|
|
local songincourse = te:GetSong()
|
|
local stepsincourse = te:GetSteps()
|
|
- table.insert(allitems[pn], {songincourse, stepsincourse})
|
|
+ table.insert(allitems[pn], { songincourse, stepsincourse })
|
|
end
|
|
end
|
|
end
|
|
@@ -1464,16 +1473,16 @@ WF.UpdateProfilesOnEvaluation = function(hashes)
|
|
local itgdata = (not iscourse) and WF.ITGJudgmentData[pn]
|
|
or WF.ITGJudgmentData[pn][WF.CurrentSongInCourse]
|
|
local ts = itgdata[#itgdata] and (itgdata[#itgdata][3] + 0.02) or 0.1
|
|
- table.insert(itgdata, {nil, 0, ts})
|
|
+ table.insert(itgdata, { nil, 0, ts })
|
|
-- now just insert into wf lifebar tables
|
|
- for i = 1, #WF.LifeBarNames do
|
|
+ for i = 1, #WF.LifeBarNames do
|
|
if WF.LifeBarChanges[pn][i] then
|
|
-- reuse ts here because itg tracks life at every judgment rather than just changes
|
|
-- what the fuck am i doing lol
|
|
-- [TODO] - this causes a funny bug when itg fails early and then the song is skipped
|
|
local barchanges = (not iscourse) and WF.LifeBarChanges[pn][i]
|
|
or WF.LifeBarChanges[pn][i][WF.CurrentSongInCourse]
|
|
- table.insert(barchanges, {0, ts})
|
|
+ table.insert(barchanges, { 0, ts })
|
|
end
|
|
end
|
|
end
|
|
@@ -1503,7 +1512,7 @@ WF.UpdateProfilesOnEvaluation = function(hashes)
|
|
stats.SongsPlayed = stats.SongsPlayed + WF.CurrentSongInCourse
|
|
end
|
|
for i = 1, 5 do
|
|
- stats.TotalTapJudgments[i] = stats.TotalTapJudgments[i] + pss:GetTapNoteScores("TapNoteScore_W"..i)
|
|
+ stats.TotalTapJudgments[i] = stats.TotalTapJudgments[i] + pss:GetTapNoteScores("TapNoteScore_W" .. i)
|
|
end
|
|
stats.TotalTapJudgments[6] = stats.TotalTapJudgments[6] + pss:GetTapNoteScores("TapNoteScore_Miss")
|
|
local ra = pss:GetRadarActual()
|
|
@@ -1515,7 +1524,8 @@ WF.UpdateProfilesOnEvaluation = function(hashes)
|
|
stats.TotalMines[1] = stats.TotalMines[1] + pss:GetTapNoteScores("TapNoteScore_HitMine")
|
|
stats.TotalMines[2] = stats.TotalMines[2] + rv:GetValue("Mines")
|
|
if not iscourse then
|
|
- stats.LastSongPlayed = song:GetSongDir():gsub("/AdditionalSongs/","",1):gsub("/Songs/","",1):sub(1,-2)
|
|
+ stats.LastSongPlayed = song:GetSongDir():gsub("/AdditionalSongs/", "", 1):gsub("/Songs/", "", 1):sub(1,
|
|
+ -2)
|
|
end
|
|
|
|
-- loop through all potential "item stats"
|
|
@@ -1533,18 +1543,18 @@ WF.UpdateProfilesOnEvaluation = function(hashes)
|
|
local curitgclr = itgclr
|
|
local curfaplus = WF.FAPlusCount[pn]
|
|
if cind > 1 then
|
|
- local jt = {curstatsobj:GetJudgmentCount("W1"),curstatsobj:GetJudgmentCount("W2"),
|
|
- curstatsobj:GetJudgmentCount("W3"),curstatsobj:GetJudgmentCount("W4"),
|
|
- curstatsobj:GetJudgmentCount("W5"),curstatsobj:GetJudgmentCount("Miss"),
|
|
- curstatsobj:GetJudgmentCount("Held"),curstatsobj:GetJudgmentCount("LetGo"),
|
|
- curstatsobj:GetJudgmentCount("HitMine")}
|
|
+ local jt = { curstatsobj:GetJudgmentCount("W1"), curstatsobj:GetJudgmentCount("W2"),
|
|
+ curstatsobj:GetJudgmentCount("W3"), curstatsobj:GetJudgmentCount("W4"),
|
|
+ curstatsobj:GetJudgmentCount("W5"), curstatsobj:GetJudgmentCount("Miss"),
|
|
+ curstatsobj:GetJudgmentCount("Held"), curstatsobj:GetJudgmentCount("LetGo"),
|
|
+ curstatsobj:GetJudgmentCount("HitMine") }
|
|
curdp = math.floor(WF.CalculatePercentDP(jt, cursteps, player, false) * 10000)
|
|
- curitgdp = math.floor(WF.CalculatePercentDP(WF.ITGJudgmentCountsPerSongInCourse[pn][cind-1],
|
|
+ curitgdp = math.floor(WF.CalculatePercentDP(WF.ITGJudgmentCountsPerSongInCourse[pn][cind - 1],
|
|
cursteps, player, true) * 10000)
|
|
- curfaplus = WF.FAPlusCountPerSongInCourse[pn][cind-1]
|
|
+ curfaplus = WF.FAPlusCountPerSongInCourse[pn][cind - 1]
|
|
if WF.ITGFailed[pn] then
|
|
- if cind-1 < WF.ITGSongInCourseAtFail[pn] then curitgclr = "C"
|
|
- elseif cind-1 == WF.ITGSongInCourseAtFail[pn] then curitgclr = "F"
|
|
+ if cind - 1 < WF.ITGSongInCourseAtFail[pn] then curitgclr = "C"
|
|
+ elseif cind - 1 == WF.ITGSongInCourseAtFail[pn] then curitgclr = "F"
|
|
else curitgclr = nil end
|
|
end
|
|
end
|
|
@@ -1599,8 +1609,9 @@ WF.UpdateProfilesOnEvaluation = function(hashes)
|
|
end
|
|
local newgrade_itg = CalculateGradeITG(songstats)
|
|
if newgrade_itg < oldgrade_itg then
|
|
- if oldgrade_itg ~= 99 then stats.GradeCounts_ITG[oldgrade_itg] =
|
|
- stats.GradeCounts_ITG[oldgrade_itg] - 1 end
|
|
+ if oldgrade_itg ~= 99 then stats.GradeCounts_ITG[oldgrade_itg] = stats.GradeCounts_ITG[oldgrade_itg]
|
|
+ - 1
|
|
+ end
|
|
stats.GradeCounts_ITG[newgrade_itg] = stats.GradeCounts_ITG[newgrade_itg] + 1
|
|
end
|
|
for i = 1, 2 do
|
|
@@ -1625,7 +1636,7 @@ WF.UpdateProfilesOnEvaluation = function(hashes)
|
|
songstats.BestPercentDP = curdp
|
|
songstats.BestPlay.DateObtained = dateobtained
|
|
for i = 1, 5 do
|
|
- songstats.BestPlay.Judgments[i] = curstatsobj:GetJudgmentCount("TapNoteScore_W"..i)
|
|
+ songstats.BestPlay.Judgments[i] = curstatsobj:GetJudgmentCount("TapNoteScore_W" .. i)
|
|
end
|
|
songstats.BestPlay.Judgments[6] = curstatsobj:GetJudgmentCount("TapNoteScore_Miss")
|
|
songstats.BestPlay.Judgments[7] = (cind == 1) and currv:GetValue("Holds")
|
|
@@ -1641,7 +1652,7 @@ WF.UpdateProfilesOnEvaluation = function(hashes)
|
|
local bar = WF.LifeBarValues[pn][i]
|
|
local saf = (bar.ScoreAtFail ~= -1) and bar.ScoreAtFail or curdp
|
|
if cind > 1 then
|
|
- saf = (not (bar.Failed and bar.SongInCourseAtFail == cind - 1))
|
|
+ saf = (not (bar.Failed and bar.SongInCourseAtFail == cind - 1))
|
|
and bar.ScoreAtFailSongInCourse or curdp
|
|
end
|
|
songstats.BestPlay.ScoreAtLifeEmpty[i] = saf
|
|
@@ -1652,7 +1663,7 @@ WF.UpdateProfilesOnEvaluation = function(hashes)
|
|
if not iscourse then
|
|
WF.WriteDetailedHighScoreStats(pn, songstats)
|
|
else
|
|
- table.insert(wfus[pn], cind-1)
|
|
+ table.insert(wfus[pn], cind - 1)
|
|
end
|
|
end
|
|
|
|
@@ -1663,7 +1674,7 @@ WF.UpdateProfilesOnEvaluation = function(hashes)
|
|
if not iscourse then
|
|
WF.WriteDetailedHighScoreStats(pn, nil, "_ITG")
|
|
else
|
|
- table.insert(itgus[pn], cind-1)
|
|
+ table.insert(itgus[pn], cind - 1)
|
|
end
|
|
end
|
|
|
|
@@ -1710,18 +1721,18 @@ WF.UpdateProfilesOnEvaluation = function(hashes)
|
|
local curitgclr = itgclr
|
|
local curfaplus = WF.FAPlusCount[pn]
|
|
if cind > 1 then
|
|
- local jt = {curstatsobj:GetJudgmentCount("W1"),curstatsobj:GetJudgmentCount("W2"),
|
|
- curstatsobj:GetJudgmentCount("W3"),curstatsobj:GetJudgmentCount("W4"),
|
|
- curstatsobj:GetJudgmentCount("W5"),curstatsobj:GetJudgmentCount("Miss"),
|
|
- curstatsobj:GetJudgmentCount("Held"),curstatsobj:GetJudgmentCount("LetGo"),
|
|
- curstatsobj:GetJudgmentCount("HitMine")}
|
|
+ local jt = { curstatsobj:GetJudgmentCount("W1"), curstatsobj:GetJudgmentCount("W2"),
|
|
+ curstatsobj:GetJudgmentCount("W3"), curstatsobj:GetJudgmentCount("W4"),
|
|
+ curstatsobj:GetJudgmentCount("W5"), curstatsobj:GetJudgmentCount("Miss"),
|
|
+ curstatsobj:GetJudgmentCount("Held"), curstatsobj:GetJudgmentCount("LetGo"),
|
|
+ curstatsobj:GetJudgmentCount("HitMine") }
|
|
curdp = math.floor(WF.CalculatePercentDP(jt, cursteps, player, false) * 10000)
|
|
- curitgdp = math.floor(WF.CalculatePercentDP(WF.ITGJudgmentCountsPerSongInCourse[pn][cind-1],
|
|
+ curitgdp = math.floor(WF.CalculatePercentDP(WF.ITGJudgmentCountsPerSongInCourse[pn][cind - 1],
|
|
cursteps, player, true) * 10000)
|
|
- curfaplus = WF.FAPlusCountPerSongInCourse[pn][cind-1]
|
|
+ curfaplus = WF.FAPlusCountPerSongInCourse[pn][cind - 1]
|
|
if WF.ITGFailed[pn] then
|
|
- if cind-1 < WF.ITGSongInCourseAtFail[pn] then curitgclr = "C"
|
|
- elseif cind-1 == WF.ITGSongInCourseAtFail[pn] then curitgclr = "F"
|
|
+ if cind - 1 < WF.ITGSongInCourseAtFail[pn] then curitgclr = "C"
|
|
+ elseif cind - 1 == WF.ITGSongInCourseAtFail[pn] then curitgclr = "F"
|
|
else curitgclr = nil end
|
|
end
|
|
end
|
|
@@ -1748,7 +1759,7 @@ WF.UpdateProfilesOnEvaluation = function(hashes)
|
|
-- so this essentially checks if the same chart was played and play count has already incremented
|
|
curmstats.PlayCount = curmstats.PlayCount + 1
|
|
end
|
|
-
|
|
+
|
|
|
|
-- insert into high score list
|
|
local profile = PROFILEMAN:GetProfile(player)
|
|
@@ -1760,7 +1771,7 @@ WF.UpdateProfilesOnEvaluation = function(hashes)
|
|
curmr.PlayerGuid = (not isguest) and profile:GetGUID() or "None"
|
|
curmr.DateObtained = dateobtained
|
|
curmr.PercentDP = dplist[pn][cind]
|
|
- curmstats.HighScoreList[#curmstats.HighScoreList+1] = curmr
|
|
+ curmstats.HighScoreList[#curmstats.HighScoreList + 1] = curmr
|
|
table.insert(mr[pn], curmr)
|
|
|
|
-- insert into itg high score list
|
|
@@ -1771,7 +1782,7 @@ WF.UpdateProfilesOnEvaluation = function(hashes)
|
|
curitgmr.PlayerGuid = (not isguest) and profile:GetGUID() or ""
|
|
curitgmr.DateObtained = dateobtained
|
|
curitgmr.PercentDP = dplist_itg[pn][cind]
|
|
- curmstats.HighScoreList_ITG[#curmstats.HighScoreList_ITG+1] = curitgmr
|
|
+ curmstats.HighScoreList_ITG[#curmstats.HighScoreList_ITG + 1] = curitgmr
|
|
table.insert(itgmr[pn], curitgmr)
|
|
|
|
if not iscourse then
|
|
@@ -1803,7 +1814,7 @@ WF.UpdateProfilesOnEvaluation = function(hashes)
|
|
for k, v in pairs(score) do if mr[pn][cind][k] ~= v then found = false end end
|
|
if found then
|
|
if cind == 1 then rt[pn].MachineHSInd = i
|
|
- else rt[pn].MachineCourseSongHSInd[cind-1] = i end
|
|
+ else rt[pn].MachineCourseSongHSInd[cind - 1] = i end
|
|
break
|
|
end
|
|
end
|
|
@@ -1812,13 +1823,13 @@ WF.UpdateProfilesOnEvaluation = function(hashes)
|
|
for k, v in pairs(score) do if itgmr[pn][cind][k] ~= v then found = false end end
|
|
if found then
|
|
if cind == 1 then rt[pn].MachineHSInd_ITG = i
|
|
- else rt[pn].MachineCourseSongHSInd_ITG[cind-1] = i end
|
|
+ else rt[pn].MachineCourseSongHSInd_ITG[cind - 1] = i end
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|
|
-
|
|
+
|
|
return rt
|
|
end
|
|
|
|
@@ -1831,7 +1842,7 @@ WF.CopySongStats = function(hs)
|
|
t[k] = v
|
|
elseif k == "BestFAPlusCounts" then
|
|
t[k] = {}
|
|
- for i = 1,3 do t[k][i] = v[i] end
|
|
+ for i = 1, 3 do t[k][i] = v[i] end
|
|
end
|
|
end
|
|
return t
|
|
@@ -1844,15 +1855,15 @@ WF.ImportCheck = function()
|
|
-- with the new system the UI probably doesn't need to report anything super specific
|
|
if ThemePrefs.Get("AlwaysMergeScores") then return true end
|
|
local mdir = PROFILEMAN:GetProfileDir("ProfileSlot_Machine")
|
|
- if not FILEMAN:DoesFileExist(mdir.."/MachineStats.wfm") then return true end
|
|
+ if not FILEMAN:DoesFileExist(mdir .. "/MachineStats.wfm") then return true end
|
|
if WF.MachineProfileStats and WF.MachineProfileStats.ForceImportCourses then
|
|
return true
|
|
end
|
|
local players = GAMESTATE:GetHumanPlayers()
|
|
for player in ivalues(players) do
|
|
local pn = player:sub(-1)
|
|
- local dir = PROFILEMAN:GetProfileDir("ProfileSlot_Player"..pn)
|
|
- if (dir ~= "") and (not FILEMAN:DoesFileExist(dir.."/PlayerStats.wfs")) then
|
|
+ local dir = PROFILEMAN:GetProfileDir("ProfileSlot_Player" .. pn)
|
|
+ if (dir ~= "") and (not FILEMAN:DoesFileExist(dir .. "/PlayerStats.wfs")) then
|
|
return true
|
|
end
|
|
if WF.PlayerProfileStats[pn] and WF.PlayerProfileStats[pn].ForceImportCourses then
|
|
@@ -1870,31 +1881,31 @@ WF.MergeProfileStats = function()
|
|
|
|
-- There is also now a ThemePref that will force this merge always; this is more affordable to do now
|
|
-- with the addition of a maintained hash cache #HashCash
|
|
-
|
|
+
|
|
-- check which we should import first, so that we can minimize the amount of SetStatsPrefix jawns
|
|
local mdir = PROFILEMAN:GetProfileDir("ProfileSlot_Machine")
|
|
local alwaysmerge = ThemePrefs.Get("AlwaysMergeScores")
|
|
- local importmachine = alwaysmerge or (not FILEMAN:DoesFileExist(mdir.."/MachineStats.wfm"))
|
|
+ local importmachine = alwaysmerge or (not FILEMAN:DoesFileExist(mdir .. "/MachineStats.wfm"))
|
|
if (not importmachine) and WF.MachineProfileStats and WF.MachineProfileStats.ForceImportCourses then
|
|
importmachine = true
|
|
end
|
|
local importsongsmachine = importmachine
|
|
if (importmachine) and (WF.MachineProfileStats.ForceImportCourses) and (not alwaysmerge)
|
|
- and FILEMAN:DoesFileExist(mdir.."/MachineStats.wfm") then
|
|
+ and FILEMAN:DoesFileExist(mdir .. "/MachineStats.wfm") then
|
|
importsongsmachine = false
|
|
end
|
|
|
|
local players = GAMESTATE:GetHumanPlayers()
|
|
local importplayers = {}
|
|
- local importsongsplayer = {true,true}
|
|
+ local importsongsplayer = { true, true }
|
|
for player in ivalues(players) do
|
|
local pn = tonumber(player:sub(-1))
|
|
- local dir = PROFILEMAN:GetProfileDir("ProfileSlot_Player"..pn)
|
|
- if alwaysmerge or ((dir ~= "") and (not FILEMAN:DoesFileExist(dir.."/PlayerStats.wfs")))
|
|
- or (WF.PlayerProfileStats[pn] and WF.PlayerProfileStats[pn].ForceImportCourses) then
|
|
+ local dir = PROFILEMAN:GetProfileDir("ProfileSlot_Player" .. pn)
|
|
+ if alwaysmerge or ((dir ~= "") and (not FILEMAN:DoesFileExist(dir .. "/PlayerStats.wfs")))
|
|
+ or (WF.PlayerProfileStats[pn] and WF.PlayerProfileStats[pn].ForceImportCourses) then
|
|
table.insert(importplayers, player)
|
|
- if (not alwaysmerge) and FILEMAN:DoesFileExist(dir.."/PlayerStats.wfs")
|
|
- and WF.PlayerProfileStats[pn].ForceImportCourses then
|
|
+ if (not alwaysmerge) and FILEMAN:DoesFileExist(dir .. "/PlayerStats.wfs")
|
|
+ and WF.PlayerProfileStats[pn].ForceImportCourses then
|
|
importsongsplayer[pn] = false
|
|
end
|
|
end
|
|
@@ -1939,15 +1950,15 @@ WF.ImportProfileStats = function(importsongs, importcourses, pn)
|
|
-- pn nil for machine
|
|
local stats = (not pn) and WF.MachineProfileStats or WF.PlayerProfileStats[pn]
|
|
if not stats then return end
|
|
- local profile = (not pn) and PROFILEMAN:GetMachineProfile() or PROFILEMAN:GetProfile("PlayerNumber_P"..pn)
|
|
+ local profile = (not pn) and PROFILEMAN:GetMachineProfile() or PROFILEMAN:GetProfile("PlayerNumber_P" .. pn)
|
|
if not profile then return end
|
|
|
|
local curprefix = PROFILEMAN:GetStatsPrefix()
|
|
- local scoretype = {["Exp-"] = "standard", [""] = "ITG", ["ECFA-"] = "ITG (FA+)"}
|
|
+ local scoretype = { ["Exp-"] = "standard", [""] = "ITG", ["ECFA-"] = "ITG (FA+)" }
|
|
|
|
-- status message traced to log
|
|
local name = (not pn) and "Machine" or profile:GetDisplayName()
|
|
- local statusbase = "Importing scores for profile: "..name
|
|
+ local statusbase = "Importing scores for profile: " .. name
|
|
local status = statusbase
|
|
Trace(status)
|
|
|
|
@@ -1977,10 +1988,10 @@ WF.ImportProfileStats = function(importsongs, importcourses, pn)
|
|
if hsl then
|
|
local scores = hsl:GetHighScores()
|
|
local stepsid = WF.GetItemID(song, steps)
|
|
- status = statusbase.."\nScores found for chart/course: "..stepsid
|
|
+ status = statusbase .. "\nScores found for chart/course: " .. stepsid
|
|
Trace(status)
|
|
local bestplayset = {} -- used below
|
|
-
|
|
+
|
|
for scoreind, score in ipairs(scores) do
|
|
-- first check if song stats already exists, and create it if not.
|
|
-- need to get the songstats each iteration, because rate might be different (ugh)
|
|
@@ -2006,7 +2017,7 @@ WF.ImportProfileStats = function(importsongs, importcourses, pn)
|
|
hs.PlayerGuid = "Unknown"
|
|
hs.DateObtained = tostring(score:GetDate())
|
|
hs.PercentDP = dp
|
|
- list[#list+1] = hs
|
|
+ list[#list + 1] = hs
|
|
end
|
|
else
|
|
-- for player, we need to get all the personal best stuff we can detect.
|
|
@@ -2030,7 +2041,7 @@ WF.ImportProfileStats = function(importsongs, importcourses, pn)
|
|
songstats.BestFAPlusCounts[3] = math.max(songstats.BestFAPlusCounts[3], faplus)
|
|
if newscore then
|
|
stats.TotalTapJudgments[1] = stats.TotalTapJudgments[1] + faplus
|
|
- -- we can detect a "mastery" if score is 100% and there are no W2 judgments
|
|
+ -- we can detect a "mastery" if score is 100% and there are no W2 judgments
|
|
if score:GetPercentDP() == 1 and score:GetTapNoteScore("TapNoteScore_W2") == 0 then
|
|
songstats.BestClearType = 1
|
|
songstats.BestPercentDP = 10000
|
|
@@ -2067,9 +2078,10 @@ WF.ImportProfileStats = function(importsongs, importcourses, pn)
|
|
if newscore then
|
|
for i = 1, 5 do
|
|
stats.TotalTapJudgments[i] = stats.TotalTapJudgments[i]
|
|
- + statsobj:GetJudgmentCount("W"..i)
|
|
+ + statsobj:GetJudgmentCount("W" .. i)
|
|
end
|
|
- stats.TotalTapJudgments[6] = stats.TotalTapJudgments[6] + statsobj:GetJudgmentCount("Miss")
|
|
+ stats.TotalTapJudgments[6] = stats.TotalTapJudgments[6] +
|
|
+ statsobj:GetJudgmentCount("Miss")
|
|
|
|
-- there is no way to reliably differentiate holds from rolls in terms of performance vs
|
|
-- total, so we'll just ignore those. but we can at least tally mines.
|
|
@@ -2085,7 +2097,7 @@ WF.ImportProfileStats = function(importsongs, importcourses, pn)
|
|
if not bestplayset[rate] then
|
|
local bp = songstats.BestPlay
|
|
bp.DateObtained = tostring(score:GetDate())
|
|
- for i = 1,5 do bp.Judgments[i] = statsobj:GetJudgmentCount("W"..i) end
|
|
+ for i = 1, 5 do bp.Judgments[i] = statsobj:GetJudgmentCount("W" .. i) end
|
|
bp.Judgments[6] = statsobj:GetJudgmentCount("Miss")
|
|
-- just combine holds held and rolls held into holds held
|
|
bp.Judgments[7] = statsobj:GetJudgmentCount("Held")
|
|
@@ -2096,7 +2108,7 @@ WF.ImportProfileStats = function(importsongs, importcourses, pn)
|
|
bp.LifeBarVals[3] = 0
|
|
bp.LifeBarVals[1] = (not failed) and 1000 or 0
|
|
bp.LifeBarVals[2] = (not failed) and 800 or 0
|
|
- for i = 1,3 do bp.ScoreAtLifeEmpty[i] = dp end
|
|
+ for i = 1, 3 do bp.ScoreAtLifeEmpty[i] = dp end
|
|
-- won't bother with significant mods for this
|
|
bestplayset[rate] = true
|
|
end
|
|
@@ -2107,7 +2119,7 @@ WF.ImportProfileStats = function(importsongs, importcourses, pn)
|
|
end
|
|
end
|
|
|
|
- status = statusbase.."\nDone"
|
|
+ status = statusbase .. "\nDone"
|
|
Trace(status)
|
|
|
|
-- save stats before next load (upon changing the prefix)
|
|
@@ -2119,66 +2131,68 @@ end
|
|
WF.ProfileCardLowerAF = function(pn, items)
|
|
-- items can be passed in, otherwise will come from ThemePrefs for the profile.
|
|
-- options are "SongsPlayed", "FCTiers", "FCTiersNoPerfect", "LifeBarClears", "TopGradesITG"
|
|
- if not items then items = SL["P"..pn].ActiveModifiers.ProfileCardInfo end
|
|
+ if not items then items = SL["P" .. pn].ActiveModifiers.ProfileCardInfo end
|
|
if not items then items = "SongsPlayed" end
|
|
|
|
- local af = Def.ActorFrame{}
|
|
+ local af = Def.ActorFrame {}
|
|
local iscourse = GAMESTATE:IsCourseMode()
|
|
|
|
if items == "SongsPlayed" then
|
|
- af[#af+1] = LoadFont("Common Normal")..{
|
|
+ af[#af + 1] = LoadFont("Common Normal") .. {
|
|
Text = "Current Session:",
|
|
InitCommand = function(self) self:y(4):zoom(0.8) end
|
|
}
|
|
- af[#af+1] = LoadFont("Common Normal")..{
|
|
+ af[#af + 1] = LoadFont("Common Normal") .. {
|
|
Text = string.format("%d %s%s", WF.CurrentSessionSongsPlayed[pn], (not iscourse) and "song" or "course",
|
|
(WF.CurrentSessionSongsPlayed[pn] > 1) and "s" or ""),
|
|
InitCommand = function(self) self:zoom(0.8):y(20) end
|
|
}
|
|
elseif items == "FCTiers" or items == "FCTiersNoPerfect" or items == "LifeBarClears" then
|
|
- local cto = {FCTiers = 0, FCTiersNoPerfect = 1, LifeBarClears = 4}
|
|
+ local cto = { FCTiers = 0, FCTiersNoPerfect = 1, LifeBarClears = 4 }
|
|
local p = (not iscourse) and "" or "Course"
|
|
for i = 1, 3 do
|
|
local cti = i + cto[items]
|
|
- af[#af+1] = LoadFont("Common Normal")..{
|
|
+ af[#af + 1] = LoadFont("Common Normal") .. {
|
|
Text = WF.ClearTypesShort[cti],
|
|
- InitCommand = function(self) self:zoom(0.8):diffuse(WF.ClearTypeColor(cti)):xy(-20, 14*(i-1)) end
|
|
+ InitCommand = function(self) self:zoom(0.8):diffuse(WF.ClearTypeColor(cti)):xy(-20, 14 * (i - 1)) end
|
|
}
|
|
- af[#af+1] = LoadFont("Common Normal")..{
|
|
- Text = tostring(WF.PlayerProfileStats[pn][p.."ClearTypeCounts"][cti]),
|
|
- InitCommand = function(self) self:zoom(0.8):xy(36, 14*(i-1)):horizalign("right"):maxwidth(36/0.8) end
|
|
+ af[#af + 1] = LoadFont("Common Normal") .. {
|
|
+ Text = tostring(WF.PlayerProfileStats[pn][p .. "ClearTypeCounts"][cti]),
|
|
+ InitCommand = function(self) self:zoom(0.8):xy(36, 14 * (i - 1)):horizalign("right"):maxwidth(36 / 0.8) end
|
|
}
|
|
end
|
|
elseif items == "TopGradesITG" then
|
|
- local positions = {{-34, 2}, {12, 2}, {-34, 24}, {12, 24}}
|
|
+ local positions = { { -34, 2 }, { 12, 2 }, { -34, 24 }, { 12, 24 } }
|
|
local p = (not iscourse) and "" or "Course"
|
|
for i = 1, 4 do
|
|
- af[#af+1] = LoadActor(THEME:GetPathG("", "_GradesSmall/LetterGrade.lua"), {grade = i, itg = true})..{
|
|
- OnCommand = function(self) self:zoom(0.2):xy(positions[i][1], positions[i][2]) end
|
|
- }
|
|
- af[#af+1] = LoadFont("Common Normal")..{
|
|
- Text = tostring(WF.PlayerProfileStats[pn][p.."GradeCounts_ITG"][i]),
|
|
- InitCommand = function(self) self:zoom(0.75):xy(positions[i][1] + 32, positions[i][2]+1)
|
|
- :maxwidth(20/0.75):horizalign("right") end
|
|
+ af[#af + 1] = LoadActor(THEME:GetPathG("", "_GradesSmall/LetterGrade.lua"), { grade = i, itg = true }) ..
|
|
+ {
|
|
+ OnCommand = function(self) self:zoom(0.2):xy(positions[i][1], positions[i][2]) end
|
|
+ }
|
|
+ af[#af + 1] = LoadFont("Common Normal") .. {
|
|
+ Text = tostring(WF.PlayerProfileStats[pn][p .. "GradeCounts_ITG"][i]),
|
|
+ InitCommand = function(self) self:zoom(0.75):xy(positions[i][1] + 32, positions[i][2] + 1)
|
|
+ :maxwidth(20 / 0.75):horizalign("right")
|
|
+ end
|
|
}
|
|
end
|
|
elseif items == "ECFA2021" then
|
|
-- unused now
|
|
local points = tostring(math.floor(WF.PlayerProfileStats[pn].ECFA2021ScoreList.TotalPoints))
|
|
local songs = tostring(WF.PlayerProfileStats[pn].ECFA2021ScoreList.Songs)
|
|
- af[#af+1] = LoadFont("Common Normal")..{
|
|
+ af[#af + 1] = LoadFont("Common Normal") .. {
|
|
Text = "ECFA Total",
|
|
InitCommand = function(self) self:zoom(0.8) end
|
|
}
|
|
- af[#af+1] = LoadFont("Common Normal")..{
|
|
+ af[#af + 1] = LoadFont("Common Normal") .. {
|
|
Text = points,
|
|
- InitCommand = function(self) self:zoom(0.8):y(14):maxwidth(92/0.8) end
|
|
+ InitCommand = function(self) self:zoom(0.8):y(14):maxwidth(92 / 0.8) end
|
|
}
|
|
- af[#af+1] = LoadFont("Common Normal")..{
|
|
+ af[#af + 1] = LoadFont("Common Normal") .. {
|
|
Text = "Songs Played:",
|
|
InitCommand = function(self) self:zoom(0.7):xy(-44, 29):horizalign("left") end
|
|
}
|
|
- af[#af+1] = LoadFont("Common Normal")..{
|
|
+ af[#af + 1] = LoadFont("Common Normal") .. {
|
|
Text = songs,
|
|
InitCommand = function(self) self:zoom(0.7):xy(44, 29):horizalign("right") end
|
|
}
|
|
@@ -2197,26 +2211,25 @@ function TestHashes()
|
|
for id, v in pairs(HashTest) do
|
|
if id ~= "WFVersion" then
|
|
if WF.HashCache[id] == v then
|
|
- Trace("Hashes match for ID: "..id)
|
|
+ Trace("Hashes match for ID: " .. id)
|
|
Trace(v or "[NO HASH]")
|
|
Trace(WF.HashCache[id] or "[NO HASH]")
|
|
else
|
|
if WF.HashCache[id] then
|
|
wrong = wrong + 1
|
|
- Trace("Hashes do not match for ID: "..id)
|
|
+ Trace("Hashes do not match for ID: " .. id)
|
|
Trace(v or "[NO HASH]")
|
|
Trace(WF.HashCache[id] or "[NO HASH]")
|
|
else
|
|
nochart = nochart + 1
|
|
- Trace("No chart or hash for ID: "..id)
|
|
+ Trace("No chart or hash for ID: " .. id)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
- Trace("Hash test complete. "..wrong.." incorrect hashes, "..nochart.." empty hashes.")
|
|
+ Trace("Hash test complete. " .. wrong .. " incorrect hashes, " .. nochart .. " empty hashes.")
|
|
end
|
|
|
|
-
|
|
-- The following is a really dumb hacky idea, entirely to try to maintain "Last song played."
|
|
-- Firstly, we'll have a flag that signals to the theme to not do any of the WF file operations for profiles
|
|
-- if it's set while the Load/SaveProfileCustom functions run, because there is no need.
|
|
@@ -2263,7 +2276,7 @@ WF.InitHashCache = function()
|
|
if (fn) and fn ~= "" and (steps:GetStepsType():find("Dance") or steps:GetStepsType():find("Pump")) then
|
|
local id = WF.GetStepsID(song, steps)
|
|
if not WF.HashCache[id] then
|
|
- table.insert(WF.NewChartsToCache, {song, steps})
|
|
+ table.insert(WF.NewChartsToCache, { song, steps })
|
|
end
|
|
end
|
|
end
|
|
@@ -2334,6 +2347,8 @@ WF.SaveHashCache = function()
|
|
end
|
|
end
|
|
|
|
+ File.Write("/Save/Waterfall/zkldi.json", json.encode(WF.ZkldiDump))
|
|
+
|
|
local fstr = table.concat(ft, "\n")
|
|
if File.Write(path, fstr) then
|
|
Trace("Hash Cache successfully written. #HashCash")
|
|
@@ -2347,8 +2362,8 @@ WF.GetHashCacheBuildStatus = function(total)
|
|
-- if no total is passed in, the number of items in the NewChartsToCache table will be used, and then that
|
|
-- total can be passed back in
|
|
if not total then total = #WF.NewChartsToCache end
|
|
-
|
|
- local rt = {Step = "Generating hash", ChartID = "", Finished = total - #WF.NewChartsToCache, Total = total}
|
|
+
|
|
+ local rt = { Step = "Generating hash", ChartID = "", Finished = total - #WF.NewChartsToCache, Total = total }
|
|
if #WF.NewChartsToCache == 0 then
|
|
rt.Step = "Done"
|
|
WF.HashCacheBuildFinish()
|
|
@@ -2381,6 +2396,40 @@ WF.ProcessHashCacheItem = function()
|
|
hash = GetHashFromSimfileString(item[2], WF.LastMSD.MSD, WF.LastMSD.Type) or ""
|
|
end
|
|
|
|
+
|
|
+ local song = item[1]
|
|
+ local steps = item[2]
|
|
+
|
|
+ ParseChartInfo(steps, "P1")
|
|
+
|
|
+ WF.ZkldiDump[id] = {
|
|
+ title = song:GetMainTitle(),
|
|
+ artist = song:GetDisplayArtist(),
|
|
+ subtitle = song:GetDisplaySubTitle(),
|
|
+
|
|
+ chartHash = hash,
|
|
+ level = steps:GetMeter(),
|
|
+ difficulty = steps:GetDifficulty(),
|
|
+ breakdown = {
|
|
+ detailed = GenerateBreakdownText("P1", 0),
|
|
+ partiallySimplified = GenerateBreakdownText("P1", 1),
|
|
+ simplified = GenerateBreakdownText("P1", 2),
|
|
+ total = GenerateBreakdownText("P1", 3),
|
|
+ npsPerMeasure = SL.P1.Streams.NPSperMeasure,
|
|
+ notesPerMeasure = SL.P1.Streams.NotesPerMeasure,
|
|
+ },
|
|
+ tech = {
|
|
+ footswitches = SL.P1.Streams.Footswitches,
|
|
+ jacks = SL.P1.Streams.Jacks,
|
|
+ sideswitches = SL.P1.Streams.Sideswitches,
|
|
+ brackets = SL.P1.Streams.Brackets,
|
|
+ crossovers = SL.P1.Streams.Crossovers,
|
|
+ },
|
|
+ length = song:GetLastSecond(),
|
|
+ charter = steps:GetAuthorCredit(),
|
|
+ displayBPM = steps:GetDisplayBpms()
|
|
+ }
|
|
+
|
|
WF.HashCache[id] = hash
|
|
table.remove(WF.NewChartsToCache, 1)
|
|
end
|
|
@@ -2430,9 +2479,9 @@ WF.CalculateClearsAndGrades = function(stepstype, groupname, difficulty, rate, p
|
|
|
|
-- i could do all the dumb logic i did for edits in the song item file, but the idea of tracking a
|
|
-- "lamp" for a specific index of edit difficulty within a pack seems dumb and pointless to me
|
|
- if difficulty == "Difficulty_Edit" then return {WF = 0, ITG = 0} end
|
|
+ if difficulty == "Difficulty_Edit" then return { WF = 0, ITG = 0 } end
|
|
|
|
- local arg = {WF = 0, ITG = 0}
|
|
+ local arg = { WF = 0, ITG = 0 }
|
|
for song in ivalues(songs) do
|
|
local charts = song:GetStepsByStepsType(stepstype)
|
|
if charts then
|
|
@@ -2464,7 +2513,7 @@ WF.CalculateClearsAndGrades = function(stepstype, groupname, difficulty, rate, p
|
|
-- if we get here, every chart had a score of some kind. arg.WF = None CT means * for WF
|
|
-- ITG will already have 99 assigned from CalculateGradeITG if any chart was unplayed
|
|
if arg.WF == WF.ClearTypes.None then arg.WF = 99 end
|
|
-
|
|
+
|
|
WF.AddToClearsAndGrades(stepstype, groupname, difficulty, rate, pn, arg.WF, arg.ITG)
|
|
return arg
|
|
end
|
|
@@ -2480,14 +2529,14 @@ WF.PreloadClearsAndGrades = function(pn)
|
|
-- first, get all the rates we need to do this for (i feel like there should be a shortcut here but it's
|
|
-- like 4am and i'm kinda dumb)
|
|
local scores = WF.PlayerProfileStats[pn].SongStats
|
|
- local rates = {"1.0"}
|
|
+ local rates = { "1.0" }
|
|
for score in ivalues(scores) do
|
|
if (not FindInTable(score.RateMod, rates)) then table.insert(rates, score.RateMod) end
|
|
end
|
|
|
|
- local diffs =
|
|
- {"Difficulty_Beginner","Difficulty_Easy","Difficulty_Medium","Difficulty_Hard","Difficulty_Challenge"}
|
|
- local types = {"Dance_Single","Dance_Double","Pump_Single","Pump_Double"}
|
|
+ local diffs =
|
|
+ { "Difficulty_Beginner", "Difficulty_Easy", "Difficulty_Medium", "Difficulty_Hard", "Difficulty_Challenge" }
|
|
+ local types = { "Dance_Single", "Dance_Double", "Pump_Single", "Pump_Double" }
|
|
local groups = SONGMAN:GetSongGroupNames()
|
|
for rate in ivalues(rates) do
|
|
for stype in ivalues(types) do
|
|
@@ -2535,7 +2584,7 @@ WF.PullITGScoreFromGrooveStats = function(pn, hash, gsentry, steps)
|
|
if not stats then
|
|
-- no stats for 1.0; make a new one
|
|
if not steps then
|
|
- steps = GAMESTATE:GetCurrentSteps("PlayerNumber_P"..pn)
|
|
+ steps = GAMESTATE:GetCurrentSteps("PlayerNumber_P" .. pn)
|
|
end
|
|
-- don't proceed if certain things don't look right
|
|
if not steps then return end
|
|
@@ -2575,13 +2624,13 @@ end
|
|
-- (the following 2 functions were moved from WF-Scoring.lua)
|
|
WF.GetStepsID = function(song, steps)
|
|
-- this is the index for any item in the SongStats table, pertaining to any steps
|
|
- local stypeid = steps:GetStepsType():gsub("StepsType_","")
|
|
- local songid = song:GetSongDir():gsub("/AdditionalSongs/","",1):gsub("/Songs/","",1):sub(1,-2)
|
|
- local diffid = steps:GetDifficulty():gsub("Difficulty_","")
|
|
+ local stypeid = steps:GetStepsType():gsub("StepsType_", "")
|
|
+ local songid = song:GetSongDir():gsub("/AdditionalSongs/", "", 1):gsub("/Songs/", "", 1):sub(1, -2)
|
|
+ local diffid = steps:GetDifficulty():gsub("Difficulty_", "")
|
|
local ext = diffid == "Edit" and WF.GetEditIndex(song, steps) or ""
|
|
- diffid = diffid:sub(1,1)
|
|
+ diffid = diffid:sub(1, 1)
|
|
--return stypeid.."/"..songid.."/"..diffid..ext
|
|
- return table.concat({stypeid,songid,diffid..ext}, "/")
|
|
+ return table.concat({ stypeid, songid, diffid .. ext }, "/")
|
|
end
|
|
|
|
WF.GetEditIndex = function(song, steps)
|
|
@@ -2605,7 +2654,7 @@ WF.GetCourseID = function(course, trail)
|
|
if course:IsAutogen() then courseid = course:GetDisplayFullTitle() end
|
|
local diffid = ToEnumShortString(trail:GetDifficulty())
|
|
diffid = diffid:sub(1, 1)
|
|
- return table.concat({stypeid, "CRS", courseid, diffid}, "/")
|
|
+ return table.concat({ stypeid, "CRS", courseid, diffid }, "/")
|
|
end
|
|
|
|
WF.GetItemID = function(songcrs, stepstrl)
|
|
@@ -2618,7 +2667,7 @@ function LookupIdentifier(hashorid, rate)
|
|
-- OLD FUNCTION, lookup table no longer works this way, but this id is still used for detailed filenames
|
|
if IsNormalRate(rate) then return hashorid end
|
|
|
|
- return hashorid.."_"..(NormalizeRateString(rate):gsub("%.", "_"))
|
|
+ return hashorid .. "_" .. (NormalizeRateString(rate):gsub("%.", "_"))
|
|
end
|
|
|
|
function CheckLookupEntry(t, hashorid, rate)
|
|
@@ -2704,12 +2753,13 @@ function GetSignificantMods(player, steps)
|
|
-- render it insignificant. this is pretty harmless as all it will do is show the icon at eval, but
|
|
-- later on i could write a function to evaluate this (not the most complicated thing really)
|
|
local td = (not iscourse) and steps:GetTimingData()
|
|
- if (options:CMod()) and (iscourse or (not steps:IsDisplayBpmConstant()) or td:HasStops() or td:HasScrollChanges()
|
|
- or td:HasSpeedChanges() or td:HasNegativeBPMs() or td:HasWarps()) then
|
|
+ if (options:CMod()) and (
|
|
+ iscourse or (not steps:IsDisplayBpmConstant()) or td:HasStops() or td:HasScrollChanges()
|
|
+ or td:HasSpeedChanges() or td:HasNegativeBPMs() or td:HasWarps()) then
|
|
table.insert(t, "C")
|
|
end
|
|
|
|
- local turns = {"Left","Right","Mirror","Shuffle","SoftShuffle","SuperShuffle","NoMines"}
|
|
+ local turns = { "Left", "Right", "Mirror", "Shuffle", "SoftShuffle", "SuperShuffle", "NoMines" }
|
|
for turn in ivalues(turns) do
|
|
if options[turn](options) then
|
|
table.insert(t, turn)
|
|
@@ -2721,10 +2771,10 @@ function GetSignificantMods(player, steps)
|
|
end
|
|
|
|
if slmods.FAPlus ~= 0 then
|
|
- table.insert(t, string.format("FA%d", slmods.FAPlus*10000))
|
|
+ table.insert(t, string.format("FA%d", slmods.FAPlus * 10000))
|
|
end
|
|
|
|
- local what = {{"Disabled","NoBoys"},{"Extended","BigBoys"}}
|
|
+ local what = { { "Disabled", "NoBoys" }, { "Extended", "BigBoys" } }
|
|
for boy in ivalues(what) do
|
|
if math.abs(PREFSMAN:GetPreference("TimingWindowSecondsW5") - WF.GetErrorWindowVal(boy[1])) < 0.00001 then
|
|
table.insert(t, boy[2])
|
|
@@ -2739,15 +2789,18 @@ end
|
|
function IsNormalRate(rate)
|
|
return (rate == "1.0" or NormalizeRateString(rate) == "1.0")
|
|
end
|
|
+
|
|
function RateFromNumber(num)
|
|
if math.abs(1 - num) < 0.0001 then return "1.0" end
|
|
local s = tostring(num)
|
|
- if s:len() == 1 then s = s..".0" end
|
|
+ if s:len() == 1 then s = s .. ".0" end
|
|
return s
|
|
end
|
|
+
|
|
function NormalizeRateString(rate)
|
|
return RateFromNumber(tonumber(rate))
|
|
end
|
|
+
|
|
function RatesAreEqual(rate1, rate2)
|
|
return ((IsNormalRate(rate1) and IsNormalRate(rate2)) or NormalizeRateString(rate1) == NormalizeRateString(rate2))
|
|
end
|
|
@@ -2779,7 +2832,7 @@ WF.TimeString = function(hour, minute, second)
|
|
end
|
|
|
|
WF.DateTimeString = function(year, month, day, hour, minute, second)
|
|
- return WF.DateString(year, month, day).." "..WF.TimeString(hour, minute, second)
|
|
+ return WF.DateString(year, month, day) .. " " .. WF.TimeString(hour, minute, second)
|
|
end
|
|
|
|
WF.CompareDateTime = function(s1, s2)
|
|
@@ -2852,7 +2905,7 @@ mt_datetime = {
|
|
return false
|
|
end,
|
|
__eq = function(a, b)
|
|
- local chk = {"Year","Month","Day","Hour","Minute","Second"}
|
|
+ local chk = { "Year", "Month", "Day", "Hour", "Minute", "Second" }
|
|
for field in ivalues(chk) do
|
|
if a[field] ~= b[field] then return false end
|
|
end
|