From 900e368a918bc167e6b6966b021f22399d8f4b5c Mon Sep 17 00:00:00 2001 From: FajsiEx Date: Thu, 12 Aug 2021 17:18:35 +0200 Subject: [PATCH] + finish filterwheel leave transition & + placeholders for perm and blast cursors --- scripts/songselect/filterwheel.lua | 161 +++++++++++++------------- scripts/songselect/songwheel.lua | 38 +++--- textures/song_select/cursor_blast.png | Bin 0 -> 6605 bytes textures/song_select/cursor_perm.png | Bin 0 -> 6605 bytes 4 files changed, 97 insertions(+), 102 deletions(-) create mode 100644 textures/song_select/cursor_blast.png create mode 100644 textures/song_select/cursor_perm.png diff --git a/scripts/songselect/filterwheel.lua b/scripts/songselect/filterwheel.lua index d0118c3..a8da821 100644 --- a/scripts/songselect/filterwheel.lua +++ b/scripts/songselect/filterwheel.lua @@ -3,13 +3,14 @@ local Easing = require('common.easings'); local SongSelectHeader = require('components.headers.songSelectHeader') local Footer = require('components.footer'); -local defaultFolderBgImage = gfx.CreateSkinImage('song_select/filter_wheel/bg.png', 0) +local defaultFolderBgImage = gfx.CreateSkinImage( + 'song_select/filter_wheel/bg.png', 0) 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_exc.png", 1), -- TODO: premissive rate - gfx.CreateSkinImage("song_select/cursor_exc.png", 1), -- TODO: blastive rate + gfx.CreateSkinImage("song_select/cursor_exc.png", 1) -- TODO: blastive rate } local ITEM_HEIGHT = 172; @@ -17,27 +18,20 @@ local ITEM_HEIGHT = 172; local specialFolders = { { keys = { - 'SOUND VOLTEX BOOTH', - 'SDVX BOOTH', - 'SOUND VOLTEX I', - 'SDVX I', - 'SOUND VOLTEX 1', - 'SDVX 1' + 'SOUND VOLTEX BOOTH', 'SDVX BOOTH', 'SOUND VOLTEX I', 'SDVX I', + 'SOUND VOLTEX 1', 'SDVX 1' }, - folderBg = gfx.CreateSkinImage('song_select/filter_wheel/special_folder_bgs/Booth.png', 0) - }, - { + folderBg = gfx.CreateSkinImage( + 'song_select/filter_wheel/special_folder_bgs/Booth.png', 0) + }, { keys = { - 'SOUND VOLTEX INFINITE INFECTION', - 'SDVX INFINITE INFECTION', - 'SOUND VOLTEX II', - 'SDVX II', - 'SOUND VOLTEX 2', - 'SDVX 2' + 'SOUND VOLTEX INFINITE INFECTION', 'SDVX INFINITE INFECTION', + 'SOUND VOLTEX II', 'SDVX II', 'SOUND VOLTEX 2', 'SDVX 2' }, - folderBg = gfx.CreateSkinImage('song_select/filter_wheel/special_folder_bgs/Infinite Infection.png', 0) - }, - -- { + folderBg = gfx.CreateSkinImage( + 'song_select/filter_wheel/special_folder_bgs/Infinite Infection.png', + 0) + }, -- { -- keys = { -- 'SOUND VOLTEX GRAVITY WARS', -- 'SDVX GRAVITY WARS', @@ -50,37 +44,26 @@ local specialFolders = { -- }, { keys = { - 'SOUND VOLTEX HEAVENLY HAVEN', - 'SDVX HEAVENLY HAVEN', - 'SOUND VOLTEX IV', - 'SDVX IV', - 'SOUND VOLTEX 4', - 'SDVX 4' + 'SOUND VOLTEX HEAVENLY HAVEN', 'SDVX HEAVENLY HAVEN', + 'SOUND VOLTEX IV', 'SDVX IV', 'SOUND VOLTEX 4', 'SDVX 4' }, - folderBg = gfx.CreateSkinImage('song_select/filter_wheel/special_folder_bgs/Heavenly Haven.png', 0) - }, - { + folderBg = gfx.CreateSkinImage( + 'song_select/filter_wheel/special_folder_bgs/Heavenly Haven.png', 0) + }, { keys = { - 'SOUND VOLTEX VIVID WAVE', - 'SDVX VIVID WAVE', - 'SOUND VOLTEX V', - 'SDVX V', - 'SOUND VOLTEX 5', - 'SDVX 5' + 'SOUND VOLTEX VIVID WAVE', 'SDVX VIVID WAVE', 'SOUND VOLTEX V', + 'SDVX V', 'SOUND VOLTEX 5', 'SDVX 5' }, - folderBg = gfx.CreateSkinImage('song_select/filter_wheel/special_folder_bgs/Vivid Wave.png', 0) - }, - { + folderBg = gfx.CreateSkinImage( + 'song_select/filter_wheel/special_folder_bgs/Vivid Wave.png', 0) + }, { keys = { - 'SOUND VOLTEX EXCEED GEAR', - 'SDVX EXCEED GEAR', - 'SOUND VOLTEX VI', - 'SDVX VI', - 'SOUND VOLTEX 6', - 'SDVX 6' + 'SOUND VOLTEX EXCEED GEAR', 'SDVX EXCEED GEAR', 'SOUND VOLTEX VI', + 'SDVX VI', 'SOUND VOLTEX 6', 'SDVX 6' }, - folderBg = gfx.CreateSkinImage('song_select/filter_wheel/special_folder_bgs/Exceed Gear.png', 0) - }, + folderBg = gfx.CreateSkinImage( + 'song_select/filter_wheel/special_folder_bgs/Exceed Gear.png', 0) + } } -- AUDIO @@ -98,6 +81,7 @@ local transitionScrollScale = 0; local transitionScrollOffsetY = 0; local scrollingUp = false; +local transitionEnterReverse = false; local transitionEnterScale = 0; local transitionEnterOffsetY = 0; @@ -143,8 +127,8 @@ function getFolderData(folderLabel) local folderBgImage = defaultFolderBgImage; local isSpecial = false; - for i,specialFolder in ipairs(specialFolders) do - for i,specialFolderKey in ipairs(specialFolder.keys) do + for i, specialFolder in ipairs(specialFolders) do + for i, specialFolderKey in ipairs(specialFolder.keys) do if (specialFolderKey == labelMatcherString) then folderBgImage = specialFolder.folderBg; isSpecial = true; @@ -156,7 +140,7 @@ function getFolderData(folderLabel) type = folderType, label = folderLabel, bgImage = folderBgImage, - isSpecial = isSpecial, + isSpecial = isSpecial } end @@ -169,15 +153,15 @@ function drawFolder(label, y) -- Draw the bg gfx.BeginPath() - gfx.ImageRect(x, y, 630*0.86, 200*0.86, folderData.bgImage, 1, 0) + gfx.ImageRect(x, y, 630 * 0.86, 200 * 0.86, folderData.bgImage, 1, 0) -- Draw the folder label, but only if the folder is not special - if (not folderData.isSpecial) then + if (not folderData.isSpecial) then gfx.BeginPath(); gfx.FontSize(38) gfx.TextAlign(gfx.TEXT_ALIGN_LEFT + gfx.TEXT_ALIGN_MIDDLE) gfx.FillColor(255, 255, 255, 255); - gfx.Text(folderData.label, x+18, y+72); + gfx.Text(folderData.label, x + 18, y + 72); end end @@ -194,36 +178,35 @@ function drawFolderList() folderList = filters.level; end - yOffset = transitionEnterOffsetY + transitionScrollOffsetY + yOffset = transitionEnterOffsetY + transitionScrollOffsetY; local i = 1; while (i <= numOfItemsAround) do local index = getCorrectedIndex(selectedIndex, -i) - drawFolder(folderList[index], desh / 2 - ITEM_HEIGHT / 2 - - ITEM_HEIGHT * i + yOffset) + drawFolder(folderList[index], + desh / 2 - ITEM_HEIGHT / 2 - ITEM_HEIGHT * i + yOffset) i = i + 1; end -- Draw the selected song - drawFolder(folderList[selectedIndex], - desh / 2 - ITEM_HEIGHT / 2 + yOffset) + drawFolder(folderList[selectedIndex], desh / 2 - ITEM_HEIGHT / 2 + yOffset) i = 1; while (i <= numOfItemsAround) do local index = getCorrectedIndex(selectedIndex, i) - drawFolder(folderList[index], desh / 2 - ITEM_HEIGHT / 2 + - ITEM_HEIGHT * i + yOffset) + drawFolder(folderList[index], + desh / 2 - ITEM_HEIGHT / 2 + ITEM_HEIGHT * i + yOffset) i = i + 1; end end function drawCursor() 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) + gfx.ImageRect(desw / 2 - 14, desh / 2 - 213 / 2, 555, 213, cursorImage, 1, 0) end function tickTransitions(deltaTime) @@ -232,27 +215,40 @@ function tickTransitions(deltaTime) else transitionScrollScale = 1 end - - if scrollingUp then - transitionScrollOffsetY = Easing.inQuad(1-transitionScrollScale) * ITEM_HEIGHT; + + if scrollingUp then + transitionScrollOffsetY = Easing.inQuad(1 - transitionScrollScale) * + ITEM_HEIGHT; else - transitionScrollOffsetY = Easing.inQuad(1-transitionScrollScale) * -ITEM_HEIGHT; + transitionScrollOffsetY = Easing.inQuad(1 - transitionScrollScale) * + -ITEM_HEIGHT; end -- ENTRY TRANSITION - if transitionEnterScale < 1 then - transitionEnterScale = transitionEnterScale + deltaTime / 15 -- transition should last for that time in seconds + if transitionEnterReverse then + if transitionEnterScale > 0 then + transitionEnterScale = transitionEnterScale - deltaTime / 15 -- transition should last for that time in seconds + else + transitionEnterScale = 0 + end else - transitionEnterScale = 1 + if transitionEnterScale < 1 then + transitionEnterScale = transitionEnterScale + deltaTime / 15 -- transition should last for that time in seconds + else + transitionEnterScale = 1 + end end - transitionEnterOffsetY = -Easing.inOutQuad(1-transitionEnterScale) * (desh+ITEM_HEIGHT*2+145); + + transitionEnterOffsetY = -Easing.inOutQuad(1 - transitionEnterScale) * + (desh + ITEM_HEIGHT * 2 + 145 + + (transitionEnterReverse and -4 or 0)); end function drawFilterWheel(deltatime) gfx.ResetTransform() resetLayoutInformation() tickTransitions(deltatime); - gfx.Scale(scale,scale); + gfx.Scale(scale, scale); drawFolderList() @@ -260,18 +256,19 @@ function drawFilterWheel(deltatime) end render = function(deltatime, shown) - if not shown then + if not shown then game.SetSkinSetting('_songWheelOverlayActive', 0); - transitionEnterScale = 0; + transitionEnterReverse = true + + if (transitionEnterScale > 0) then drawFilterWheel(deltatime) end else - game.SetSkinSetting('_songWheelOverlayActive', 1); + transitionEnterReverse = false + game.SetSkinSetting('_songWheelOverlayActive', 1); drawFilterWheel(deltatime) end SongSelectHeader.draw(deltatime); - Footer.draw({ - noEnterTransition = true - }); + Footer.draw({noEnterTransition = true}); -- Debug text gfx.BeginPath(); @@ -279,7 +276,8 @@ render = function(deltatime, shown) gfx.TextAlign(gfx.TEXT_ALIGN_LEFT + gfx.TEXT_ALIGN_TOP) gfx.FillColor(255, 255, 255, 255); gfx.Text('S_M: ' .. selectionMode .. ' // S_F: ' .. selectedFolder .. - ' // S_L: ' .. selectedLevel .. ' // T_S_S: ' .. transitionScrollScale, 8, 1900); + ' // S_L: ' .. selectedLevel .. ' // T_E_S: ' .. + transitionEnterScale, 8, 1900); end set_selection = function(newIndex, isFolder) @@ -297,12 +295,11 @@ set_selection = function(newIndex, isFolder) transitionScrollScale = 0; - scrollingUp = false; - if ((newIndex > oldIndex and not (newIndex == total and oldIndex == 1)) or (newIndex == 1 and oldIndex == total)) then - scrollingUp = true; - end; + scrollingUp = false; + if ((newIndex > oldIndex and not (newIndex == total and oldIndex == 1)) or + (newIndex == 1 and oldIndex == total)) then scrollingUp = true; end - game.PlaySample('song_wheel/cursor_change.wav'); + game.PlaySample('song_wheel/cursor_change.wav'); end set_mode = function(isFolder) diff --git a/scripts/songselect/songwheel.lua b/scripts/songselect/songwheel.lua index 1c8273d..3314163 100644 --- a/scripts/songselect/songwheel.lua +++ b/scripts/songselect/songwheel.lua @@ -1,10 +1,5 @@ require('common') local Easing = require('common.easings'); -local SongSelectHeader = require('components.headers.songSelectHeader'); -local Footer = require('components.footer'); - -local HEADER_HEIGHT = 100; -local BAR_ALPHA = 191; local backgroundImage = gfx.CreateSkinImage("song_select/bg.png", 1) local dataPanelImage = gfx.CreateSkinImage("song_select/data_bg_overlay.png", 1) @@ -19,8 +14,8 @@ local songPlateBottomBarOverlayImage = gfx.CreateSkinImage("song_select/plate/bo 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_exc.png", 1), -- TODO: premissive rate - gfx.CreateSkinImage("song_select/cursor_exc.png", 1), -- TODO: blastive rate + gfx.CreateSkinImage("song_select/cursor_perm.png", 1), -- Premissive rate + gfx.CreateSkinImage("song_select/cursor_blast.png", 1), -- Blastive rate } local diffCursorImage = gfx.CreateSkinImage("song_select/level_cursor.png", 1) @@ -123,7 +118,7 @@ local transitionAfterscrollTextSongArtist = 0; local transitionAfterscrollDifficultiesAlpha = 0; local transitionAfterscrollJacketBgAlpha = 0; -local transitionLeaveActive = false; +local transitionLeaveReverse = false; local transitionLeaveScale = 0; local transitionLeaveOffsetY = 0; @@ -526,17 +521,21 @@ function tickTransitions(deltaTime) end -- Leave transition - if transitionLeaveScale < 1 then - transitionLeaveScale = transitionLeaveScale + deltaTime / 15 -- transition should last for that time in seconds + if (transitionLeaveReverse) then + if transitionLeaveScale > 0 then + transitionLeaveScale = transitionLeaveScale - deltaTime / 15 -- transition should last for that time in seconds + else + transitionLeaveScale = 0 + end else - transitionLeaveScale = 1 + if transitionLeaveScale < 1 then + transitionLeaveScale = transitionLeaveScale + deltaTime / 15 -- transition should last for that time in seconds + else + transitionLeaveScale = 1 + end end - if (transitionLeaveActive) then - transitionLeaveOffsetY = Easing.inOutQuad(transitionLeaveScale) * (desh+songPlateHeight*2+145); - else - transitionLeaveOffsetY = 0; - end + transitionLeaveOffsetY = Easing.inOutQuad(transitionLeaveScale) * (desh+songPlateHeight*2+145); end @@ -558,11 +557,10 @@ render = function (deltaTime) drawSearch(); - if (game.GetSkinSetting('_songWheelOverlayActive') ~= 1) then - transitionLeaveActive = false; - transitionLeaveScale = 0; + if (game.GetSkinSetting('_songWheelOverlayActive') ~= 1) then + transitionLeaveReverse = true; else - transitionLeaveActive = true; + transitionLeaveReverse = false; end gfx.BeginPath(); diff --git a/textures/song_select/cursor_blast.png b/textures/song_select/cursor_blast.png new file mode 100644 index 0000000000000000000000000000000000000000..cb16c1517a44aa78d69454486aac227cba5da5b5 GIT binary patch literal 6605 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 literal 0 HcmV?d00001 diff --git a/textures/song_select/cursor_perm.png b/textures/song_select/cursor_perm.png new file mode 100644 index 0000000000000000000000000000000000000000..cb16c1517a44aa78d69454486aac227cba5da5b5 GIT binary patch literal 6605 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 literal 0 HcmV?d00001