2021-08-07 20:35:00 +02:00
require ( ' common ' )
2021-12-23 03:52:12 +01:00
local Easing = require ( ' common.easing ' )
2021-12-02 03:41:12 +01:00
local Background = require ( ' components.background ' )
2021-11-20 22:43:11 +01:00
local common = require ( ' common.common ' )
2021-12-02 03:41:12 +01:00
local Numbers = require ( ' common.numbers ' )
2021-08-09 20:48:31 +02:00
2021-12-02 03:41:12 +01:00
local VolforceCalc = require ( ' components.volforceCalc ' )
2021-08-12 21:21:42 +02:00
2021-11-22 20:23:34 +01:00
local backgroundImage = gfx.CreateSkinImage ( " bg_pattern.png " , gfx.IMAGE_REPEATX | gfx.IMAGE_REPEATY )
2021-08-01 20:00:45 +02:00
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 )
2021-07-30 16:37:01 +02:00
local songPlateBg = gfx.CreateSkinImage ( " song_select/plate/bg.png " , 1 )
local songPlateBottomBarOverlayImage = gfx.CreateSkinImage ( " song_select/plate/bottom_bar_overlay.png " , 1 )
2021-10-25 21:06:06 +02:00
local scoreBoardBarBgImage = gfx.CreateSkinImage ( " song_select/textboard.png " , 1 )
2021-10-24 21:51:41 +02:00
local crownImage = gfx.CreateSkinImage ( " song_select/crown.png " , 1 )
2021-08-16 15:58:28 +02:00
2021-08-16 16:29:21 +02:00
local laserAnimBaseImage = gfx.CreateSkinImage ( " song_select/laser_anim.png " , 1 )
2021-08-16 15:50:53 +02:00
local top50OverlayImage = gfx.CreateSkinImage ( " song_select/top50.png " , 1 )
2021-08-16 15:58:28 +02:00
local top50JacketOverlayImage = gfx.CreateSkinImage ( " song_select/top50_jacket.png " , 1 )
2021-07-30 16:37:01 +02:00
2021-07-31 22:53:05 +02:00
local diffCursorImage = gfx.CreateSkinImage ( " song_select/level_cursor.png " , 1 )
2021-07-30 18:27:43 +02:00
2021-08-13 17:35:26 +02:00
local filterInfoBgImage = gfx.CreateSkinImage ( " song_select/filter_info_bg.png " , 1 )
2021-08-14 17:49:12 +02:00
local sortInfoBgImage = gfx.CreateSkinImage ( " song_select/sort_info_bg.png " , 1 )
2021-08-13 17:35:26 +02:00
2021-08-05 22:01:17 +02:00
local searchBgImage = gfx.CreateSkinImage ( " song_select/search_bg.png " , 1 )
2021-07-30 18:40:49 +02:00
local defaultJacketImage = gfx.CreateSkinImage ( " song_select/loading.png " , 0 )
2021-07-30 16:37:01 +02:00
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 ) ,
2021-07-25 20:10:06 +02:00
}
2021-07-30 18:27:43 +02:00
local badgeImages = {
gfx.CreateSkinImage ( " song_select/medal/nomedal.png " , 1 ) ,
gfx.CreateSkinImage ( " song_select/medal/played.png " , 1 ) ,
2021-07-30 18:40:49 +02:00
gfx.CreateSkinImage ( " song_select/medal/clear.png " , 1 ) ,
2021-07-30 18:27:43 +02:00
gfx.CreateSkinImage ( " song_select/medal/hard.png " , 1 ) ,
gfx.CreateSkinImage ( " song_select/medal/uc.png " , 1 ) ,
gfx.CreateSkinImage ( " song_select/medal/puc.png " , 1 ) ,
}
2021-11-20 19:27:28 +01:00
local cursorImages = {
gfx.CreateSkinImage ( " song_select/cursor.png " , 1 ) , -- Effective rate or fallback
gfx.CreateSkinImage ( " song_select/cursor_exc.png " , 1 ) , -- Excessive rate
gfx.CreateSkinImage ( " song_select/cursor_perm.png " , 1 ) , -- Premissive rate
gfx.CreateSkinImage ( " song_select/cursor_blast.png " , 1 ) , -- Blastive rate
}
2021-07-31 18:43:17 +02:00
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 ) ,
}
2021-07-31 22:53:05 +02:00
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 ) ,
}
2021-07-30 22:06:08 +02:00
game.LoadSkinSample ( ' song_wheel/cursor_change.wav ' ) ;
2021-08-12 14:29:55 +02:00
game.LoadSkinSample ( ' song_wheel/diff_change.wav ' ) ;
2021-07-30 22:06:08 +02:00
2021-12-02 03:41:12 +01:00
local scoreNumbers = Numbers.load_number_image ( " score_num " )
local difficultyNumbers = Numbers.load_number_image ( " diff_num " )
2021-07-25 20:10:06 +02:00
2021-12-14 19:08:46 +01:00
local LEADERBOARD_PLACE_NAMES = {
' 1st ' ,
' 2nd ' ,
' 3rd ' ,
' 4th ' ,
}
2021-07-30 21:34:36 +02:00
local songPlateHeight = 172 ;
2021-07-30 16:37:01 +02:00
local selectedIndex = 1 ;
local selectedDifficulty = 1 ;
2021-07-25 20:10:06 +02:00
2021-07-30 16:37:01 +02:00
local jacketCache = { }
2021-07-25 20:10:06 +02:00
2021-08-16 15:50:53 +02:00
local top50diffs = { }
2021-12-16 16:52:03 +01:00
local irRequestStatus = 1 ; -- 0=unused, 1=not requested, 2=loading, others are status codes
2021-12-14 20:02:25 +01:00
local irRequestTimeout = 2
2021-12-14 19:08:46 +01:00
local irLeaderboard = { }
2021-12-16 18:01:33 +01:00
local irLeaderboardsCache = { }
2021-12-14 19:08:46 +01:00
2021-07-30 21:34:36 +02:00
local transitionScrollScale = 0 ;
local transitionScrollOffsetY = 0 ;
local scrollingUp = false ;
2021-07-31 22:14:34 +02:00
local transitionAfterscrollScale = 0 ;
local transitionAfterscrollDataOverlayAlpha = 0 ;
local transitionAfterscrollGradeAlpha = 0 ;
local transitionAfterscrollBadgeAlpha = 0 ;
2021-08-01 18:08:52 +02:00
local transitionAfterscrollTextSongTitle = 0 ;
local transitionAfterscrollTextSongArtist = 0 ;
2021-07-31 23:00:32 +02:00
local transitionAfterscrollDifficultiesAlpha = 0 ;
2021-07-31 22:14:34 +02:00
2021-08-26 19:50:33 +02:00
local transitionJacketBgScrollScale = 0 ;
local transitionJacketBgScrollAlpha = 0 ;
local transitionJacketBgScrollPosX = 0 ;
2021-08-16 16:29:21 +02:00
local transitionLaserScale = 0 ;
local transitionLaserY = 0 ;
2021-08-26 15:31:28 +02:00
-- 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 ;
2021-11-20 19:12:12 +01:00
local isFilterWheelActive = false ;
2021-08-12 16:55:10 +02:00
local transitionLeaveScale = 0 ;
2021-11-20 19:36:00 +01:00
local transitionLeaveReappearTimer = 0 ;
2021-11-20 19:12:12 +01:00
local TRANSITION_LEAVE_DURATION = 0.1 ;
2021-08-09 20:48:31 +02:00
2021-11-22 20:23:34 +01:00
-- Window variables
local resX , resY
-- Aspect Ratios
local landscapeWidescreenRatio = 16 / 9
local landscapeStandardRatio = 4 / 3
local portraitWidescreenRatio = 9 / 16
-- Portrait sizes
local fullX , fullY
local desw = 1080
local desh = 1920
local resolutionChange = function ( x , y )
resX = x
resY = y
fullX = portraitWidescreenRatio * y
fullY = y
2021-11-22 22:25:38 +01:00
game.Log ( ' resX: ' .. resX .. ' // resY: ' .. resY .. ' // fullX: ' .. fullX .. ' // fullY: ' .. fullY , game.LOGGER_ERROR ) ;
2021-07-25 20:10:06 +02:00
end
2021-07-30 20:18:03 +02:00
function getCorrectedIndex ( from , offset )
total = # songwheel.songs ;
2021-08-12 22:34:38 +02:00
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
2021-07-30 20:18:03 +02:00
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 ;
2021-07-30 16:37:01 +02:00
function getJacketImage ( song )
2021-07-31 19:36:47 +02:00
if not jacketCache [ song.id ] or jacketCache [ song.id ] == defaultJacketImage then
2021-08-13 22:36:21 +02:00
jacketCache [ song.id ] = gfx.LoadImageJob ( song.difficulties [
math.min ( selectedDifficulty , # song.difficulties )
] . jacketPath , defaultJacketImage , 500 , 500 ) ;
2021-07-25 20:10:06 +02:00
end
2021-07-30 16:37:01 +02:00
return jacketCache [ song.id ] ;
2021-07-25 20:10:06 +02:00
end
2021-07-31 18:43:17 +02:00
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
2021-08-16 16:29:21 +02:00
function drawLaserAnim ( )
2021-11-22 22:25:38 +01:00
gfx.Save ( ) ;
2021-08-16 16:29:21 +02:00
gfx.BeginPath ( )
2021-11-22 22:25:38 +01:00
2021-08-16 16:29:21 +02:00
gfx.Scissor ( 0 , transitionLaserY , desw , 100 ) ;
2021-11-22 22:25:38 +01:00
2021-08-16 16:29:21 +02:00
gfx.ImageRect ( 0 , 0 , desw , desh , laserAnimBaseImage , 1 , 0 )
2021-11-22 22:25:38 +01:00
gfx.Restore ( ) ;
2021-08-16 16:29:21 +02:00
end
2021-08-02 19:55:17 +02:00
function drawBackground ( deltaTime )
2021-08-21 13:52:40 +02:00
Background.draw ( deltaTime )
2021-11-20 19:12:12 +01:00
2021-07-31 20:36:05 +02:00
local song = songwheel.songs [ selectedIndex ] ;
2021-08-12 11:52:37 +02:00
local diff = song and song.difficulties [ selectedDifficulty ] or false ;
2021-08-06 20:04:34 +02:00
2021-11-20 19:34:15 +01:00
if ( not isFilterWheelActive and transitionLeaveReappearTimer == 0 ) then
2021-11-20 19:12:12 +01:00
-- If the score for song exists
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 ( ) ;
end
2021-08-01 20:00:45 +02:00
end
2021-08-11 20:00:35 +02:00
2021-11-20 19:12:12 +01:00
gfx.BeginPath ( ) ;
2021-08-01 20:00:45 +02:00
gfx.ImageRect ( 0 , 0 , desw , desh , dataPanelImage , 1 , 0 )
2021-08-16 16:29:21 +02:00
drawLaserAnim ( )
2021-08-11 20:00:35 +02:00
2021-11-20 19:34:15 +01:00
if song and diff and ( not isFilterWheelActive and transitionLeaveReappearTimer == 0 ) then
2021-08-01 20:00:45 +02:00
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 )
2021-07-31 20:36:05 +02:00
end
2021-08-02 19:55:17 +02:00
2021-07-25 20:10:06 +02:00
end
2021-07-30 16:37:01 +02:00
function drawSong ( song , y )
2021-07-31 20:36:05 +02:00
if ( not song ) then return end ;
2021-07-30 16:37:01 +02:00
local songX = desw / 2 + 28
2021-08-12 21:47:16 +02:00
local selectedSongDifficulty = song.difficulties [ math.min ( selectedDifficulty , # song.difficulties ) ] -- Limit selecting difficulty that is above the number that the song has
2021-07-31 18:43:17 +02:00
if not selectedSongDifficulty then
return ;
end
local bestScore ;
if selectedSongDifficulty.scores then
bestScore = selectedSongDifficulty.scores [ 1 ] ;
end
2021-07-25 20:10:06 +02:00
2021-07-30 16:37:01 +02:00
-- Draw the bg for the song plate
gfx.BeginPath ( )
2021-07-30 16:42:01 +02:00
gfx.ImageRect ( songX , y , 515 , 172 , songPlateBg , 1 , 0 )
2021-07-30 16:37:01 +02:00
-- Draw jacket
local jacketImage = getJacketImage ( song ) ;
gfx.BeginPath ( )
2021-07-30 18:40:49 +02:00
gfx.ImageRect ( songX + 4 , y + 4 , 163 , 163 , jacketImage or defaultJacketImage , 1 , 0 )
2021-07-25 20:10:06 +02:00
2021-07-30 16:37:01 +02:00
-- Draw the overlay for the song plate (that bottom black bar)
gfx.BeginPath ( )
2021-07-30 16:42:01 +02:00
gfx.ImageRect ( songX , y , 515 , 172 , songPlateBottomBarOverlayImage , 1 , 0 )
2021-07-30 16:37:01 +02:00
-- Draw the difficulty notch background
2021-07-25 20:10:06 +02:00
gfx.BeginPath ( )
2021-08-07 20:35:00 +02:00
local diffIndex = GetDisplayDifficulty ( selectedSongDifficulty.jacketPath , selectedSongDifficulty.difficulty )
gfx.ImageRect ( songX , y + 95 , 83 , 74 , difficultyLabelImages [ diffIndex ] , 1 , 0 )
2021-07-25 20:10:06 +02:00
2021-07-30 16:37:01 +02:00
-- Draw the difficulty level number
gfx.BeginPath ( )
2021-12-02 03:41:12 +01:00
Numbers.draw_number ( songX + 30 , y + 125 , 1.0 , selectedSongDifficulty.level , 2 , difficultyNumbers , false , 0.65 , 1 )
2021-07-30 18:27:43 +02:00
2021-07-30 22:10:04 +02:00
-- Draw song title
gfx.FontSize ( 24 )
gfx.TextAlign ( gfx.TEXT_ALIGN_LEFT + gfx.TEXT_ALIGN_MIDDLE )
gfx.Text ( song.title , songX + 90 , y + 155 ) ;
2021-07-30 18:27:43 +02:00
-- Draw score badge
local badgeImage = badgeImages [ 1 ] ;
2021-08-12 18:08:27 +02:00
if selectedSongDifficulty.topBadge then
badgeImage = badgeImages [ selectedSongDifficulty.topBadge + 1 ] ;
2021-07-30 18:27:43 +02:00
end
2021-08-26 15:31:28 +02:00
local badgeAlpha = 1 ;
if ( selectedSongDifficulty.topBadge >= 3 ) then
badgeAlpha = transitionFlashAlpha ; -- If hard clear or above, flash the badge
end
2021-07-30 18:27:43 +02:00
gfx.BeginPath ( )
2021-08-26 15:31:28 +02:00
gfx.ImageRect ( songX + 282 , y + 44 , 79 , 69 , badgeImage , badgeAlpha , 0 )
2021-07-31 18:43:17 +02:00
-- Draw grade
local gradeImage = gradeImages.none ;
2021-08-26 15:31:28 +02:00
local gradeAlpha = 1 ;
2021-07-31 18:43:17 +02:00
if bestScore then
gradeImage = getGradeImageForScore ( bestScore.score )
2021-08-26 15:31:28 +02:00
if ( bestScore.score >= gradeCutoffs.S ) then
gradeAlpha = transitionFlashAlpha ; -- If S, flash the badge
end
2021-07-31 18:43:17 +02:00
end
gfx.BeginPath ( ) ;
2021-08-26 15:31:28 +02:00
gfx.ImageRect ( songX + 391 , y + 47 , 60 , 60 , gradeImage , gradeAlpha , 0 ) ;
2021-07-31 18:43:17 +02:00
2021-08-16 15:50:53 +02:00
-- 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
2021-07-25 20:10:06 +02:00
end
2021-07-30 16:37:01 +02:00
function drawSongList ( )
2021-11-20 19:12:12 +01:00
gfx.GlobalAlpha ( 1 - transitionLeaveScale ) ;
2021-07-30 21:34:36 +02:00
local numOfSongsAround = 7 ; -- How many songs should be up and how many should be down of the selected one
2021-11-20 19:36:00 +01:00
local yOffset = transitionScrollOffsetY ;
2021-07-30 20:07:04 +02:00
local i = 1 ;
while ( i <= numOfSongsAround ) do
2021-07-30 20:18:03 +02:00
local songIndex = getCorrectedIndex ( selectedIndex , - i )
2021-08-12 16:55:10 +02:00
drawSong ( songwheel.songs [ songIndex ] , desh / 2 - songPlateHeight / 2 - songPlateHeight * i + yOffset )
2021-07-30 20:07:04 +02:00
i = i + 1 ;
end ;
-- Draw the selected song
2021-08-12 16:55:10 +02:00
drawSong ( songwheel.songs [ selectedIndex ] , desh / 2 - songPlateHeight / 2 + yOffset )
2021-07-30 20:07:04 +02:00
i = 1 ;
while ( i <= numOfSongsAround ) do
2021-07-30 20:18:03 +02:00
local songIndex = getCorrectedIndex ( selectedIndex , i )
2021-08-12 16:55:10 +02:00
drawSong ( songwheel.songs [ songIndex ] , desh / 2 - songPlateHeight / 2 + songPlateHeight * i + yOffset )
2021-07-30 20:07:04 +02:00
i = i + 1 ;
end ;
2021-11-20 19:12:12 +01:00
gfx.GlobalAlpha ( 1 ) ;
2021-07-25 20:10:06 +02:00
end
2021-07-31 20:36:05 +02:00
function drawData ( ) -- Draws the song data on the left panel
2021-11-20 19:12:12 +01:00
2021-11-20 19:34:15 +01:00
if isFilterWheelActive or transitionLeaveReappearTimer ~= 0 then return false end ;
2021-11-20 19:12:12 +01:00
2021-07-31 20:36:05 +02:00
local song = songwheel.songs [ selectedIndex ] ;
2021-08-12 11:52:37 +02:00
local diff = song and song.difficulties [ selectedDifficulty ] or false ;
local bestScore = diff and diff.scores [ 1 ] ;
if not song then return false end
2021-07-31 20:36:05 +02:00
local jacketImage = getJacketImage ( song ) ;
gfx.BeginPath ( )
gfx.ImageRect ( 96 , 324 , 348 , 348 , jacketImage or defaultJacketImage , 1 , 0 )
2021-08-16 15:58:28 +02:00
if ( top50diffs [ diff.id ] ) then
gfx.BeginPath ( )
gfx.ImageRect ( 96 , 529 , 410 * 0.85 , 168 * 0.85 , top50JacketOverlayImage , 1 , 0 )
end
2021-07-31 20:36:05 +02:00
2021-07-31 22:14:34 +02:00
gfx.Save ( )
2021-08-26 15:39:16 +02:00
-- Draw best score
gfx.BeginPath ( )
2021-08-26 15:42:50 +02:00
local scoreNumber = 0 ;
2021-07-31 20:36:05 +02:00
if bestScore then
2021-08-26 15:42:50 +02:00
scoreNumber = bestScore.score
2021-08-26 15:39:16 +02:00
end
2021-07-31 20:36:05 +02:00
2021-12-02 03:41:12 +01:00
Numbers.draw_number ( 100 , 793 , 1.0 , math.floor ( scoreNumber / 10000 ) , 4 , scoreNumbers , true , 0.3 , 1.12 )
Numbers.draw_number ( 253 , 798 , 1.0 , scoreNumber , 4 , scoreNumbers , true , 0.22 , 1.12 )
2021-08-26 15:42:50 +02:00
2021-08-26 15:39:16 +02:00
-- Draw grade
local gradeImage = gradeImages.none ;
local gradeAlpha = transitionAfterscrollGradeAlpha ;
if bestScore then
gradeImage = getGradeImageForScore ( bestScore.score )
2021-08-26 15:36:47 +02:00
2021-08-26 15:39:16 +02:00
if ( transitionAfterscrollGradeAlpha == 1 and bestScore.score >= gradeCutoffs.S ) then
gradeAlpha = transitionFlashAlpha ; -- If S, flash the badge
2021-07-31 20:36:05 +02:00
end
2021-08-26 15:39:16 +02:00
end
2021-07-31 20:36:05 +02:00
2021-08-26 15:39:16 +02:00
gfx.BeginPath ( ) ;
gfx.ImageRect ( 360 , 773 , 45 , 45 , gradeImage , gradeAlpha , 0 ) ;
2021-08-26 15:36:47 +02:00
2021-08-26 15:39:16 +02:00
-- Draw badge
badgeImage = badgeImages [ diff.topBadge + 1 ] ;
2021-08-26 15:36:47 +02:00
2021-08-26 15:39:16 +02:00
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
2021-07-31 20:36:05 +02:00
end
2021-08-26 15:39:16 +02:00
gfx.BeginPath ( )
gfx.ImageRect ( 425 , 724 , 93 / 1.1 , 81 / 1.1 , badgeImage , badgeAlpha , 0 )
2021-07-31 22:14:34 +02:00
gfx.Restore ( )
2021-07-31 20:36:05 +02:00
-- Draw BPM
2021-07-31 22:14:34 +02:00
gfx.BeginPath ( ) ;
2021-07-31 20:36:05 +02:00
gfx.FontSize ( 24 )
gfx.TextAlign ( gfx.TEXT_ALIGN_LEFT + gfx.TEXT_ALIGN_MIDDLE )
gfx.Save ( )
gfx.LoadSkinFont ( ' Digital-Serial-Bold.ttf ' )
2021-08-01 18:08:52 +02:00
gfx.GlobalAlpha ( transitionAfterscrollDataOverlayAlpha ) -- TODO: split this out
2021-07-31 20:36:05 +02:00
gfx.Text ( song.bpm , 85 , 920 ) ;
gfx.Restore ( )
-- Draw song title
gfx.FontSize ( 28 )
2021-08-01 18:08:52 +02:00
gfx.GlobalAlpha ( transitionAfterscrollTextSongTitle ) ;
gfx.Text ( song.title , 30 + ( 1 - transitionAfterscrollTextSongTitle ) * 20 , 955 ) ;
2021-07-31 20:36:05 +02:00
-- Draw artist
2021-08-01 18:08:52 +02:00
gfx.GlobalAlpha ( transitionAfterscrollTextSongArtist ) ;
2021-08-06 20:06:35 +02:00
gfx.Text ( song.artist , 30 + ( 1 - transitionAfterscrollTextSongArtist ) * 30 , 997 ) ;
2021-08-01 18:08:52 +02:00
gfx.GlobalAlpha ( 1 ) ;
2021-07-31 22:53:05 +02:00
-- Draw difficulties
local DIFF_X_START = 98.5
local DIFF_GAP = 114.8 ;
2021-07-31 23:00:32 +02:00
gfx.GlobalAlpha ( transitionAfterscrollDifficultiesAlpha ) ;
2021-08-12 15:53:29 +02:00
for i , diff in ipairs ( song.difficulties ) do
2021-07-31 22:53:05 +02:00
gfx.BeginPath ( )
2021-08-12 15:53:29 +02:00
local index = diff.difficulty + 1
if i == selectedDifficulty then
2021-07-31 22:53:05 +02:00
gfx.ImageRect ( DIFF_X_START + ( index - 1 ) * DIFF_GAP - ( 163 * 0.8 ) / 2 , 1028 , 163 * 0.8 , 163 * 0.8 , diffCursorImage , 1 , 0 )
end
2021-12-02 03:41:12 +01:00
Numbers.draw_number ( 85 + ( index - 1 ) * DIFF_GAP , 1085 , 1.0 , diff.level , 2 , difficultyNumbers , false , 0.8 , 1 )
2021-07-31 22:53:05 +02:00
2021-08-07 20:35:00 +02:00
local diffLabelImage = difficultyLabelUnderImages [
GetDisplayDifficulty ( diff.jacketPath , diff.difficulty )
] ;
2021-07-31 22:53:05 +02:00
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
2021-07-31 23:00:32 +02:00
gfx.GlobalAlpha ( 1 ) ;
2021-10-25 21:06:06 +02:00
2021-08-01 20:07:48 +02:00
2021-10-25 21:06:06 +02:00
-- Scoreboard
2021-08-01 20:07:48 +02:00
2021-12-14 19:08:46 +01:00
drawLocalLeaderboard ( diff )
drawIrLeaderboard ( )
gfx.FontSize ( 22 )
2021-12-16 16:52:03 +01:00
gfx.TextAlign ( gfx.TEXT_ALIGN_LEFT + gfx.TEXT_ALIGN_MIDDLE )
2021-12-14 19:08:46 +01:00
gfx.GlobalAlpha ( transitionAfterscrollDataOverlayAlpha ) ;
gfx.Text ( diff.effector , 270 , 1180 ) ; -- effected by
gfx.Text ( diff.illustrator , 270 , 1210 ) ; -- illustrated by
gfx.GlobalAlpha ( 1 ) ;
end
function drawLocalLeaderboard ( diff )
2021-10-24 21:51:41 +02:00
gfx.LoadSkinFont ( ' Digital-Serial-Bold.ttf ' )
2021-12-14 19:08:46 +01:00
gfx.FontSize ( 26 )
2021-10-24 21:51:41 +02:00
2021-10-25 21:06:06 +02:00
local scoreBoardX = 75 ;
local scoreBoardY = 1250 ;
2021-08-01 20:07:48 +02:00
2021-10-25 21:06:06 +02:00
local sbBarWidth = 336 * 1.2 ;
local sbBarHeight = 33 ;
2021-10-24 21:51:41 +02:00
2021-12-14 19:08:46 +01:00
local sbBarContentLeftX = scoreBoardX + 80 ;
2021-10-25 21:06:06 +02:00
local sbBarContentRightX = scoreBoardX + sbBarWidth / 2 + 30 ;
2021-10-24 21:51:41 +02:00
2021-10-25 21:06:06 +02:00
-- Draw the header
gfx.BeginPath ( ) ;
gfx.ImageRect ( scoreBoardX , scoreBoardY , sbBarWidth , sbBarHeight , scoreBoardBarBgImage , 1 , 0 ) ;
2021-10-24 21:51:41 +02:00
2021-10-25 21:06:06 +02:00
gfx.BeginPath ( ) ;
gfx.ImageRect ( 205 , 1252.5 , 800 * 0.045 , 600 * 0.045 , crownImage , 1 , 0 ) ;
2021-10-24 21:51:41 +02:00
2021-10-25 21:06:06 +02:00
gfx.TextAlign ( gfx.TEXT_ALIGN_LEFT + gfx.TEXT_ALIGN_MIDDLE )
gfx.BeginPath ( ) ;
2021-12-14 19:08:46 +01:00
gfx.Text ( " LOCAL TOP " , sbBarContentRightX , scoreBoardY + sbBarHeight / 2 ) ;
2021-10-24 21:51:41 +02:00
2021-10-25 21:06:06 +02:00
for i = 1 , 5 , 1 do
gfx.BeginPath ( ) ;
gfx.ImageRect ( scoreBoardX , scoreBoardY + i * sbBarHeight , sbBarWidth , sbBarHeight , scoreBoardBarBgImage , 1 , 0 ) ;
2021-12-14 19:08:46 +01:00
gfx.TextAlign ( gfx.TEXT_ALIGN_LEFT + gfx.TEXT_ALIGN_MIDDLE )
2021-10-25 21:06:06 +02:00
gfx.BeginPath ( ) ;
gfx.Text ( game.GetSkinSetting ( " username " ) , sbBarContentLeftX , scoreBoardY + sbBarHeight / 2 + i * sbBarHeight ) ;
gfx.BeginPath ( ) ;
2021-10-29 16:36:35 +02:00
gfx.Text ( ( diff.scores [ i ] ) and diff.scores [ i ] . score or " - - - - - - - - " , sbBarContentRightX , scoreBoardY + sbBarHeight / 2 + i * sbBarHeight ) ;
2021-10-25 21:06:06 +02:00
end
2021-12-14 19:08:46 +01:00
end
2021-10-24 21:51:41 +02:00
2021-12-14 19:08:46 +01:00
function drawIrLeaderboard ( )
2021-12-16 18:29:04 +01:00
if not IRData.Active then
return ;
end
2021-12-14 19:08:46 +01:00
gfx.LoadSkinFont ( ' Digital-Serial-Bold.ttf ' )
gfx.FontSize ( 26 )
2021-12-16 16:52:03 +01:00
2021-12-14 19:08:46 +01:00
local scoreBoardX = 75 ;
local scoreBoardY = 1500 ;
2021-12-16 16:52:03 +01:00
2021-12-14 19:08:46 +01:00
local sbBarWidth = 336 * 1.2 ;
local sbBarHeight = 33 ;
2021-12-16 16:52:03 +01:00
2021-12-14 19:08:46 +01:00
local sbBarContentLeftX = scoreBoardX + 80 ;
local sbBarContentRightX = scoreBoardX + sbBarWidth / 2 + 30 ;
-- Draw the header
gfx.BeginPath ( ) ;
gfx.ImageRect ( scoreBoardX , scoreBoardY , sbBarWidth , sbBarHeight , scoreBoardBarBgImage , 1 , 0 ) ;
2021-12-16 16:52:03 +01:00
gfx.TextAlign ( gfx.TEXT_ALIGN_CENTER + gfx.TEXT_ALIGN_MIDDLE )
gfx.BeginPath ( ) ;
2021-12-16 17:31:38 +01:00
if irRequestStatus == 1 or irRequestStatus == 2 then
2021-12-16 16:52:03 +01:00
gfx.Text ( " Loading ranking... " , scoreBoardX + ( sbBarWidth / 2 ) , scoreBoardY + sbBarHeight / 2 ) ;
return ;
end
if irRequestStatus == IRData.States . ChartRefused then
gfx.Text ( " This chart is blacklisted " , scoreBoardX + ( sbBarWidth / 2 ) , scoreBoardY + sbBarHeight / 2 ) ;
return ;
end
if irRequestStatus == IRData.States . NotFound then
gfx.Text ( " This chart is not tracked " , scoreBoardX + ( sbBarWidth / 2 ) , scoreBoardY + sbBarHeight / 2 ) ;
return ;
end
if # irLeaderboard == 0 then
2021-12-16 18:01:33 +01:00
gfx.Text ( " This chart has no scores " , scoreBoardX + ( sbBarWidth / 2 ) , scoreBoardY + sbBarHeight / 2 ) ;
2021-12-16 16:52:03 +01:00
return ;
end
2021-12-14 19:08:46 +01:00
gfx.TextAlign ( gfx.TEXT_ALIGN_CENTER + gfx.TEXT_ALIGN_MIDDLE )
gfx.BeginPath ( ) ;
gfx.Text ( " IR TOP " , scoreBoardX + ( sbBarWidth / 2 ) , scoreBoardY + sbBarHeight / 2 ) ;
for i = 1 , 4 , 1 do
gfx.BeginPath ( ) ;
gfx.ImageRect ( scoreBoardX , scoreBoardY + i * sbBarHeight , sbBarWidth , sbBarHeight , scoreBoardBarBgImage , 1 , 0 ) ;
2021-12-14 20:23:45 +01:00
end
2021-12-14 19:08:46 +01:00
2021-12-14 20:23:45 +01:00
-- Becuase the scores are in "random order", we have to do this
2021-12-14 22:22:38 +01:00
for index , irScore in ipairs ( irLeaderboard ) do
-- local irScore = irLeaderboard[i];
2021-12-14 20:23:45 +01:00
2021-12-14 19:08:46 +01:00
if irScore then
2021-12-16 20:49:11 +01:00
local rank = index ;
2021-12-14 19:08:46 +01:00
gfx.TextAlign ( gfx.TEXT_ALIGN_CENTER + gfx.TEXT_ALIGN_MIDDLE )
gfx.BeginPath ( ) ;
2021-12-14 20:23:45 +01:00
gfx.Text ( LEADERBOARD_PLACE_NAMES [ rank ] , sbBarContentLeftX - 40 , scoreBoardY + sbBarHeight / 2 + rank * sbBarHeight ) ;
2021-12-14 19:08:46 +01:00
gfx.TextAlign ( gfx.TEXT_ALIGN_LEFT + gfx.TEXT_ALIGN_MIDDLE )
gfx.BeginPath ( ) ;
2021-12-14 20:23:45 +01:00
gfx.Text ( string.upper ( irScore.username ) , sbBarContentLeftX , scoreBoardY + sbBarHeight / 2 + rank * sbBarHeight ) ;
2021-12-14 19:08:46 +01:00
gfx.BeginPath ( ) ;
2021-12-14 20:23:45 +01:00
gfx.Text ( string.format ( " %d " , irScore.score ) , sbBarContentRightX , scoreBoardY + sbBarHeight / 2 + rank * sbBarHeight ) ;
2021-10-24 21:51:41 +02:00
2021-12-14 19:08:46 +01:00
local badgeImage = badgeImages [ irScore.lamp + 1 ] ;
gfx.BeginPath ( )
2021-12-14 20:23:45 +01:00
gfx.ImageRect ( scoreBoardX + sbBarWidth - 50 , scoreBoardY + sbBarHeight / 2 + rank * sbBarHeight - 12.5 , 31.6 , 27.6 , badgeImage , 1 , 0 )
2021-12-14 19:08:46 +01:00
end
end
2021-07-31 20:36:05 +02:00
end
2021-08-13 17:35:26 +02:00
function drawFilterInfo ( deltatime )
2021-11-20 19:27:28 +01:00
gfx.LoadSkinFont ( ' NotoSans-Regular.ttf ' )
2021-11-20 19:34:15 +01:00
2021-12-18 21:39:47 +01:00
if ( songwheel.searchInputActive ) then
return ;
end
2021-08-13 17:35:26 +02:00
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 ' )
2021-08-14 17:49:12 +02:00
local sortOptionLabel = game.GetSkinSetting ( ' _songWheelActiveSortOptionLabel ' )
2021-08-13 17:35:26 +02:00
gfx.FontSize ( 24 )
gfx.TextAlign ( gfx.TEXT_ALIGN_CENTER + gfx.TEXT_ALIGN_MIDDLE )
2021-08-14 17:49:12 +02:00
2021-08-13 17:35:26 +02:00
gfx.BeginPath ( )
2021-08-13 22:36:21 +02:00
gfx.Text ( folderLabel or ' ' , 167 , 131 ) ;
2021-08-14 17:49:12 +02:00
2021-08-13 17:35:26 +02:00
gfx.BeginPath ( )
2021-08-13 22:36:21 +02:00
gfx.Text ( subFolderLabel or ' ' , 195 , 166 ) ;
2021-08-14 17:49:12 +02:00
gfx.BeginPath ( )
gfx.ImageRect ( desw - 310 - 5 , 108 , 310 , 75 , sortInfoBgImage , 1 , 0 )
gfx.BeginPath ( )
2021-08-14 17:52:04 +02:00
gfx.Text ( sortOptionLabel or ' ' , desw - 150 , 130 ) ;
2021-08-13 17:35:26 +02:00
end
2021-11-20 19:27:28 +01:00
function drawCursor ( )
if isFilterWheelActive or transitionLeaveScale ~= 0 then return false end
gfx.BeginPath ( )
local cursorImageIndex = game.GetSkinSetting ( ' _gaugeType ' )
local cursorImage = cursorImages [ cursorImageIndex or 1 ] ;
gfx.ImageRect ( desw / 2 - 14 , desh / 2 - 213 / 2 , 555 , 213 , cursorImage , 1 , 0 )
end
2021-08-05 22:01:17 +02:00
function drawSearch ( )
if ( not songwheel.searchInputActive ) then
return ;
end
2021-12-18 21:39:47 +01:00
2021-08-05 22:01:17 +02:00
gfx.BeginPath ( ) ;
local tw , th = gfx.ImageSize ( searchBgImage )
2021-12-18 21:39:47 +01:00
local xPos = desw - tw / 2 ;
local yPos = 90 ;
2021-08-05 22:01:17 +02:00
2021-12-18 21:39:47 +01:00
gfx.ImageRect ( xPos , yPos , tw / 2 , th / 2 , searchBgImage , 1 , 0 )
gfx.FontSize ( 32 ) ;
gfx.LoadSkinFont ( ' Digital-Serial-Bold.ttf ' )
gfx.TextAlign ( gfx.TEXT_ALIGN_LEFT + gfx.TEXT_ALIGN_MIDDLE )
gfx.Text ( songwheel.searchText , xPos + 100 , yPos + 52 ) ;
2021-08-05 22:01:17 +02:00
end
2021-12-16 18:01:33 +01:00
function refreshIrLeaderboard ( deltaTime )
2021-12-16 18:29:04 +01:00
if not IRData.Active then
return ;
end
2021-12-16 20:49:11 +01:00
2021-12-16 17:31:38 +01:00
if irRequestStatus ~= 1 then -- Only continue if the leaderboard is requesteded, but not loading or loaded.
2021-12-14 19:08:46 +01:00
return
end
irLeaderboard = { }
local song = songwheel.songs [ selectedIndex ] ;
local diff = song and song.difficulties [ selectedDifficulty ] or false ;
if ( not diff ) then
return ;
end
2021-12-16 18:01:33 +01:00
if ( irLeaderboardsCache [ diff.hash ] ) then
irLeaderboard = irLeaderboardsCache [ diff.hash ] ;
irRequestStatus = 20 ;
return ;
end
if ( irRequestTimeout > 0 ) then
irRequestTimeout = irRequestTimeout - deltaTime
return ;
end
2021-12-16 17:31:38 +01:00
irRequestStatus = 2 ; -- Loading
-- onIrLeaderboardFetched({
-- statusCode = 20,
-- body = {}
-- })
2021-12-14 19:08:46 +01:00
IR.Leaderboard ( diff.hash , ' best ' , 4 , onIrLeaderboardFetched )
end
function dump ( o )
if type ( o ) == ' table ' then
local s = ' { '
for k , v in pairs ( o ) do
if type ( k ) ~= ' number ' then k = ' " ' .. k .. ' " ' end
s = s .. ' [ ' .. k .. ' ] = ' .. dump ( v ) .. ' , '
end
return s .. ' } '
else
return tostring ( o )
end
end
function onIrLeaderboardFetched ( res )
2021-12-16 16:52:03 +01:00
irRequestStatus = res.statusCode ;
2021-12-16 20:49:11 +01:00
local song = songwheel.songs [ selectedIndex ] ;
local diff = song and song.difficulties [ selectedDifficulty ] or false ;
game.Log ( diff.hash , game.LOGGER_ERROR )
2021-12-14 19:08:46 +01:00
if res.statusCode == IRData.States . Success then
2021-12-16 20:49:11 +01:00
game.Log ( ' Raw IR reposonse: ' .. dump ( res.body ) , game.LOGGER_ERROR )
local tempIrLB = res.body ;
2021-12-14 22:22:38 +01:00
2021-12-16 20:49:11 +01:00
table.sort ( tempIrLB , function ( a , b )
-- game.Log(a.score .. ' ?? ' .. b.score, game.LOGGER_ERROR)
return a.score > b.score
end )
-- for i, tempScore in ipairs(tempIrLeaderboard) do
-- irLeaderboard[tempScore.ranking] = tempScore
-- end
2021-12-14 22:22:38 +01:00
2021-12-16 20:49:11 +01:00
irLeaderboard = tempIrLB ;
2021-12-16 21:31:06 +01:00
irLeaderboardsCache [ diff.hash ] = irLeaderboard ;
2021-12-16 18:01:33 +01:00
2021-12-14 19:08:46 +01:00
game.Log ( dump ( irLeaderboard ) , game.LOGGER_ERROR )
else
game.Log ( " IR error " .. res.statusCode , game.LOGGER_ERROR )
end
end
2021-07-30 21:34:36 +02:00
function tickTransitions ( deltaTime )
if transitionScrollScale < 1 then
transitionScrollScale = transitionScrollScale + deltaTime / 0.1 -- transition should last for that time in seconds
else
transitionScrollScale = 1
end
2021-07-31 22:14:34 +02:00
if transitionAfterscrollScale < 1 then
if transitionScrollScale == 1 then
-- Only start the after scroll transition when the scroll transition is finished
2021-08-01 18:08:52 +02:00
transitionAfterscrollScale = transitionAfterscrollScale + deltaTime / 15
2021-07-31 22:14:34 +02:00
end
else
transitionAfterscrollScale = 1 ;
end
2021-07-30 21:34:36 +02:00
if scrollingUp then
transitionScrollOffsetY = Easing.inQuad ( 1 - transitionScrollScale ) * songPlateHeight ;
else
transitionScrollOffsetY = Easing.inQuad ( 1 - transitionScrollScale ) * - songPlateHeight ;
end
2021-07-31 22:14:34 +02:00
2021-08-01 18:08:52 +02:00
if transitionAfterscrollScale < 0.02 then
transitionAfterscrollDataOverlayAlpha = math.min ( 1 , transitionAfterscrollScale / 0.02 )
2021-07-31 22:14:34 +02:00
else
transitionAfterscrollDataOverlayAlpha = 1 ;
end
-- Grade alpha
2021-08-01 18:08:52 +02:00
if transitionAfterscrollScale >= 0.03 and transitionAfterscrollScale < 0.033 then
2021-07-31 22:14:34 +02:00
transitionAfterscrollGradeAlpha = 0.5 ;
2021-08-01 18:08:52 +02:00
elseif transitionAfterscrollScale >= 0.04 then
2021-07-31 22:14:34 +02:00
transitionAfterscrollGradeAlpha = 1 ;
else
transitionAfterscrollGradeAlpha = 0 ;
end
-- Badge alpha
2021-08-01 18:08:52 +02:00
if transitionAfterscrollScale >= 0.032 and transitionAfterscrollScale < 0.035 then
2021-07-31 22:14:34 +02:00
transitionAfterscrollBadgeAlpha = 0.5 ;
2021-08-01 18:08:52 +02:00
elseif transitionAfterscrollScale >= 0.042 then
2021-07-31 22:14:34 +02:00
transitionAfterscrollBadgeAlpha = 1 ;
else
transitionAfterscrollBadgeAlpha = 0 ;
end
2021-08-01 18:08:52 +02:00
-- Song title alpha and pos
2021-08-06 20:06:35 +02:00
if transitionAfterscrollScale < 0.025 then
transitionAfterscrollTextSongTitle = Easing.outQuad ( math.min ( 1 , ( transitionAfterscrollScale ) / 0.025 ) ) ;
2021-08-01 18:08:52 +02:00
else
transitionAfterscrollTextSongTitle = 1
end
-- Song artist alpha and pos
2021-08-06 20:06:35 +02:00
if transitionAfterscrollScale < 0.025 then
transitionAfterscrollTextSongArtist = Easing.outQuad ( math.min ( 1 , ( transitionAfterscrollScale ) / 0.025 ) ) ;
2021-08-01 18:08:52 +02:00
else
transitionAfterscrollTextSongArtist = 1
end
2021-07-31 23:00:32 +02:00
-- Difficulties alpha
2021-08-01 18:08:52 +02:00
if transitionAfterscrollScale < 0.025 then
transitionAfterscrollDifficultiesAlpha = math.min ( 1 , transitionAfterscrollScale / 0.025 )
2021-07-31 23:00:32 +02:00
else
transitionAfterscrollDifficultiesAlpha = 1 ;
end
2021-08-01 18:08:52 +02:00
2021-08-26 19:50:33 +02:00
-- Jacket bg animation
if transitionJacketBgScrollScale < 1 then
transitionJacketBgScrollScale = transitionJacketBgScrollScale + deltaTime / 20 -- transition should last for that time in seconds
2021-08-01 18:08:52 +02:00
else
2021-08-26 19:50:33 +02:00
transitionJacketBgScrollScale = 0
2021-08-01 18:08:52 +02:00
end
2021-08-12 16:55:10 +02:00
2021-08-26 19:50:33 +02:00
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 ;
2021-08-16 16:29:21 +02:00
-- Laser anim
if transitionLaserScale < 1 then
2021-08-18 18:41:33 +02:00
transitionLaserScale = transitionLaserScale + deltaTime / 2 -- transition should last for that time in seconds
2021-08-16 16:29:21 +02:00
else
transitionLaserScale = 0
end
transitionLaserY = desh - math.min ( transitionLaserScale * 2 * desh , desh ) ;
2021-08-26 15:31:28 +02:00
-- Flash transition
if transitionFlashScale < 1 then
local songBpm = 120 ;
2021-08-26 19:04:20 +02:00
if ( songwheel.songs [ selectedIndex ] and game.GetSkinSetting ( ' animations_affectWithBPM ' ) ) then
2021-08-26 15:31:28 +02:00
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
2021-08-27 21:31:46 +02:00
-- 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
2021-08-26 15:31:28 +02:00
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
2021-08-12 16:55:10 +02:00
-- Leave transition
2021-11-20 19:12:12 +01:00
if ( isFilterWheelActive ) then
2021-08-12 17:18:35 +02:00
if transitionLeaveScale < 1 then
2021-11-20 19:12:12 +01:00
transitionLeaveScale = transitionLeaveScale + deltaTime / TRANSITION_LEAVE_DURATION -- transition should last for that time in seconds
2021-08-12 17:18:35 +02:00
else
transitionLeaveScale = 1
end
2021-11-20 19:12:12 +01:00
transitionLeaveReappearTimer = 1 ;
transitionAfterscrollScale = 0 ; -- Keep songwheel in the "afterscroll" state while the filterwheel is active
2021-11-20 19:27:28 +01:00
transitionJacketBgScrollScale = 0 ; -- Same thing here, just with the jacket bg
2021-11-20 19:12:12 +01:00
else
2021-11-20 19:34:15 +01:00
if ( transitionLeaveReappearTimer ~= 0 ) then
transitionAfterscrollScale = 0 ; -- Keep songwheel in the "afterscroll" state while we're waiting on filter wheel to fade out
transitionJacketBgScrollScale = 0 ; -- Same thing here, just with the jacket bg
2021-11-20 19:12:12 +01:00
end
2021-11-20 19:27:28 +01:00
transitionLeaveReappearTimer = transitionLeaveReappearTimer - deltaTime / ( TRANSITION_LEAVE_DURATION + 0.05 ) -- 0.05s is a few frames between the completetion of the fade out and songs reappearing in the AC
2021-08-12 16:55:10 +02:00
2021-11-20 19:12:12 +01:00
if ( transitionLeaveReappearTimer <= 0 ) then
transitionLeaveScale = 0 ;
transitionLeaveReappearTimer = 0 ;
end
end
2021-07-30 21:34:36 +02:00
end
2021-11-22 20:23:34 +01:00
draw_songwheel = function ( x , y , w , h , deltaTime )
2021-11-22 22:25:38 +01:00
2021-11-22 20:23:34 +01:00
gfx.Translate ( x , y ) ;
gfx.Scale ( w / 1080 , h / 1920 ) ;
2021-11-22 22:25:38 +01:00
gfx.Scissor ( 0 , 0 , 1080 , 1920 ) ;
2021-07-25 20:10:06 +02:00
2021-08-02 19:55:17 +02:00
drawBackground ( deltaTime ) ;
2021-07-25 20:10:06 +02:00
2021-07-30 16:37:01 +02:00
drawSongList ( )
2021-07-25 20:10:06 +02:00
2021-11-20 19:12:12 +01:00
isFilterWheelActive = game.GetSkinSetting ( ' _songWheelOverlayActive ' ) == 1 ;
2021-07-31 20:36:05 +02:00
drawData ( )
2021-11-20 19:27:28 +01:00
drawCursor ( )
2021-07-31 20:36:05 +02:00
2021-08-13 17:35:26 +02:00
drawFilterInfo ( deltaTime )
2021-08-05 22:01:17 +02:00
drawSearch ( ) ;
2021-07-25 20:10:06 +02:00
gfx.BeginPath ( ) ;
2021-07-30 16:37:01 +02:00
gfx.FontSize ( 18 )
gfx.TextAlign ( gfx.TEXT_ALIGN_LEFT + gfx.TEXT_ALIGN_TOP )
2021-07-30 21:34:36 +02:00
local debugScrollingUp = " FALSE "
if scrollingUp then debugScrollingUp = " TRUE " end ;
2022-02-17 18:06:25 +01:00
if game.GetSkinSetting ( ' debug_showInformation ' ) then
gfx.Text ( ' S_I: ' .. selectedIndex .. ' // S_D: ' .. selectedDifficulty .. ' // S_UP: ' .. debugScrollingUp .. ' // AC_TS: ' .. transitionAfterscrollScale .. ' // L_TS: ' .. transitionLeaveScale .. ' // IR_CODE: ' .. irRequestStatus .. ' // IR_T: ' .. irRequestTimeout , 8 , 8 ) ;
end
2021-11-22 20:23:34 +01:00
gfx.ResetTransform ( ) ;
end
render = function ( deltaTime )
tickTransitions ( deltaTime ) ;
game.SetSkinSetting ( ' _currentScreen ' , ' songwheel ' )
common.stopMusic ( ) ;
-- detect resolution change
local resx , resy = game.GetResolution ( ) ;
if resx ~= resX or resy ~= resY then
resolutionChange ( resx , resy )
end
gfx.BeginPath ( )
bgImageWidth , bgImageHeight = gfx.ImageSize ( backgroundImage )
gfx.Rect ( 0 , 0 , resX , resY )
gfx.FillPaint ( gfx.ImagePattern ( 0 , 0 , bgImageWidth , bgImageHeight , 0 , backgroundImage , 0.2 ) )
gfx.Fill ( )
draw_songwheel ( ( resX - fullX ) / 2 , 0 , fullX , fullY , deltaTime ) ;
2021-12-14 19:08:46 +01:00
2021-12-16 18:01:33 +01:00
refreshIrLeaderboard ( deltaTime ) ;
2021-07-25 20:10:06 +02:00
end
2021-08-12 21:21:42 +02:00
songs_changed = function ( withAll )
2021-12-16 18:17:48 +01:00
irLeaderboardsCache = { } -- Reset LB cache
2021-08-12 21:21:42 +02:00
if not withAll then return end
2021-08-27 20:18:55 +02:00
game.SetSkinSetting ( ' _songWheelScrollbarTotal ' , # songwheel.songs )
game.SetSkinSetting ( ' _songWheelScrollbarIndex ' , selectedIndex )
2021-08-12 21:21:42 +02:00
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
2021-08-16 15:50:53 +02:00
top50diffs [ diffs [ i ] . id ] = true ;
2021-08-12 21:21:42 +02:00
totalForce = totalForce + diffs [ i ] . force
end
end
game.SetSkinSetting ( ' _volforce ' , totalForce )
end
2021-07-25 20:10:06 +02:00
set_index = function ( newIndex )
2021-07-30 21:34:36 +02:00
transitionScrollScale = 0 ;
2021-07-31 22:14:34 +02:00
transitionAfterscrollScale = 0 ;
2021-08-26 19:50:33 +02:00
transitionJacketBgScrollScale = 0 ;
2021-07-30 21:34:36 +02:00
2021-08-27 20:18:55 +02:00
game.SetSkinSetting ( ' _songWheelScrollbarTotal ' , # songwheel.songs )
game.SetSkinSetting ( ' _songWheelScrollbarIndex ' , newIndex )
2021-07-30 21:34:36 +02:00
scrollingUp = false ;
if ( ( newIndex > selectedIndex and not ( newIndex == # songwheel.songs and selectedIndex == 1 ) ) or ( newIndex == 1 and selectedIndex == # songwheel.songs ) ) then
scrollingUp = true ;
end ;
2021-07-30 22:06:08 +02:00
game.PlaySample ( ' song_wheel/cursor_change.wav ' ) ;
2021-07-30 21:34:36 +02:00
2021-07-30 16:37:01 +02:00
selectedIndex = newIndex ;
2021-07-25 20:10:06 +02:00
end ;
set_diff = function ( newDiff )
2021-08-12 14:29:55 +02:00
if newDiff ~= selectedDifficulty then
2021-08-13 22:36:21 +02:00
jacketCache = { } ; -- Clear the jacket cache for the new diff jackets
2021-08-12 14:29:55 +02:00
game.PlaySample ( ' song_wheel/diff_change.wav ' ) ;
end
2021-07-30 16:37:01 +02:00
selectedDifficulty = newDiff ;
2021-12-14 20:02:25 +01:00
irLeaderboard = { }
2021-12-16 21:31:06 +01:00
irRequestStatus = 1 ;
2021-12-14 20:02:25 +01:00
irRequestTimeout = 2
2021-07-30 16:37:01 +02:00
end ;