From 543b6dfe94f57f193a5fb5144b00a413dd3515a3 Mon Sep 17 00:00:00 2001 From: Hersi Date: Sat, 20 Nov 2021 22:54:47 +0100 Subject: [PATCH] WIP: the biggest chalwheel commit you will see from me --- scripts/songselect/chalwheel.lua | 407 +++++++++++++++++++++---------- 1 file changed, 276 insertions(+), 131 deletions(-) diff --git a/scripts/songselect/chalwheel.lua b/scripts/songselect/chalwheel.lua index b76cdae..eaebfe0 100644 --- a/scripts/songselect/chalwheel.lua +++ b/scripts/songselect/chalwheel.lua @@ -14,7 +14,6 @@ local jacket = nil; local selectedIndex = 1 local selectedDiff = 1 local challengeCache = {} -local ioffset = 0 local doffset = 0 local soffset = 0 local diffColors = { { 0, 0, 255 }, { 0, 255, 0 }, { 255, 0, 0 }, { 255, 0, 255 } } @@ -26,6 +25,7 @@ local searchText = gfx.CreateLabel("", 5, 0) local searchIndex = 1 local backgroundImage = gfx.CreateSkinImage("challenge_select/bg.png", 0) +local challengeCardBG = gfx.CreateSkinImage("challenge_select/small_box.png", 0) local jacketFallback = gfx.CreateSkinImage("song_select/loading.png", 0) local showGuide = game.GetSkinSetting("show_guide") @@ -82,13 +82,20 @@ local badges = { gfx.CreateSkinImage("song_select/medal/puc.png", 1) } +local passStates = { + gfx.CreateSkinImage("challenge_select/pass_states/not_played.png", 0), + gfx.CreateSkinImage("challenge_select/pass_states/failed.png", 0), + gfx.CreateSkinImage("challenge_select/pass_states/cleared.png", 0), +} + +gfx.LoadSkinFont("divlit_custom.ttf") gfx.LoadSkinFont("dfmarugoth.ttf"); game.LoadSkinSample("menu_click") game.LoadSkinSample("click-02") game.LoadSkinSample("woosh") -local wheelSize = 6 +local wheelSize = 5 get_page_size = function() return math.floor(wheelSize / 2) @@ -96,11 +103,11 @@ end -- Responsive UI variables -- Aspect Ratios -local aspectFloat = 1.850 +local aspectFloat = 1.0 local aspectRatio = "widescreen" -local landscapeWidescreenRatio = 1.850 -local landscapeStandardRatio = 1.500 -local portraitWidescreenRatio = 0.5 +local landscapeWidescreenRatio = 16 / 9 +local landscapeStandardRatio = 4 / 3 +local portraitWidescreenRatio = 9 / 16 -- Responsive sizes local fifthX = 0 @@ -116,7 +123,7 @@ local halfY = 0 local fullY = 0 adjustScreen = function(x, y) - local a = x / y; + aspectFloat = x / y; fifthX = x / 5 fourthX = x / 4 thirdX = x / 3 @@ -130,54 +137,62 @@ adjustScreen = function(x, y) fullY = y end -check_or_create_cache = function(challenge, full) +check_or_create_cache = function(challenge) + local namesLabelSize = 20 + local percentLabelSize = 35 + if not challengeCache[challenge.id] then challengeCache[challenge.id] = {} end if not challengeCache[challenge.id]["title"] then - challengeCache[challenge.id]["title"] = gfx.CreateLabel(challenge.title, 30, 0) + challengeCache[challenge.id]["title"] = gfx.CreateLabel(challenge.title, namesLabelSize, 0) end - if not challengeCache[challenge.id]["chart_names"] then - local names = "Charts:" - for _, chart in ipairs(challenge.charts) do - names = names .. " [" .. chart.title .. "]" - end + if not challengeCache[challenge.id]["charts"] then if challenge.missing_chart then - names = names .. " *COULD NOT FIND ALL CHARTS!*" + local missing_text = "*COULD NOT FIND ALL CHARTS!*" + challengeCache[challenge.id]["charts"] = { + { + ["title"] = gfx.CreateLabel(missing_text, namesLabelSize, 0), + ["level"] = 0, + ["difficulty"] = 0 + }, + } end - challengeCache[challenge.id]["chart_names"] = gfx.CreateLabel(names, 20, 0) + + local charts = {} + for _, chart in ipairs(challenge.charts) do + table.insert(charts, { + ["title"] = gfx.CreateLabel(chart.title, namesLabelSize, 0), + ["level"] = chart.level, + ["difficulty"] = chart.difficulty + }) + end + challengeCache[challenge.id]["charts"] = charts end - if challenge.topBadge ~= 0 - and (not challengeCache[challenge.id]["percent"] or not challengeCache[challenge.id]["percent_value"] - or challengeCache[challenge.id]["percent_value"] ~= challenge.bestScore) then - challengeCache[challenge.id]["percent"] = gfx.CreateLabel( - string.format( - "%u%%", math.max(0, (challenge.bestScore - 8000000) // 10000) - ), 35, 0 - ) - challengeCache[challenge.id]["percent_value"] = challenge.bestScore + + if (not challengeCache[challenge.id]["percent"] + or not challengeCache[challenge.id]["total_score"] + or challengeCache[challenge.id]["total_score"] ~= challenge.bestScore) then + challengeCache[challenge.id]["percent"] = math.max(0, (challenge.bestScore - 8000000) // 10000) + challengeCache[challenge.id]["total_score"] = challenge.bestScore end - if full then - if not challengeCache[challenge.id]["jackets"] then - local jackets = {} - for i, chart in ipairs(challenge.charts) do - jackets[i] = gfx.LoadImageJob(chart.jacketPath, jacketFallback, 200, 200) - end - challengeCache[challenge.id]["jackets"] = jackets + + if not challengeCache[challenge.id]["pass_state"] then + local passState = math.min(challenge.topBadge, 2) + 1 --challenge.topBadge -> [1, 3] + challengeCache[challenge.id]["pass_state"] = passStates[passState] + end + + if not challengeCache[challenge.id]["jackets"] then + local jackets = {} + for i, chart in ipairs(challenge.charts) do + jackets[i] = gfx.LoadImageJob(chart.jacketPath, jacketFallback, 200, 200) end - if not challengeCache[challenge.id]["desc"] then - local desc = "\n" - for _, chart in ipairs(challenge.charts) do - desc = desc .. "" .. chart.title .. "\n\n" - end - if challenge.missing_chart then - desc = desc .. "*COULD NOT FIND ALL CHARTS!*\n\n" - end - desc = desc .. "" - challengeCache[challenge.id]["desc"] = gfx.CreateLabel(desc, 20, 0) + if #jackets == 0 then + jackets[1] = jacketFallback end + challengeCache[challenge.id]["jackets"] = jackets end end @@ -218,6 +233,7 @@ draw_challenge = function(challenge, x, y, w, h, selected) check_or_create_cache(challenge) + --[[ gfx.BeginPath() gfx.RoundedRectVarying(x,y, w, h,0,0,0,40) gfx.FillColor(30, 30, 30) @@ -241,73 +257,121 @@ draw_challenge = function(challenge, x, y, w, h, selected) --gfx.DrawLabel(challengeCache[challenge.id]["artist"], x+20, y + 50, w-10) gfx.ForceRender() + --]] -end - -draw_diff_icon = function(diff, x, y, w, h, selected, deltaTime) - local shrinkX = w / 4 - local shrinkY = h / 4 - if selected then - gfx.FontSize(h / 2) - shrinkX = w / 6 - shrinkY = h / 6 - else - gfx.FontSize(math.floor(h / 3)) - end + --[[ + gfx.Save() gfx.BeginPath() - gfx.RoundedRectVarying(x + shrinkX, y + shrinkY, w - shrinkX * 2, h - shrinkY * 2, 0, 0, 0, 0) - gfx.FillColor(15, 15, 15) - gfx.StrokeColor(table.unpack(diffColors[diff.difficulty + 1])) - gfx.StrokeWidth(2) - gfx.Fill() + gfx.StrokeColor(255,0,0) + if selected then + gfx.StrokeColor(255,255,0) + end + gfx.Rect(x,y,w,h) gfx.Stroke() - gfx.FillColor(255, 255, 255) - gfx.TextAlign(gfx.TEXT_ALIGN_MIDDLE + gfx.TEXT_ALIGN_CENTER) - gfx.FastText(tostring(diff.level), x + (w / 2), y + (h / 2)) - -- gfx.BeginPath() - -- DiffRectangle.render(deltaTime, 183, 2.5, 10, songCache[song.id][selectedDiff],tostring(diff.level)); -end + gfx.Restore() + --]] -draw_diffs = function(diffs, x, y, w, h) - local diffWidth = w / 2.5 - local diffHeight = w / 2.5 - local diffCount = #diffs - gfx.Scissor(x, y, w, h) - for i = math.max(selectedDiff - 2, 1), math.max(selectedDiff - 1, 1) do - local diff = diffs[i] - local xpos = x + ((w / 2 - diffWidth / 2) + (selectedDiff - i + doffset) * (-0.8 * diffWidth)) - if i ~= selectedDiff then - draw_diff_icon(diff, xpos, y, diffWidth, diffHeight, false) + local testBox = function (xpos, ypos, width, height, value) + local textSize = 24 + gfx.BeginPath() + + if value then + gfx.FontSize(textSize) + gfx.TextAlign(gfx.TEXT_ALIGN_MIDDLE | gfx.TEXT_ALIGN_CENTER) + gfx.Text(tostring(value), xpos + width / 2, ypos + height / 2) end + + gfx.StrokeColor(0,255,255) + gfx.Rect(xpos, ypos, width, height) + gfx.Stroke() + + gfx.ForceRender() + end + + local _draw_card_bg = function () + gfx.BeginPath() + gfx.ImageRect(x, y, w, h, challengeCardBG, 1, 0) end - -- after selected - for i = math.min(selectedDiff + 2, diffCount), selectedDiff + 1, -1 do - local diff = diffs[i] - local xpos = x + ((w / 2 - diffWidth / 2) + (selectedDiff - i + doffset) * (-0.8 * diffWidth)) - if i ~= selectedDiff then - draw_diff_icon(diff, xpos, y, diffWidth, diffHeight, false) + local _draw_info = function () + local stateLabel = challengeCache[challenge.id]["pass_state"] + local stateLabelWidth, stateLabelHeight = gfx.ImageSize(stateLabel) + local stateLabelAspect = stateLabelWidth / stateLabelHeight + + local stateWidth = w / 5 + local stateHeight = stateWidth / stateLabelAspect + local stateOffsetX = x + w / 32 + local stateOffsetY = y + h / 16 + + local titleMargin = 6 + local titleMaxWidth = 3/5 * w + local titleCenterX = x + w - titleMargin - titleMaxWidth/2 --align right + local titleOffsetY = y + 1/11 * h --align baseline + + if not selected then + stateWidth = stateWidth * 0.9 + stateHeight = stateHeight * 0.9 + stateOffsetY = y + h / 32 + + titleMaxWidth = 6/9 * w + titleCenterX = x + w - titleMargin - titleMaxWidth/2 --align right + titleOffsetY = y + titleMargin/2 --align baseline end + + gfx.BeginPath() + gfx.ImageRect(stateOffsetX, stateOffsetY, stateWidth, stateHeight, stateLabel, 1, 0) + --testBox(stateOffsetX, stateOffsetY, stateWidth, stateHeight) + + gfx.FontFace("divlit_custom.ttf") + gfx.TextAlign(gfx.TEXT_ALIGN_CENTER | gfx.TEXT_ALIGN_BASELINE) + gfx.DrawLabel(challengeCache[challenge.id]["title"], titleCenterX, titleOffsetY, titleMaxWidth) + --testBox(titleOffsetX, titleOffsetY, math.min(titleLabelWidth, titleMaxWidth), titleLabelHeight) end - local diff = diffs[selectedDiff] - local xpos = x + ((w / 2 - diffWidth / 2) + (doffset) * (-0.8 * diffWidth)) - draw_diff_icon(diff, xpos, y, diffWidth, diffHeight, true) - gfx.BeginPath() - gfx.FillColor(0, 128, 255) - gfx.Rect(x, y + 10, 2, diffHeight - h / 6) - gfx.Fill() - gfx.BeginPath() - gfx.Rect(x + w - 2, y + 10, 2, diffHeight - h / 6) - gfx.Fill() - gfx.ResetScissor() - draw_cursor(x + w / 2, y + diffHeight / 2, timer * math.pi, diffHeight / 1.5) -end -draw_selected = function(challenge, x, y, w, h) - if not challenge then return end + local _draw_jacket = function () + local size = h * 0.68 + local offsetX = x + w / 32 + local offsetY = y + h - size - h * 0.05 - check_or_create_cache(challenge, true) + if not selected then + size = h * 0.66 + offsetX = x + w * 0.058 + offsetY = y + h - size - h * 0.066 + end + + gfx.BeginPath() + gfx.ImageRect(offsetX, offsetY, size, size, challengeCache[challenge.id]["jackets"][1], 1, 0) + end + local _draw_stats = function () + local percentOffsetX = x + 5/9 * w + local percentOffsetY = y + 5/6 * h + local scoreOffsetX = x + local scoreOffsetY = y + + gfx.BeginPath() + gfx.FontFace("divlit_custom.ttf") + gfx.FontSize(56) + gfx.TextAlign(gfx.TEXT_ALIGN_RIGHT) + gfx.Text(challengeCache[challenge.id]["percent"], percentOffsetX - 24, percentOffsetY) + gfx.FontSize(32) + gfx.Text("%", percentOffsetX, percentOffsetY) + end + + local _draw_chart = function () + + end + + if not selected then + _draw_card_bg() + end + + _draw_info() + _draw_jacket() + + _draw_stats() + + --[[ -- set up padding and margins local xPadding = math.floor(w / 16) local yPadding = math.floor(h / 32) @@ -329,6 +393,7 @@ draw_selected = function(challenge, x, y, w, h) -- jacket should take up 1/3 of height, always be square, and be centered local imageSize = math.floor((height / 2) * 2) - 10 local imageXPos = x + xMargin + xPadding + local imageYPos = y + yMargin + yPadding local square_size = math.ceil(math.sqrt(#challenge.charts)) local origImageSize = imageSize @@ -347,7 +412,7 @@ draw_selected = function(challenge, x, y, w, h) xoff = xoff end gfx.ImageRect( - 62.52, 888.6 + (img_row / 200 * imageSize), imageSize * 1.19, imageSize * 1.19, + imageXPos, imageYPos + (img_row / 200 * imageSize), imageSize * 1.19, imageSize * 1.19, challengeCache[challenge.id]["jackets"][i], 1, 0 ) img_col = img_col + 1 @@ -450,42 +515,122 @@ draw_selected = function(challenge, x, y, w, h) -- draw_scores(diff, xpos+xPadding+imageSize+3, (height/3)*2, width-imageSize-20, (height/3)-yPadding) -- else -- draw_scores(diff, xpos, (height/6)*5, width, (height/6)) - -- end + -- end + --]] gfx.ForceRender() + end -draw_challengewheel = function(x, y, w, h) - local offsetX = fifthX / 2 - local width = math.floor((w / 5) * 4) - local height = math.floor((h / wheelSize) * 1.5) +draw_diff_icon = function(diff, x, y, w, h, selected, deltaTime) + local shrinkX = w / 4 + local shrinkY = h / 4 + if selected then + gfx.FontSize(h / 2) + shrinkX = w / 6 + shrinkY = h / 6 + else + gfx.FontSize(math.floor(h / 3)) + end + gfx.BeginPath() + gfx.RoundedRectVarying(x + shrinkX, y + shrinkY, w - shrinkX * 2, h - shrinkY * 2, 0, 0, 0, 0) + gfx.FillColor(15, 15, 15) + gfx.StrokeColor(table.unpack(diffColors[diff.difficulty + 1])) + gfx.StrokeWidth(2) + gfx.Fill() + gfx.Stroke() + gfx.FillColor(255, 255, 255) + gfx.TextAlign(gfx.TEXT_ALIGN_MIDDLE + gfx.TEXT_ALIGN_CENTER) + gfx.FastText(tostring(diff.level), x + (w / 2), y + (h / 2)) + -- gfx.BeginPath() + -- DiffRectangle.render(deltaTime, 183, 2.5, 10, songCache[song.id][selectedDiff],tostring(diff.level)); +end - -- before selected - for i = math.max(selectedIndex - wheelSize / 2, 1), math.max(selectedIndex - 1, 0) do - local challenge = chalwheel.challenges[i] - local xpos = x + offsetX + ((selectedIndex - i + ioffset) ^ 2) * 3 - local offsetY = (selectedIndex - i + ioffset) - * (height - (wheelSize / 2 * ((selectedIndex - i + ioffset) * aspectFloat))) - local ypos = y + ((h / 2 - height / 2) - offsetY) - draw_challenge(challenge, xpos, ypos, width, height) +draw_diffs = function(diffs, x, y, w, h) + local diffWidth = w / 2.5 + local diffHeight = w / 2.5 + local diffCount = #diffs + gfx.Scissor(x, y, w, h) + for i = math.max(selectedDiff - 2, 1), math.max(selectedDiff - 1, 1) do + local diff = diffs[i] + local xpos = x + ((w / 2 - diffWidth / 2) + (selectedDiff - i + doffset) * (-0.8 * diffWidth)) + if i ~= selectedDiff then + draw_diff_icon(diff, xpos, y, diffWidth, diffHeight, false) + end end -- after selected - for i = math.min(selectedIndex + wheelSize / 2, #chalwheel.challenges), selectedIndex + 1, -1 do - local challenge = chalwheel.challenges[i] - local xpos = x + offsetX + ((i - selectedIndex - ioffset) ^ 2) * 2 - local offsetY = (selectedIndex - i + ioffset) - * (height - (wheelSize / 2 * ((i - selectedIndex - ioffset) * aspectFloat))) - local ypos = y + ((h / 2 - height / 2) - (selectedIndex - i) - offsetY) - local alpha = 255 - (selectedIndex - i + ioffset) * 31 - draw_challenge(challenge, xpos, ypos, width, height) + for i = math.min(selectedDiff + 2, diffCount), selectedDiff + 1, -1 do + local diff = diffs[i] + local xpos = x + ((w / 2 - diffWidth / 2) + (selectedDiff - i + doffset) * (-0.8 * diffWidth)) + if i ~= selectedDiff then + draw_diff_icon(diff, xpos, y, diffWidth, diffHeight, false) + end + end + local diff = diffs[selectedDiff] + local xpos = x + ((w / 2 - diffWidth / 2) + (doffset) * (-0.8 * diffWidth)) + draw_diff_icon(diff, xpos, y, diffWidth, diffHeight, true) + gfx.BeginPath() + gfx.FillColor(0, 128, 255) + gfx.Rect(x, y + 10, 2, diffHeight - h / 6) + gfx.Fill() + gfx.BeginPath() + gfx.Rect(x + w - 2, y + 10, 2, diffHeight - h / 6) + gfx.Fill() + gfx.ResetScissor() + draw_cursor(x + w / 2, y + diffHeight / 2, timer * math.pi, diffHeight / 1.5) +end + +draw_selected = function(challenge, x, y, w, h) + if not challenge then return end + + check_or_create_cache(challenge) + + draw_challenge(challenge, x, y, w, h, true) + +end + +draw_chalwheel = function(x, y, w, h) + local challengeAspect = 4.367 + local selectedChallengeAspect = 3.305 + + local portraitAspectCorrection = portraitWidescreenRatio / aspectFloat + + local width = math.floor(w * 0.839) + local height = math.floor((width / challengeAspect) * portraitAspectCorrection) + + local selectedWidth = math.floor(w * 0.944) + local selectedHeight = math.floor((selectedWidth / selectedChallengeAspect) * portraitAspectCorrection) + + local offsetX = w / 2 - width / 2 --center + local centerY = h / 2 - height / 2 + local selectedOffsetX = w / 2 - selectedWidth / 2 + local selectedCenterY = h / 2 - selectedHeight / 2 + local margin = h / 128 + local centerMargin = h / 100 + + local imin = math.ceil(selectedIndex - wheelSize / 2) + local imax = math.floor(selectedIndex + wheelSize / 2) + for i = math.max(imin, 1), math.min(imax, #chalwheel.challenges) do + local current = selectedIndex - i + if not (current == 0) then + local challenge = chalwheel.challenges[i] + local xpos = x + offsetX + --local offsetY = current * (height - (wheelSize / 2 * (current * aspectFloat))) + local offsetY = math.abs(current) * (height + margin) + (selectedHeight - height) / 2 + local ypos = y + centerY + if current < 0 then + ypos = ypos + centerMargin + offsetY + else -- if current > 0 then + ypos = ypos - centerMargin - offsetY + end + draw_challenge(challenge, xpos, ypos, width, height) + end end - -- draw selected - local xpos = x + offsetX / 1.2 + ((-ioffset) ^ 2) * 2 - local offsetY = (ioffset) * (height - (wheelSize / 2 * ((1) * aspectFloat))) - local ypos = y + ((h / 2 - height / 2) - (ioffset) - offsetY) - draw_challenge(chalwheel.challenges[selectedIndex], xpos, ypos, width, height, true) - return chalwheel.challenges[selectedIndex] + -- render selected song information + local xpos = x + selectedOffsetX + local ypos = y + selectedCenterY + draw_selected(chalwheel.challenges[selectedIndex], xpos, ypos, selectedWidth, selectedHeight) end draw_legend_pane = function(x, y, w, h, obj) @@ -565,21 +710,21 @@ render = function(deltaTime) gfx.FontSize(40); gfx.FillColor(255, 255, 255); if chalwheel.challenges and chalwheel.challenges[1] then - -- draw chalwheel and get selected song - local song = draw_challengewheel(0, 0, fullX, fullY) - -- render selected song information - draw_selected(song, 0, 0, fullX, fifthY) + -- draw chalwheel + draw_chalwheel(0, 0, fullX, fullY) end -- Draw Legend Information + --[[ if showGuide then draw_legend(0, (fifthY / 3) * 14, fullX, (fifthY / 3) * 1) end + --]] -- draw text search + --[[ draw_search(fifthX * 2, 5, fifthX * 3, fifthY / 5) - ioffset = ioffset * 0.9 doffset = doffset * 0.9 soffset = soffset * 0.8 if chalwheel.searchStatus then @@ -592,6 +737,7 @@ render = function(deltaTime) gfx.LoadSkinFont("dfmarugoth.ttf"); gfx.ResetTransform() gfx.ForceRender() + --]] end set_index = function(newIndex, scrollamt) @@ -599,7 +745,6 @@ set_index = function(newIndex, scrollamt) game.PlaySample("menu_click") scrollmulOffset = 0 end - ioffset = ioffset + selectedIndex - newIndex selectedIndex = newIndex scrollmul = scrollamt + scrollmulOffset end;