ExperimentalGear/scripts/titlescreen/mainmenu.lua

521 lines
17 KiB
Lua

require "common.globals"
require "common.class"
local Footer = require("components.footer")
local Wallpaper = require("components.wallpaper")
local Background = require("components.background")
local Display = require("scripts.graphics.display")
local lang = require("language")
local util = require("common.util")
local cursorIndex = 3
local buttonHeight = 128 + 16
local SELECTOR_BAR_OFFSET_FROM_CENTER = 128
local BAR_ALPHA = 191
local HEADER_HEIGHT = 100
local crew = game.GetSkinSetting("single_idol")
local resources = {
images = {
headerTitleImage = gfx.CreateSkinImage("titlescreen/title.png", 0),
selectorBgImage = gfx.CreateSkinImage("titlescreen/selector_bg.png", 0),
selectorArrowsImage = gfx.CreateSkinImage("titlescreen/selector_arrows.png", 0),
unselectedButtonImage = gfx.CreateSkinImage("titlescreen/unselected_button.png", 0),
selectedButtonBgImage = gfx.CreateSkinImage("titlescreen/selected_button_bg.png", 0),
selectedButtonOverImage = gfx.CreateSkinImage("titlescreen/selected_button_over.png", 0)
},
anims = {
idolAnimation = gfx.LoadSkinAnimation("crew/anim/" .. crew, 1 / 30, 0, true)
},
audiosamples = {
bgm = "titlescreen/bgm.wav",
cursorChange = "titlescreen/cursor_change.wav",
cursorSelect = "titlescreen/cursor_select.wav"
},
labels = {
selectorDescriptionLabel = gfx.CreateLabel(lang.Start.desc, 22, 0),
selectorLegendScrollLabel = gfx.CreateLabel(lang.Start.sc, 20, 0),
selectorLegendSelectLabel = gfx.CreateLabel(lang.Start.st3, 20, 0)
}
}
-- load audio samples
for _, path in pairs(resources.audiosamples) do
game.LoadSkinSample(path)
end
local buttons = {
{
labelImage = gfx.CreateSkinImage("titlescreen/labels/skill.png", 0),
labelWidth = 412,
action = nil, -- Menu.Challenges,
description = lang.Challanges.ch,
details = lang.Challanges.ch1,
},
{
labelImage = gfx.CreateSkinImage("titlescreen/labels/friend.png", 0),
labelWidth = 169,
action = nil, -- Menu.Multiplayer,
description = lang.Multiplayer.mp,
details = lang.Multiplayer.mp2,
},
{
labelImage = gfx.CreateSkinImage("titlescreen/labels/normal.png", 0),
labelWidth = 210,
action = nil, -- Menu.Start,
description = lang.Start.st,
details = lang.Start.st2,
},
{
labelImage = gfx.CreateSkinImage("titlescreen/labels/nautica.png", 0),
labelWidth = 230,
action = nil, -- Menu.DLScreen,
description = lang.Nautica.dls,
details = lang.Nautica.dls2,
},
{
labelImage = gfx.CreateSkinImage("titlescreen/labels/settings.png", 0),
labelWidth = 247,
action = nil, -- Menu.Settings,
description = lang.Settings.se,
details = lang.Settings.se1,
},
{
labelImage = gfx.CreateSkinImage("titlescreen/labels/exit.png", 0),
labelWidth = 110,
action = nil, -- Menu.Exit,
description = lang.Exit.ex,
details = lang.Exit.ex2,
},
}
local miscButtons = {
upArrow = {
x = Display.design.width - 265,
y = Display.design.height / 2 + SELECTOR_BAR_OFFSET_FROM_CENTER - buttonHeight + 4,
w = 64,
h = 36
},
downArrow = {
x = Display.design.width - 265,
y = Display.design.height / 2 + SELECTOR_BAR_OFFSET_FROM_CENTER + buttonHeight / 2 + 28,
w = 64,
h = 36
},
mainButton = {
x = Display.design.width - 512,
y = Display.design.height / 2 + SELECTOR_BAR_OFFSET_FROM_CENTER - buttonHeight / 2 - 28,
w = 505,
h = 196
},
upButton1 = {
x = Display.design.width - 512,
y = Display.design.height / 2 + SELECTOR_BAR_OFFSET_FROM_CENTER - 128 - buttonHeight,
w = 1026 / 2,
h = 257 / 2
},
upButton2 = {
x = Display.design.width - 512,
y = Display.design.height / 2 + SELECTOR_BAR_OFFSET_FROM_CENTER - 128 - buttonHeight * 2,
w = 1026 / 2,
h = 257 / 2
},
downButton1 = {
x = Display.design.width - 512,
y = Display.design.height / 2 + SELECTOR_BAR_OFFSET_FROM_CENTER + 128 + 10,
w = 1026 / 2,
h = 257 / 2
},
downButton2 = {
x = Display.design.width - 512,
y = Display.design.height / 2 + SELECTOR_BAR_OFFSET_FROM_CENTER + 128 + buttonHeight + 10,
w = 1026 / 2,
h = 257 / 2
},
}
local scrollTransitionScale = 1 -- Goes from 0 to 1 when transition is happening, sits at 1 when it's not.
local buttonsMovementScale = 0 -- Basically same as `scrollTransitionScale` but with a +/- sign for the scroll direction and goes from 1 to 0
local idolAnimTransitionScale = 0
local oldCursorIndex = 3
local scrollingUp = false
local playedBgm = false
local triggerServiceMenu = false
local function setButtonActions()
buttons[1].action = Menu.Challenges
buttons[2].action = Menu.Multiplayer
buttons[3].action = Menu.Start
buttons[4].action = Menu.DLScreen
buttons[5].action = Menu.Settings
buttons[6].action = Menu.Exit
end
local function draw_button(button, x, y, selected, index)
if (selected) then
-- Draw button background
gfx.BeginPath()
gfx.ImageRect(x, y + (196 / 2 * (1 - scrollTransitionScale)), 505, 196 * scrollTransitionScale,
resources.images.selectedButtonBgImage, 1, 0)
-- Draw button main label
gfx.BeginPath()
gfx.ImageRect(x + 256 - (button.labelWidth / 2), (y + 58) + (64 / 2 * (1 - scrollTransitionScale)),
button.labelWidth, 64 * scrollTransitionScale, button.labelImage, 1, 0)
-- Draw description
gfx.GlobalAlpha((scrollTransitionScale - 0.8) * 5)
gfx.TextAlign(gfx.TEXT_ALIGN_CENTER + gfx.TEXT_ALIGN_MIDDLE)
gfx.FontSize(40)
gfx.BeginPath()
gfx.Text(button.description, x + 256, y + 28)
gfx.GlobalAlpha(1)
-- Draw the glow overlay
gfx.BeginPath()
gfx.ImageRect(x + 2, (y - 42) + (277 / 2 * (1 - scrollTransitionScale)), 501, 277 * scrollTransitionScale,
resources.images.selectedButtonOverImage, 1, 0)
else
if scrollingUp then
if (index == 3 or index == 0) then gfx.GlobalAlpha(1 - scrollTransitionScale) end
if (index == 2 or index == 5) then gfx.GlobalAlpha(scrollTransitionScale) end
else
if (index == 3 or index == 6) then gfx.GlobalAlpha(1 - scrollTransitionScale) end
if (index == 1 or index == 4) then gfx.GlobalAlpha(scrollTransitionScale) end
end
-- Draw button background
gfx.BeginPath()
gfx.ImageRect(x, y + buttonsMovementScale * buttonHeight, 1026 / 2, 257 / 2, resources.images.unselectedButtonImage, 1, 0)
-- Draw button main label
gfx.BeginPath()
gfx.ImageRect(x + 64, y + 28 + buttonsMovementScale * buttonHeight, button.labelWidth, 64, button.labelImage, 1,
0)
-- Draw description
gfx.TextAlign(gfx.TEXT_ALIGN_LEFT + gfx.TEXT_ALIGN_MIDDLE)
gfx.FontSize(28)
gfx.BeginPath()
gfx.Text(button.description, x + 64, y + 18 + buttonsMovementScale * buttonHeight)
gfx.GlobalAlpha(1)
end
end
local function getCorrectedButtonIndex(from, offset)
local buttonsNum = #buttons
local index = from + offset
if index < 1 then
index = buttonsNum + (from + offset) -- this only happens if the offset is negative
end
if index > buttonsNum then
index = offset - (buttonsNum - from) -- this only happens if the offset is positive
end
return index
end
local function draw_buttons()
local indexes = {
getCorrectedButtonIndex(cursorIndex, -2),
getCorrectedButtonIndex(cursorIndex, -1),
cursorIndex,
getCorrectedButtonIndex(cursorIndex, 1),
getCorrectedButtonIndex(cursorIndex, 2),
}
local yBase = Display.design.height / 2 + SELECTOR_BAR_OFFSET_FROM_CENTER
local centerButtonY = yBase - buttonHeight / 2 - 28 -- to fit with the selector bg
local marginFromDesHCenter = 128
if scrollingUp then
draw_button(buttons[indexes[5]], Display.design.width - 512, yBase - marginFromDesHCenter - buttonHeight * 3, false,
0) -- Placeholder for fadeout transition
end
draw_button(buttons[indexes[1]], Display.design.width - 512, yBase - marginFromDesHCenter - buttonHeight * 2, false, 1)
draw_button(buttons[indexes[2]], Display.design.width - 512, yBase - marginFromDesHCenter - buttonHeight, false, 2)
draw_button(buttons[indexes[3]], Display.design.width - 512, centerButtonY, true) -- The main selected center button
if scrollingUp then
draw_button(buttons[indexes[3]], Display.design.width - 512, yBase + marginFromDesHCenter - buttonHeight, false, 3) -- Placeholder for transition that goes to the bottom
else
draw_button(buttons[indexes[3]], Display.design.width - 512, centerButtonY, false, 3) -- Placeholder for transition that goes to the top
end
draw_button(buttons[indexes[4]], Display.design.width - 512, yBase + marginFromDesHCenter + 10, false, 4)
draw_button(buttons[indexes[5]], Display.design.width - 512, yBase + marginFromDesHCenter + buttonHeight + 10, false, 5)
if not scrollingUp then
draw_button(buttons[indexes[1]], Display.design.width - 512, yBase + marginFromDesHCenter + buttonHeight * 2, false,
6)
end
end
local function drawTexts()
local currentFullDescriptionText = buttons[cursorIndex].details
gfx.BeginPath()
gfx.UpdateLabel(resources.labels.selectorDescriptionLabel, currentFullDescriptionText, 22)
gfx.BeginPath()
-- gfx.UpdateLabel(resources.labels.selectorLegendScrollLabel, 'SCROLL', 20)
-- descriptionAlpha = math.abs(selectedButtonScaleY - 0.5) * 2
gfx.TextAlign(gfx.TEXT_ALIGN_LEFT + gfx.TEXT_ALIGN_MIDDLE)
-- Description
gfx.FillColor(255, 255, 255, math.floor(scrollTransitionScale * 255))
gfx.BeginPath()
gfx.DrawLabel(resources.labels.selectorDescriptionLabel, 64, Display.design.height / 2 + SELECTOR_BAR_OFFSET_FROM_CENTER - 52)
-- Legend on the selector
gfx.FillColor(217, 177, 126)
gfx.BeginPath()
gfx.DrawLabel(resources.labels.selectorLegendScrollLabel, 118, Display.design.height / 2 + SELECTOR_BAR_OFFSET_FROM_CENTER + 56)
gfx.BeginPath()
gfx.DrawLabel(resources.labels.selectorLegendSelectLabel, 360, Display.design.height / 2 + SELECTOR_BAR_OFFSET_FROM_CENTER + 56)
gfx.FillColor(255, 255, 255)
end
local function drawHeader()
gfx.BeginPath()
gfx.FillColor(0, 0, 0, BAR_ALPHA)
gfx.Rect(0, 0, Display.design.width, HEADER_HEIGHT)
gfx.Fill()
gfx.ClosePath()
gfx.ImageRect(Display.design.width / 2 - 200, HEADER_HEIGHT / 2 - 20, 400, 40, resources.images.headerTitleImage, 1, 0)
end
local function draw_titlescreen(deltaTime)
gfx.LoadSkinFont("segoeui.ttf")
-- Draw background
gfx.BeginPath()
Background.draw(deltaTime)
local idolAnimTickRes = gfx.TickAnimation(resources.anims.idolAnimation, deltaTime)
if idolAnimTickRes == 1 then
gfx.GlobalAlpha(idolAnimTransitionScale)
idolAnimTransitionScale = idolAnimTransitionScale + 1 / 60
if (idolAnimTransitionScale > 1) then idolAnimTransitionScale = 1 end
gfx.BeginPath()
gfx.ImageRect(0, 0, Display.design.width, Display.design.height, resources.anims.idolAnimation, 1, 0)
gfx.GlobalAlpha(1)
end
-- Draw selector background
gfx.BeginPath()
gfx.ImageRect(0, (Display.design.height / 2 + SELECTOR_BAR_OFFSET_FROM_CENTER) - 280 / 2, 1079, 280, resources.images.selectorBgImage, 1,
0)
buttonY = (Display.design.height / 2) - 2 * (257 + 5)
draw_buttons()
drawTexts()
-- Draw the arrows around the selected button
gfx.BeginPath()
gfx.ImageRect(Display.design.width - 512, Display.design.height / 2 + SELECTOR_BAR_OFFSET_FROM_CENTER - buttonHeight - 8,
501, 300, resources.images.selectorArrowsImage, 1, 0)
-- Draw top and bottom bars
drawHeader()
Footer.draw(deltaTime)
end
local function tickTransitions(deltaTime)
scrollTransitionScale = scrollTransitionScale + deltaTime / 0.2
if (scrollTransitionScale > 1) then scrollTransitionScale = 1 end
if scrollingUp then
buttonsMovementScale = 1 - scrollTransitionScale
else
buttonsMovementScale = -1 + scrollTransitionScale
end
end
local PageView = require "api.page.pageview"
local ModeSelectPage = require "titlescreen.modeselect.modeselectpage"
local PageViewInstance = PageView.new(ModeSelectPage.new())
local function render(deltaTime)
--[[
if not playedBgm then
game.PlaySample(resources.audiosamples.bgm, true)
playedBgm = true
end
]]
game.SetSkinSetting("_currentScreen", "title")
Display.updateResolution()
Wallpaper.render()
Display.transformToScreenSpace()
tickTransitions(deltaTime)
--draw_titlescreen(deltaTime)
PageViewInstance:render(deltaTime)
if (triggerServiceMenu) then
triggerServiceMenu = false
return {eventType = "switch", toScreen = "service"}
end
end
local function reset()
PageViewInstance:get():init()
end
local function callButtonAction()
if buttons[cursorIndex].action == nil then setButtonActions() end
buttons[cursorIndex].action()
end
local function onKnobsChange(direction)
cursorIndex = util.modIndex(cursorIndex + direction, #buttons)
scrollTransitionScale = 0 -- Reset transitions and play them
scrollingUp = false
if ((cursorIndex > oldCursorIndex and not (cursorIndex == 6 and oldCursorIndex == 1)) or
(cursorIndex == 1 and oldCursorIndex == 6)) then scrollingUp = true end
game.PlaySample(resources.audiosamples.cursorChange)
oldCursorIndex = cursorIndex
end
local function onButtonPressed(button)
if button == game.BUTTON_STA then
game.PlaySample(resources.audiosamples.cursorSelect)
game.StopSample(resources.audiosamples.bgm)
callButtonAction()
elseif button == game.BUTTON_BCK then
Menu.Exit()
elseif button == game.BUTTON_FXR then
triggerServiceMenu = true
end
end
local function onMousePressed(button)
local mousePosX, mousePosY = Display.toViewSpace(game.GetMousePos())
local changeIndex = 0
if button ~= 0 then
return
end
if util.areaOverlap(mousePosX, mousePosY,
miscButtons.mainButton.x, miscButtons.mainButton.y, miscButtons.mainButton.w, miscButtons.mainButton.h) then
game.StopSample(resources.audiosamples.bgm)
game.PlaySample(resources.audiosamples.cursorSelect)
callButtonAction()
return
elseif util.areaOverlap(mousePosX, mousePosY,
miscButtons.upArrow.x, miscButtons.upArrow.y, miscButtons.upArrow.w, miscButtons.upArrow.h) or
util.areaOverlap(mousePosX, mousePosY,
miscButtons.upButton1.x, miscButtons.upButton1.y, miscButtons.upButton1.w, miscButtons.upButton1.h) then
changeIndex = -1
scrollTransitionScale = 0
scrollingUp = false
elseif util.areaOverlap(mousePosX, mousePosY,
miscButtons.downArrow.x, miscButtons.downArrow.y, miscButtons.downArrow.w, miscButtons.downArrow.h) or
util.areaOverlap(mousePosX, mousePosY,
miscButtons.downButton1.x, miscButtons.downButton1.y, miscButtons.downButton1.w, miscButtons.downButton1.h) then
changeIndex = 1
scrollTransitionScale = 0
scrollingUp = true
elseif util.areaOverlap(mousePosX, mousePosY,
miscButtons.upButton2.x, miscButtons.upButton2.y, miscButtons.upButton2.w, miscButtons.upButton2.h) then
changeIndex = -2
scrollTransitionScale = 0
scrollingUp = false
elseif util.areaOverlap(mousePosX, mousePosY,
miscButtons.downButton2.x, miscButtons.downButton2.y, miscButtons.downButton2.w, miscButtons.downButton2.h) then
changeIndex = 2
scrollTransitionScale = 0
scrollingUp = true
end
cursorIndex = util.modIndex(cursorIndex + changeIndex, #buttons)
game.PlaySample(resources.audiosamples.cursorChange)
end
local Background = require "components.background"
local Animation = require "scripts.graphics.frameanimation"
local AudioSample = require "api.audiosample"
local Page = require "api.page.page"
local Footer = require "components.footer"
local crew = game.GetSkinSetting("single_idol")
---@class MainMenuPage : Page
---@field _idolAnimationState AnimationState
local MainMenuPage = {
__name = "MainMenuPage",
ANIM = {
idolAnimation = Animation.new{
animPath = "crew/anim/" .. crew,
animFPS = 30, loop = true,
centered = true, x = Display.design.width / 2, y = Display.design.height / 2,
width = Display.design.width, height = Display.design.height,
}
},
AUDIO = {
bgm = AudioSample.new{path = "titlescreen/bgm.wav", exclusive = true, loop = true},
}
}
function MainMenuPage.new(params)
local self = CreateInstance(MainMenuPage, params, Page)
return self
end
function MainMenuPage:init()
self._idolAnimationState = self.ANIM.idolAnimation:start()
self.AUDIO.bgm:play()
end
function MainMenuPage:drawBackground(deltaTime)
Background.draw(deltaTime)
self._idolAnimationState:render(deltaTime)
end
function MainMenuPage:drawForeground(deltaTime)
Footer.draw(deltaTime)
end
return MainMenuPage