ExperimentalGear/scripts/songselect/songwheel.lua

805 lines
26 KiB
Lua

require('common')
local Easing = require('common.easings')
local Background = require('components.background');
local VolforceCalc = require('components.volforceCalc');
local dataPanelImage = gfx.CreateSkinImage("song_select/data_bg_overlay.png", 1)
local dataGlowOverlayImage = gfx.CreateSkinImage("song_select/data_panel/data_glow_overlay.png", 1)
local gradeBgImage = gfx.CreateSkinImage("song_select/data_panel/grade_bg.png", 1)
local badgeBgImage = gfx.CreateSkinImage("song_select/data_panel/clear_badge_bg.png", 1)
local effectedBgImage = gfx.CreateSkinImage("song_select/data_panel/effected_bg.png", 1)
local illustratedBgImage = gfx.CreateSkinImage("song_select/data_panel/illust_bg.png", 1)
local songPlateBg = gfx.CreateSkinImage("song_select/plate/bg.png", 1)
local songPlateBottomBarOverlayImage = gfx.CreateSkinImage("song_select/plate/bottom_bar_overlay.png", 1)
local tstImage = gfx.CreateSkinImage("song_select/textboard.png", 1)
local crownImage = gfx.CreateSkinImage("song_select/crown.png", 1)
local laserAnimBaseImage = gfx.CreateSkinImage("song_select/laser_anim.png", 1)
local top50OverlayImage = gfx.CreateSkinImage("song_select/top50.png", 1)
local top50JacketOverlayImage = gfx.CreateSkinImage("song_select/top50_jacket.png", 1)
local diffCursorImage = gfx.CreateSkinImage("song_select/level_cursor.png", 1)
local filterInfoBgImage = gfx.CreateSkinImage("song_select/filter_info_bg.png", 1)
local sortInfoBgImage = gfx.CreateSkinImage("song_select/sort_info_bg.png", 1)
local searchBgImage = gfx.CreateSkinImage("song_select/search_bg.png", 1)
local defaultJacketImage = gfx.CreateSkinImage("song_select/loading.png", 0)
local difficultyLabelImages = {
gfx.CreateSkinImage("song_select/plate/difficulty_labels/novice.png", 1),
gfx.CreateSkinImage("song_select/plate/difficulty_labels/advanced.png", 1),
gfx.CreateSkinImage("song_select/plate/difficulty_labels/exhaust.png", 1),
gfx.CreateSkinImage("song_select/plate/difficulty_labels/maximum.png", 1),
gfx.CreateSkinImage("song_select/plate/difficulty_labels/infinite.png", 1),
gfx.CreateSkinImage("song_select/plate/difficulty_labels/gravity.png", 1),
gfx.CreateSkinImage("song_select/plate/difficulty_labels/heavenly.png", 1),
gfx.CreateSkinImage("song_select/plate/difficulty_labels/vivid.png", 1),
}
local badgeImages = {
gfx.CreateSkinImage("song_select/medal/nomedal.png", 1),
gfx.CreateSkinImage("song_select/medal/played.png", 1),
gfx.CreateSkinImage("song_select/medal/clear.png", 1),
gfx.CreateSkinImage("song_select/medal/hard.png", 1),
gfx.CreateSkinImage("song_select/medal/uc.png", 1),
gfx.CreateSkinImage("song_select/medal/puc.png", 1),
}
local gradeCutoffs = {
D = 0000000,
C = 7000000,
B = 8000000,
A = 8700000,
A_P = 9000000,
AA = 9300000,
AA_P = 9500000,
AAA = 9700000,
AAA_P = 9800000,
S = 9900000,
}
local gradeImages = {
S = gfx.CreateSkinImage("common/grades/S.png", 0),
AAA_P = gfx.CreateSkinImage("common/grades/AAA+.png", 0),
AAA = gfx.CreateSkinImage("common/grades/AAA.png", 0),
AA_P = gfx.CreateSkinImage("common/grades/AA+.png", 0),
AA = gfx.CreateSkinImage("common/grades/AA.png", 0),
A_P = gfx.CreateSkinImage("common/grades/A+.png", 0),
A = gfx.CreateSkinImage("common/grades/A.png", 0),
B = gfx.CreateSkinImage("common/grades/B.png", 0),
C = gfx.CreateSkinImage("common/grades/C.png", 0),
D = gfx.CreateSkinImage("common/grades/D.png", 0),
none = gfx.CreateSkinImage("common/grades/none.png", 0),
}
local difficultyLabelUnderImages = {
gfx.CreateSkinImage("songtransition/difficulty_labels/nov.png", 0),
gfx.CreateSkinImage("songtransition/difficulty_labels/adv.png", 0),
gfx.CreateSkinImage("songtransition/difficulty_labels/exh.png", 0),
gfx.CreateSkinImage("songtransition/difficulty_labels/mxm.png", 0),
gfx.CreateSkinImage("songtransition/difficulty_labels/inf.png", 0),
gfx.CreateSkinImage("songtransition/difficulty_labels/grv.png", 0),
gfx.CreateSkinImage("songtransition/difficulty_labels/hvn.png", 0),
gfx.CreateSkinImage("songtransition/difficulty_labels/vvd.png", 0),
}
game.LoadSkinSample('song_wheel/cursor_change.wav');
game.LoadSkinSample('song_wheel/diff_change.wav');
local difficultyNumbers;
local scoreNumbers;
local resx, resy = game.GetResolution()
local desw, desh;
local scale;
local songPlateHeight = 172;
local selectedIndex = 1;
local selectedDifficulty = 1;
local jacketCache = {}
local top50diffs = {}
local transitionScrollScale = 0;
local transitionScrollOffsetY = 0;
local scrollingUp = false;
local transitionAfterscrollScale = 0;
local transitionAfterscrollDataOverlayAlpha = 0;
local transitionAfterscrollGradeAlpha = 0;
local transitionAfterscrollBadgeAlpha = 0;
local transitionAfterscrollTextSongTitle = 0;
local transitionAfterscrollTextSongArtist = 0;
local transitionAfterscrollDifficultiesAlpha = 0;
local transitionJacketBgScrollScale = 0;
local transitionJacketBgScrollAlpha = 0;
local transitionJacketBgScrollPosX = 0;
local transitionLaserScale = 0;
local transitionLaserY = 0;
-- Flash transition (animation)
-- Used for flashing the badges
-- 0 = minimum brightness; 0.5 = maximum brightness; 1 = minimum brightness again
local transitionFlashScale = 0;
local transitionFlashAlpha = 1;
local transitionLeaveReverse = false;
local transitionLeaveScale = 0;
local transitionLeaveOffsetY = 0;
function resetLayoutInformation()
resx, resy = game.GetResolution()
desw = 1080
desh = 1920
scale = resx / desw
end
function load_number_image(path)
local images = {}
for i = 0, 9 do
images[i + 1] = gfx.CreateSkinImage(string.format("%s/%d.png", path, i), 0)
end
return images
end
function draw_number(x, y, alpha, num, digits, images, is_dim, scale, kern)
scale = scale or 1;
kern = kern or 1;
local tw, th = gfx.ImageSize(images[1])
tw = tw * scale;
th = th * scale;
x = x + (tw * (digits - 1)) / 2
y = y - th / 2
for i = 1, digits do
local mul = 10 ^ (i - 1)
local digit = math.floor(num / mul) % 10
local a = alpha
if is_dim and num < mul then
a = 0.4
end
gfx.BeginPath()
gfx.ImageRect(x, y, tw, th, images[digit + 1], a, 0)
x = x - (tw * kern)
end
end
function getCorrectedIndex(from, offset)
total = #songwheel.songs;
if (math.abs(offset) > total) then
if (offset < 0) then
offset = offset + total*math.floor(math.abs(offset)/total);
else
offset = offset - total*math.floor(math.abs(offset)/total);
end
end
index = from + offset;
if index < 1 then
index = total + (from+offset) -- this only happens if the offset is negative
end;
if index > total then
indexesUntilEnd = total - from;
index = offset - indexesUntilEnd -- this only happens if the offset is positive
end;
return index;
end;
function getJacketImage(song)
if not jacketCache[song.id] or jacketCache[song.id]==defaultJacketImage then
jacketCache[song.id] = gfx.LoadImageJob(song.difficulties[
math.min(selectedDifficulty, #song.difficulties)
].jacketPath, defaultJacketImage, 500, 500);
end
return jacketCache[song.id];
end
function getGradeImageForScore(score)
local gradeImage = gradeImages.none;
local bestGradeCutoff = 0;
for gradeName, scoreCutoff in pairs(gradeCutoffs) do
if scoreCutoff <= score then
if scoreCutoff > bestGradeCutoff then
gradeImage = gradeImages[gradeName];
bestGradeCutoff = scoreCutoff;
end
end
end
return gradeImage;
end
function drawLaserAnim()
gfx.BeginPath()
gfx.Scissor(0, transitionLaserY, desw, 100);
gfx.ImageRect(0, 0, desw, desh, laserAnimBaseImage, 1, 0)
gfx.ResetScissor();
end
function drawBackground(deltaTime)
Background.draw(deltaTime)
-- If the score for song exists
local song = songwheel.songs[selectedIndex];
local diff = song and song.difficulties[selectedDifficulty] or false;
if song and diff then
local jacketImage = getJacketImage(song);
gfx.BeginPath()
gfx.ImageRect(transitionJacketBgScrollPosX, 0, 900, 900, jacketImage or defaultJacketImage, transitionJacketBgScrollAlpha, 0)
gfx.BeginPath();
gfx.FillColor(0,0,0,math.floor(transitionJacketBgScrollAlpha*64));
gfx.Rect(0,0,900,900);
gfx.Fill();
gfx.ClosePath();
gfx.BeginPath();
end
gfx.ImageRect(0, 0, desw, desh, dataPanelImage, 1, 0)
drawLaserAnim()
if song and diff then
gfx.BeginPath()
gfx.ImageRect(0, 0, desw, desh, dataGlowOverlayImage, transitionAfterscrollDataOverlayAlpha, 0)
gfx.BeginPath()
gfx.ImageRect(341, 754, 85, 85, gradeBgImage, transitionAfterscrollDataOverlayAlpha, 0)
gfx.BeginPath()
gfx.ImageRect(391, 687, 180*0.85, 226*0.85, badgeBgImage, transitionAfterscrollDataOverlayAlpha, 0)
gfx.BeginPath()
gfx.ImageRect(95, 1165, 433, 30, effectedBgImage, transitionAfterscrollDataOverlayAlpha, 0)
gfx.BeginPath()
gfx.ImageRect(95, 1195, 433, 30, illustratedBgImage, transitionAfterscrollDataOverlayAlpha, 0)
end
end
function drawSong(song, y)
if (not song) then return end;
local songX = desw/2+28
local selectedSongDifficulty = song.difficulties[math.min(selectedDifficulty, #song.difficulties)] -- Limit selecting difficulty that is above the number that the song has
if not selectedSongDifficulty then
return;
end
local bestScore;
if selectedSongDifficulty.scores then
bestScore = selectedSongDifficulty.scores[1];
end
-- Draw the bg for the song plate
gfx.BeginPath()
gfx.ImageRect(songX, y, 515, 172, songPlateBg, 1, 0)
-- Draw jacket
local jacketImage = getJacketImage(song);
gfx.BeginPath()
gfx.ImageRect(songX+4, y+4, 163, 163, jacketImage or defaultJacketImage, 1, 0)
-- Draw the overlay for the song plate (that bottom black bar)
gfx.BeginPath()
gfx.ImageRect(songX, y, 515, 172, songPlateBottomBarOverlayImage, 1, 0)
-- Draw the difficulty notch background
gfx.BeginPath()
local diffIndex = GetDisplayDifficulty(selectedSongDifficulty.jacketPath, selectedSongDifficulty.difficulty)
gfx.ImageRect(songX, y+95, 83, 74, difficultyLabelImages[diffIndex], 1, 0)
-- Draw the difficulty level number
gfx.BeginPath()
draw_number(songX+30, y+125, 1.0, selectedSongDifficulty.level, 2, difficultyNumbers, false, 0.65, 1)
-- Draw song title
gfx.FontSize(24)
gfx.TextAlign(gfx.TEXT_ALIGN_LEFT + gfx.TEXT_ALIGN_MIDDLE)
gfx.Text(song.title, songX+90, y+155);
-- Draw score badge
local badgeImage = badgeImages[1];
if selectedSongDifficulty.topBadge then
badgeImage = badgeImages[selectedSongDifficulty.topBadge+1];
end
local badgeAlpha = 1;
if (selectedSongDifficulty.topBadge >= 3) then
badgeAlpha = transitionFlashAlpha; -- If hard clear or above, flash the badge
end
gfx.BeginPath()
gfx.ImageRect(songX+282, y+44, 79, 69, badgeImage, badgeAlpha, 0)
-- Draw grade
local gradeImage = gradeImages.none;
local gradeAlpha = 1;
if bestScore then
gradeImage = getGradeImageForScore(bestScore.score)
if (bestScore.score >= gradeCutoffs.S) then
gradeAlpha = transitionFlashAlpha; -- If S, flash the badge
end
end
gfx.BeginPath();
gfx.ImageRect(songX+391, y+47, 60, 60, gradeImage, gradeAlpha, 0);
-- Draw top 50 label if applicable
if (top50diffs[selectedSongDifficulty.id]) then
gfx.BeginPath();
gfx.ImageRect(songX+82, y+109, 506*0.85, 26*0.85, top50OverlayImage, 1, 0);
end
end
function drawSongList()
local numOfSongsAround = 7; -- How many songs should be up and how many should be down of the selected one
local yOffset = transitionLeaveOffsetY + transitionScrollOffsetY;
local i=1;
while (i <= numOfSongsAround) do
local songIndex = getCorrectedIndex(selectedIndex, -i)
drawSong(songwheel.songs[songIndex], desh/2-songPlateHeight/2-songPlateHeight*i + yOffset)
i=i+1;
end;
-- Draw the selected song
drawSong(songwheel.songs[selectedIndex], desh/2-songPlateHeight/2 + yOffset)
i=1;
while (i <= numOfSongsAround) do
local songIndex = getCorrectedIndex(selectedIndex, i)
drawSong(songwheel.songs[songIndex], desh/2-songPlateHeight/2+songPlateHeight*i + yOffset)
i=i+1;
end;
end
local scoreNumbers = load_number_image("score_num");
function drawData() -- Draws the song data on the left panel
local song = songwheel.songs[selectedIndex];
local diff = song and song.difficulties[selectedDifficulty] or false;
local bestScore = diff and diff.scores[1];
if not song then return false end
local jacketImage = getJacketImage(song);
gfx.BeginPath()
gfx.ImageRect(96, 324, 348, 348, jacketImage or defaultJacketImage, 1, 0)
if (top50diffs[diff.id]) then
gfx.BeginPath()
gfx.ImageRect(96, 529, 410*0.85, 168*0.85, top50JacketOverlayImage, 1, 0)
end
gfx.Save()
-- Draw best score
gfx.BeginPath()
local scoreNumber = 0;
if bestScore then
scoreNumber = bestScore.score
end
draw_number(100, 793, 1.0, math.floor(scoreNumber / 10000), 4, scoreNumbers, true, 0.3, 1.12)
draw_number(253, 798, 1.0, scoreNumber, 4, scoreNumbers, true, 0.22, 1.12)
-- Draw grade
local gradeImage = gradeImages.none;
local gradeAlpha = transitionAfterscrollGradeAlpha;
if bestScore then
gradeImage = getGradeImageForScore(bestScore.score)
if (transitionAfterscrollGradeAlpha == 1 and bestScore.score >= gradeCutoffs.S) then
gradeAlpha = transitionFlashAlpha; -- If S, flash the badge
end
end
gfx.BeginPath();
gfx.ImageRect(360, 773, 45, 45, gradeImage, gradeAlpha, 0);
-- Draw badge
badgeImage = badgeImages[diff.topBadge+1];
local badgeAlpha = transitionAfterscrollBadgeAlpha;
if (transitionAfterscrollBadgeAlpha == 1 and diff.topBadge >= 3) then
badgeAlpha = transitionFlashAlpha; -- If hard clear or above, flash the badge, but only after the initial transition
end
gfx.BeginPath()
gfx.ImageRect(425, 724, 93/1.1, 81/1.1, badgeImage, badgeAlpha, 0)
gfx.Restore()
-- Draw BPM
gfx.BeginPath();
gfx.FontSize(24)
gfx.TextAlign(gfx.TEXT_ALIGN_LEFT + gfx.TEXT_ALIGN_MIDDLE)
gfx.Save()
gfx.LoadSkinFont('Digital-Serial-Bold.ttf')
gfx.GlobalAlpha(transitionAfterscrollDataOverlayAlpha) -- TODO: split this out
gfx.Text(song.bpm, 85, 920);
gfx.Restore()
-- Draw song title
gfx.FontSize(28)
gfx.GlobalAlpha(transitionAfterscrollTextSongTitle);
gfx.Text(song.title, 30+(1-transitionAfterscrollTextSongTitle)*20, 955);
-- Draw artist
gfx.GlobalAlpha(transitionAfterscrollTextSongArtist);
gfx.Text(song.artist, 30+(1-transitionAfterscrollTextSongArtist)*30, 997);
gfx.GlobalAlpha(1);
-- Draw difficulties
local DIFF_X_START = 98.5
local DIFF_GAP = 114.8;
gfx.GlobalAlpha(transitionAfterscrollDifficultiesAlpha);
for i, diff in ipairs(song.difficulties) do
gfx.BeginPath()
local index = diff.difficulty+1
if i == selectedDifficulty then
gfx.ImageRect(DIFF_X_START+(index-1)*DIFF_GAP-(163*0.8)/2, 1028, 163*0.8, 163*0.8, diffCursorImage, 1, 0)
end
draw_number(85+(index-1)*DIFF_GAP, 1085, 1.0, diff.level, 2, difficultyNumbers, false, 0.8, 1)
local diffLabelImage = difficultyLabelUnderImages[
GetDisplayDifficulty(diff.jacketPath, diff.difficulty)
];
local tw, th = gfx.ImageSize(diffLabelImage)
tw=tw*0.9
th=th*0.9
gfx.BeginPath()
gfx.ImageRect(DIFF_X_START+(index-1)*DIFF_GAP-tw/2, 1050, tw, th, diffLabelImage, 1, 0)
end
gfx.GlobalAlpha(1);
local drawTOPLAY = function()
local topX = 430
local topTX = 326
local div = 33
local divH = 1300
local spdiv= 33.3
gfx.LoadSkinFont('Digital-Serial-Bold.ttf')
gfx.FontSize(32)
gfx.BeginPath();
gfx.ImageRect(75, 1250, 336*1.2, spdiv, tstImage, 1, 0);
gfx.BeginPath();
gfx.ImageRect(75, 1250+spdiv, 336*1.2, spdiv, tstImage, 1, 0);
gfx.BeginPath();
gfx.ImageRect(75, 1250+spdiv+spdiv, 336*1.2, spdiv, tstImage, 1, 0);
gfx.BeginPath();
gfx.ImageRect(75, 1250+spdiv+spdiv+spdiv, 336*1.2, spdiv, tstImage, 1, 0);
gfx.BeginPath();
gfx.ImageRect(75, 1250+spdiv+spdiv+spdiv+spdiv, 336*1.2, spdiv, tstImage, 1, 0);
gfx.BeginPath();
gfx.ImageRect(75, 1250+spdiv+spdiv+spdiv+spdiv+spdiv, 336*1.2, spdiv, tstImage, 1, 0);
gfx.BeginPath();
gfx.ImageRect(205, 1252.5, 800*0.045, 600*0.045, crownImage, 1, 0);
gfx.TextAlign(gfx.TEXT_ALIGN_RIGHT + gfx.TEXT_ALIGN_MIDDLE)
gfx.Text("TOP", topTX+div/2, divH-div);
gfx.Text(scoreNumber, topX, divH);
gfx.Text(game.GetSkinSetting("username"), topX/1.78, divH);
gfx.Text(scoreNumber, topX, divH+div);
gfx.Text(game.GetSkinSetting("username"), topX/1.78, divH+div);
gfx.Text(scoreNumber, topX, divH+div+div);
gfx.Text(game.GetSkinSetting("username"), topX/1.78, divH+div+div);
gfx.Text(scoreNumber, topX, divH+div+div+div);
gfx.Text(game.GetSkinSetting("username"), topX/1.78, divH+div+div+div);
gfx.Text(scoreNumber, topX, divH+div+div+div+div);
gfx.Text(game.GetSkinSetting("username"), topX/1.78, divH+div+div+div+div);
end
gfx.FontSize(22)
gfx.GlobalAlpha(transitionAfterscrollDataOverlayAlpha);
gfx.Text(diff.effector, 270, 1180); -- effected by
gfx.Text(diff.illustrator, 270, 1210); -- illustrated by
gfx.GlobalAlpha(1);
drawTOPLAY()
end
function drawFilterInfo(deltatime)
gfx.BeginPath()
gfx.ImageRect(5, 95, 417*0.85, 163*0.85, filterInfoBgImage, 1, 0)
local folderLabel = game.GetSkinSetting('_songWheelActiveFolderLabel')
local subFolderLabel = game.GetSkinSetting('_songWheelActiveSubFolderLabel')
local sortOptionLabel = game.GetSkinSetting('_songWheelActiveSortOptionLabel')
gfx.FontSize(24)
gfx.TextAlign(gfx.TEXT_ALIGN_CENTER + gfx.TEXT_ALIGN_MIDDLE)
gfx.BeginPath()
gfx.Text(folderLabel or '', 167, 131);
gfx.BeginPath()
gfx.Text(subFolderLabel or '', 195, 166);
gfx.BeginPath()
gfx.ImageRect(desw - 310 - 5, 108, 310, 75, sortInfoBgImage, 1, 0)
gfx.BeginPath()
gfx.Text(sortOptionLabel or '', desw-150, 130);
end
function drawSearch()
if (not songwheel.searchInputActive) then
return;
end
gfx.BeginPath();
local tw, th = gfx.ImageSize(searchBgImage)
gfx.ImageRect(desw-tw/2, 0, tw/2, th/2, searchBgImage, 1, 0)
gfx.FontSize(28);
gfx.Text(songwheel.searchText, desw-200, 30);
end
function tickTransitions(deltaTime)
if transitionScrollScale < 1 then
transitionScrollScale = transitionScrollScale + deltaTime / 0.1 -- transition should last for that time in seconds
else
transitionScrollScale = 1
end
if transitionAfterscrollScale < 1 then
if transitionScrollScale == 1 then
-- Only start the after scroll transition when the scroll transition is finished
transitionAfterscrollScale = transitionAfterscrollScale + deltaTime / 15
end
else
transitionAfterscrollScale = 1;
end
if scrollingUp then
transitionScrollOffsetY = Easing.inQuad(1-transitionScrollScale) * songPlateHeight;
else
transitionScrollOffsetY = Easing.inQuad(1-transitionScrollScale) * -songPlateHeight;
end
if transitionAfterscrollScale < 0.02 then
transitionAfterscrollDataOverlayAlpha = math.min(1, transitionAfterscrollScale / 0.02)
else
transitionAfterscrollDataOverlayAlpha = 1;
end
-- Grade alpha
if transitionAfterscrollScale >= 0.03 and transitionAfterscrollScale < 0.033 then
transitionAfterscrollGradeAlpha = 0.5;
elseif transitionAfterscrollScale >= 0.04 then
transitionAfterscrollGradeAlpha = 1;
else
transitionAfterscrollGradeAlpha = 0;
end
-- Badge alpha
if transitionAfterscrollScale >= 0.032 and transitionAfterscrollScale < 0.035 then
transitionAfterscrollBadgeAlpha = 0.5;
elseif transitionAfterscrollScale >= 0.042 then
transitionAfterscrollBadgeAlpha = 1;
else
transitionAfterscrollBadgeAlpha = 0;
end
-- Song title alpha and pos
if transitionAfterscrollScale < 0.025 then
transitionAfterscrollTextSongTitle = Easing.outQuad(math.min(1, (transitionAfterscrollScale) / 0.025));
else
transitionAfterscrollTextSongTitle = 1
end
-- Song artist alpha and pos
if transitionAfterscrollScale < 0.025 then
transitionAfterscrollTextSongArtist = Easing.outQuad(math.min(1, (transitionAfterscrollScale) / 0.025));
else
transitionAfterscrollTextSongArtist = 1
end
-- Difficulties alpha
if transitionAfterscrollScale < 0.025 then
transitionAfterscrollDifficultiesAlpha = math.min(1, transitionAfterscrollScale / 0.025)
else
transitionAfterscrollDifficultiesAlpha = 1;
end
-- Jacket bg animation
if transitionJacketBgScrollScale < 1 then
transitionJacketBgScrollScale = transitionJacketBgScrollScale + deltaTime / 20 -- transition should last for that time in seconds
else
transitionJacketBgScrollScale = 0
end
if transitionJacketBgScrollScale < 0.05 or transitionJacketBgScrollScale >= 1 then
transitionJacketBgScrollAlpha = 0;
elseif transitionJacketBgScrollScale >= 0.05 and transitionJacketBgScrollScale < 0.1 then
transitionJacketBgScrollAlpha = math.min(1, (transitionJacketBgScrollScale-0.05) / 0.05);
elseif transitionJacketBgScrollScale >= 0.8 and transitionJacketBgScrollScale < 1 then
transitionJacketBgScrollAlpha = math.max(0,
math.min(1, 1-((transitionJacketBgScrollScale-0.8) / 0.05))
);
else
transitionJacketBgScrollAlpha = 1;
end
transitionJacketBgScrollPosX = 0+(transitionJacketBgScrollScale*(0.8/1))*-300;
-- Laser anim
if transitionLaserScale < 1 then
transitionLaserScale = transitionLaserScale + deltaTime / 2 -- transition should last for that time in seconds
else
transitionLaserScale = 0
end
transitionLaserY = desh - math.min(transitionLaserScale * 2 * desh, desh);
-- Flash transition
if transitionFlashScale < 1 then
local songBpm = 120;
if (songwheel.songs[selectedIndex] and game.GetSkinSetting('animations_affectWithBPM')) then
songBpm = songwheel.songs[selectedIndex].bpm;
-- Is a variable BPM
if (type(songBpm) == "string") then
local s = split(songBpm, '-');
songBpm = tonumber(s[1]); -- Lowest bpm value
end
end
-- If the original songBpm is "2021.04.01" for example, the above code can produce `nil` in the songBpm
-- since it cannot parse the number out of that string. Here we implement a fallback, to not crash
-- USC on whacky charts. Whacky charters, quit using batshit insane bpm values. It makes me angery >:(
if (songBpm == nil) then
songBpm = 120;
end
transitionFlashScale = transitionFlashScale + deltaTime / (60/songBpm) -- transition should last for that time in seconds
else
transitionFlashScale = 0
end
if transitionFlashScale < 0.5 then
transitionFlashAlpha = transitionFlashScale * 2;
else
transitionFlashAlpha = 1-((transitionFlashScale-0.5) * 2);
end
transitionFlashAlpha = 1+transitionFlashAlpha*0.5
-- Leave transition
if (transitionLeaveReverse) then
if transitionLeaveScale > 0 then
transitionLeaveScale = transitionLeaveScale - deltaTime / 0.5 -- transition should last for that time in seconds
else
transitionLeaveScale = 0
end
else
if transitionLeaveScale < 1 then
transitionLeaveScale = transitionLeaveScale + deltaTime / 0.5 -- transition should last for that time in seconds
else
transitionLeaveScale = 1
end
end
transitionLeaveOffsetY = Easing.inOutQuad(transitionLeaveScale) * (desh+songPlateHeight*2+145);
end
render = function (deltaTime)
resetLayoutInformation();
tickTransitions(deltaTime);
gfx.Scale(scale, scale);
if not difficultyNumbers then
difficultyNumbers = load_number_image('diff_num')
end
drawBackground(deltaTime);
drawSongList()
drawData()
drawFilterInfo(deltaTime)
drawSearch();
if (game.GetSkinSetting('_songWheelOverlayActive') ~= 1) then
transitionLeaveReverse = true;
else
transitionLeaveReverse = false;
end
gfx.BeginPath();
gfx.FontSize(18)
gfx.TextAlign(gfx.TEXT_ALIGN_LEFT + gfx.TEXT_ALIGN_TOP)
local debugScrollingUp= "FALSE"
if scrollingUp then debugScrollingUp = "TRUE" end;
-- gfx.Text('S_I: ' .. selectedIndex .. ' // S_D: ' .. selectedDifficulty .. ' // S_UP: ' .. debugScrollingUp .. ' // AC_TS: ' .. transitionAfterscrollScale, 8, 8);
end
songs_changed = function (withAll)
if not withAll then return end
game.SetSkinSetting('_songWheelScrollbarTotal', #songwheel.songs)
game.SetSkinSetting('_songWheelScrollbarIndex', selectedIndex)
local diffs = {}
for i = 1, #songwheel.allSongs do
local song = songwheel.allSongs[i]
for j = 1, #song.difficulties do
local diff = song.difficulties[j]
diff.force = VolforceCalc.calc(diff)
table.insert(diffs, diff)
end
end
table.sort(diffs, function (l, r)
return l.force > r.force
end)
totalForce = 0
for i = 1, 50 do
if diffs[i] then
top50diffs[diffs[i].id] = true;
totalForce = totalForce + diffs[i].force
end
end
game.SetSkinSetting('_volforce', totalForce)
end
set_index = function(newIndex)
transitionScrollScale = 0;
transitionAfterscrollScale = 0;
transitionJacketBgScrollScale = 0;
game.SetSkinSetting('_songWheelScrollbarTotal', #songwheel.songs)
game.SetSkinSetting('_songWheelScrollbarIndex', newIndex)
scrollingUp = false;
if ((newIndex > selectedIndex and not (newIndex == #songwheel.songs and selectedIndex == 1)) or (newIndex == 1 and selectedIndex == #songwheel.songs)) then
scrollingUp = true;
end;
game.PlaySample('song_wheel/cursor_change.wav');
selectedIndex = newIndex;
end;
set_diff = function(newDiff)
if newDiff ~= selectedDifficulty then
jacketCache = {}; -- Clear the jacket cache for the new diff jackets
game.PlaySample('song_wheel/diff_change.wav');
end
selectedDifficulty = newDiff;
end;