Compare commits

...

3 Commits

Author SHA1 Message Date
b337ae8516 main menu tweaks
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2026-04-02 19:12:39 +02:00
10316d3075 Controls menu 2026-04-02 18:51:17 +02:00
589b225ab0 remove configuration menu 2026-04-02 18:45:12 +02:00
8 changed files with 126 additions and 130 deletions

View File

@@ -30,7 +30,7 @@ globals = {
"MenuWindow", "MenuWindow",
"GameWindow", "GameWindow",
"PopupWindow", "PopupWindow",
"ConfigurationWindow", "ControlsWindow",
"AudioTestWindow", "AudioTestWindow",
"MinigameButtonMashWindow", "MinigameButtonMashWindow",
"MinigameRhythmWindow", "MinigameRhythmWindow",

View File

@@ -70,7 +70,7 @@ window/window.intro.title.lua
window/window.intro.ttg.lua window/window.intro.ttg.lua
window/window.intro.brief.lua window/window.intro.brief.lua
window/window.menu.lua window/window.menu.lua
window/window.configuration.lua window/window.controls.lua
window/window.audiotest.lua window/window.audiotest.lua
window/window.popup.lua window/window.popup.lua
window/window.minigame.mash.lua window/window.minigame.mash.lua

View File

@@ -3,7 +3,8 @@ local INPUT_KEY_UP = 0
local INPUT_KEY_DOWN = 1 local INPUT_KEY_DOWN = 1
local INPUT_KEY_LEFT = 2 local INPUT_KEY_LEFT = 2
local INPUT_KEY_RIGHT = 3 local INPUT_KEY_RIGHT = 3
local INPUT_KEY_Y = 7 local INPUT_KEY_A = 4
local INPUT_KEY_B = 5
local INPUT_KEY_SPACE = 48 local INPUT_KEY_SPACE = 48
local INPUT_KEY_BACKSPACE = 51 local INPUT_KEY_BACKSPACE = 51
@@ -21,7 +22,7 @@ function Input.left() return btnp(INPUT_KEY_LEFT) end
function Input.right() return btnp(INPUT_KEY_RIGHT) end function Input.right() return btnp(INPUT_KEY_RIGHT) end
--- Checks if Select is pressed. --- Checks if Select is pressed.
--- @within Input --- @within Input
function Input.select() return btnp(INPUT_KEY_Y) or keyp(INPUT_KEY_SPACE) or Mouse.clicked() end function Input.select() return btnp(INPUT_KEY_A) or keyp(INPUT_KEY_SPACE) or Mouse.clicked() end
--- Checks if Back is pressed. --- Checks if Back is pressed.
--- @within Input --- @within Input
function Input.back() return keyp(INPUT_KEY_BACKSPACE) end function Input.back() return btnp(INPUT_KEY_B) or keyp(INPUT_KEY_BACKSPACE) end

View File

@@ -10,7 +10,7 @@ function Print.text(text, x, y, color, fixed, scale)
local shadow_color = Config.colors.black local shadow_color = Config.colors.black
if color == shadow_color then shadow_color = Config.colors.light_grey end if color == shadow_color then shadow_color = Config.colors.light_grey end
scale = scale or 1 scale = scale or 1
print(text, x + 1, y + 1, shadow_color, fixed, scale) print(text, x + scale, y + scale, shadow_color, fixed, scale)
print(text, x, y, color, fixed, scale) print(text, x, y, color, fixed, scale)
end end
@@ -24,7 +24,7 @@ end
--- @param[opt] scale number The scaling factor.<br/> --- @param[opt] scale number The scaling factor.<br/>
function Print.text_center(text, x, y, color, fixed, scale) function Print.text_center(text, x, y, color, fixed, scale)
scale = scale or 1 scale = scale or 1
local text_width = print(text, 0, -6, 0, fixed, scale) local text_width = print(text, 0, -6 * scale, 0, fixed, scale)
local centered_x = x - (text_width / 2) local centered_x = x - (text_width / 2)
Print.text(text, centered_x, y, color, fixed, scale) Print.text(text, centered_x, y, color, fixed, scale)
end end

View File

@@ -1,102 +0,0 @@
--- @section ConfigurationWindow
ConfigurationWindow.controls = {}
ConfigurationWindow.selected_control = 1
--- Initializes configuration window.
--- @within ConfigurationWindow
function ConfigurationWindow.init()
ConfigurationWindow.controls = {
{
label = "Save",
action = function() Config.save() end,
type = "action_item"
},
{
label = "Restore Defaults",
action = function() Config.reset() end,
type = "action_item"
},
}
end
--- Draws configuration window.
--- @within ConfigurationWindow
function ConfigurationWindow.draw()
UI.draw_top_bar("Configuration")
local x_start = 10
local y_start = 40
local x_value_right_align = Config.screen.width - 10
local char_width = 4
for i, control in ipairs(ConfigurationWindow.controls) do
local current_y = y_start + (i - 1) * 12
local color = Config.colors.light_blue
if control.type == "numeric_stepper" then
local value = control.get()
local label_text = control.label
local value_text = string.format(control.format, value)
local value_x = x_value_right_align - (#value_text * char_width)
if i == ConfigurationWindow.selected_control then
color = Config.colors.item
Print.text("<", x_start - 8, current_y, color)
Print.text(label_text, x_start, current_y, color)
Print.text(value_text, value_x, current_y, color)
Print.text(">", x_value_right_align + 4, current_y, color)
else
Print.text(label_text, x_start, current_y, color)
Print.text(value_text, value_x, current_y, color)
end
elseif control.type == "action_item" then
local label_text = control.label
if i == ConfigurationWindow.selected_control then
color = Config.colors.item
Print.text("<", x_start - 8, current_y, color)
Print.text(label_text, x_start, current_y, color)
Print.text(">", x_start + 8 + (#label_text * char_width) + 4, current_y, color)
else
Print.text(label_text, x_start, current_y, color)
end
end
end
Print.text("Press B to go back", x_start, 120, Config.colors.light_grey)
end
--- Updates configuration window logic.
--- @within ConfigurationWindow
function ConfigurationWindow.update()
if Input.back() then
GameWindow.set_state("menu")
return
end
if Input.up() then
ConfigurationWindow.selected_control = ConfigurationWindow.selected_control - 1
if ConfigurationWindow.selected_control < 1 then
ConfigurationWindow.selected_control = #ConfigurationWindow.controls
end
elseif Input.down() then
ConfigurationWindow.selected_control = ConfigurationWindow.selected_control + 1
if ConfigurationWindow.selected_control > #ConfigurationWindow.controls then
ConfigurationWindow.selected_control = 1
end
end
local control = ConfigurationWindow.controls[ConfigurationWindow.selected_control]
if control then
if control.type == "numeric_stepper" then
local current_value = control.get()
if Input.left() then
local new_value = math.max(control.min, current_value - control.step)
control.set(new_value)
elseif Input.right() then
local new_value = math.min(control.max, current_value + control.step)
control.set(new_value)
end
elseif control.type == "action_item" then
if Input.select() then
control.action()
end
end
end
end

View File

@@ -0,0 +1,44 @@
--- @section ControlsWindow
local _controls = {
{ action = "Navigate", keyboard = "Arrow keys", gamepad = "D-pad" },
{ action = "Select / OK", keyboard = "Space", gamepad = "Z button" },
{ action = "Back", keyboard = "Backspace", gamepad = "B button" },
{ action = "Click", keyboard = "Mouse", gamepad = "" },
}
--- Draws the controls window.
--- @within ControlsWindow
function ControlsWindow.draw()
UI.draw_top_bar("Controls")
local col_action = 4
local col_keyboard = 80
local col_gamepad = 170
local row_h = 10
local y_header = 18
local y_start = 30
Print.text("Action", col_action, y_header, Config.colors.light_grey)
Print.text("Keyboard", col_keyboard, y_header, Config.colors.light_grey)
Print.text("Gamepad", col_gamepad, y_header, Config.colors.light_grey)
line(col_action, y_header + 8, Config.screen.width - 4, y_header + 8, Config.colors.dark_grey)
for i, entry in ipairs(_controls) do
local y = y_start + (i - 1) * row_h
Print.text(entry.action, col_action, y, Config.colors.white)
Print.text(entry.keyboard, col_keyboard, y, Config.colors.light_blue)
if entry.gamepad ~= "" then
Print.text(entry.gamepad, col_gamepad, y, Config.colors.light_blue)
end
end
Print.text("Space / Z button or click to go back", col_action, Config.screen.height - 10, Config.colors.light_grey)
end
--- Updates the controls window logic.
--- @within ControlsWindow
function ControlsWindow.update()
if Input.back() or Input.select() then
Window.set_current("menu")
end
end

View File

@@ -1,19 +1,62 @@
--- @section MenuWindow --- @section MenuWindow
local _menu_items = {} local _menu_items = {}
local _click_timer = 0 local _click_timer = 0
local _anim = 0
local _menu_max_w = 0
local ANIM_SPEED = 2.5
local HEADER_H = 28
--- Calculates the animated x position of the menu block.
--- @within MenuWindow
--- @return number x The left edge x coordinate for the menu.
function MenuWindow.calc_menu_x()
local center_start = Config.screen.width / 2
local center_end = Config.screen.width * 0.72
local center = center_start + _anim * (center_end - center_start)
return math.floor(center - _menu_max_w / 2)
end
--- Draws the header with title and separator.
--- @within MenuWindow
function MenuWindow.draw_header()
rect(0, 0, Config.screen.width, HEADER_H, Config.colors.dark_grey)
rect(0, HEADER_H - 2, Config.screen.width, 2, Config.colors.light_blue)
local cx = Config.screen.width / 2
local subtitle = "Definitely not an"
if Context.test_mode then subtitle = subtitle .. " [TEST]" end
local sub_w = print(subtitle, 0, -6, 0, false, 1, true)
print(subtitle, math.floor(cx - sub_w / 2) + 1, 5, Config.colors.dark_grey, false, 1, true)
print(subtitle, math.floor(cx - sub_w / 2), 4, Config.colors.light_grey, false, 1, true)
Print.text_center("IMPOSTOR", cx, 12, Config.colors.item, false, 2)
end
--- Draws the 4x scaled Norman sprite on the left side of the screen.
--- @within MenuWindow
function MenuWindow.draw_norman()
local nx = math.floor(Config.screen.width * 0.45 / 2) - 32
local ny = HEADER_H + math.floor((Config.screen.height - HEADER_H - 96) / 2)
spr(272, nx, ny, 0, 4)
spr(273, nx + 32, ny, 0, 4)
spr(288, nx, ny + 32, 0, 4)
spr(289, nx + 32, ny + 32, 0, 4)
spr(304, nx, ny + 64, 0, 4)
spr(305, nx + 32, ny + 64, 0, 4)
end
--- Draws the menu window. --- Draws the menu window.
--- @within MenuWindow --- @within MenuWindow
function MenuWindow.draw() function MenuWindow.draw()
local title = "Definitely not an Impostor" MenuWindow.draw_header()
if Context.test_mode then
title = title .. " (TEST MODE)" if _anim > 0 then
MenuWindow.draw_norman()
end end
UI.draw_top_bar(title)
local menu_h = #_menu_items * 10 local menu_h = #_menu_items * 10
local y = 10 + (Config.screen.height - 10 - 10 - menu_h) / 2 local y = HEADER_H + math.floor((Config.screen.height - HEADER_H - 10 - menu_h) / 2)
UI.draw_menu(_menu_items, Context.current_menu_item, 0, y, true) UI.draw_menu(_menu_items, Context.current_menu_item, MenuWindow.calc_menu_x(), y, false)
local ttg_text = "TTG" local ttg_text = "TTG"
local ttg_w = print(ttg_text, 0, -10, 0, false, 1, false) local ttg_w = print(ttg_text, 0, -10, 0, false, 1, false)
@@ -23,8 +66,12 @@ end
--- Updates the menu window logic. --- Updates the menu window logic.
--- @within MenuWindow --- @within MenuWindow
function MenuWindow.update() function MenuWindow.update()
if _anim < 1 then
_anim = math.min(1, _anim + ANIM_SPEED * Context.delta_time)
end
local menu_h = #_menu_items * 10 local menu_h = #_menu_items * 10
local y = 10 + (Config.screen.height - 10 - 10 - menu_h) / 2 local y = HEADER_H + math.floor((Config.screen.height - HEADER_H - 10 - menu_h) / 2)
if _click_timer > 0 then if _click_timer > 0 then
_click_timer = _click_timer - Context.delta_time _click_timer = _click_timer - Context.delta_time
@@ -38,7 +85,7 @@ function MenuWindow.update()
return return
end end
local new_item, mouse_confirmed = UI.update_menu(_menu_items, Context.current_menu_item, 0, y, true) local new_item, mouse_confirmed = UI.update_menu(_menu_items, Context.current_menu_item, MenuWindow.calc_menu_x(), y, false)
Context.current_menu_item = new_item Context.current_menu_item = new_item
if mouse_confirmed then if mouse_confirmed then
@@ -84,11 +131,10 @@ function MenuWindow.exit()
exit() exit()
end end
--- Opens the configuration menu. --- Opens the controls screen.
--- @within MenuWindow --- @within MenuWindow
function MenuWindow.configuration() function MenuWindow.controls()
ConfigurationWindow.init() Window.set_current("controls")
GameWindow.set_state("configuration")
end end
--- Opens the audio test menu. --- Opens the audio test menu.
@@ -105,7 +151,7 @@ function MenuWindow.continued()
GameWindow.set_state("continued") GameWindow.set_state("continued")
end end
--- Opens the minigame ddr test menu. --- Opens the DDR minigame test.
--- @within MenuWindow --- @within MenuWindow
function MenuWindow.ddr_test() function MenuWindow.ddr_test()
AudioTestWindow.init() AudioTestWindow.init()
@@ -113,27 +159,34 @@ function MenuWindow.ddr_test()
MinigameDDRWindow.start("menu", "generated", { special_mode = "only_nothing" }) MinigameDDRWindow.start("menu", "generated", { special_mode = "only_nothing" })
end end
--- Refreshes menu items. --- Refreshes the list of menu items based on current game state.
--- @within MenuWindow --- @within MenuWindow
function MenuWindow.refresh_menu_items() function MenuWindow.refresh_menu_items()
_menu_items = {} _menu_items = {}
if Context.game_in_progress then if Context.game_in_progress then
table.insert(_menu_items, {label = "Resume Game", decision = MenuWindow.resume_game}) table.insert(_menu_items, {label = "Resume Game", decision = MenuWindow.resume_game})
table.insert(_menu_items, {label = "Save Game", decision = MenuWindow.save_game}) table.insert(_menu_items, {label = "Save Game", decision = MenuWindow.save_game})
end end
table.insert(_menu_items, {label = "New Game", decision = MenuWindow.new_game}) table.insert(_menu_items, {label = "New Game", decision = MenuWindow.new_game})
table.insert(_menu_items, {label = "Load Game", decision = MenuWindow.load_game}) table.insert(_menu_items, {label = "Load Game", decision = MenuWindow.load_game})
table.insert(_menu_items, {label = "Configuration", decision = MenuWindow.configuration}) table.insert(_menu_items, {label = "Controls", decision = MenuWindow.controls})
if Context.test_mode then if Context.test_mode then
table.insert(_menu_items, {label = "Audio Test", decision = MenuWindow.audio_test}) table.insert(_menu_items, {label = "Audio Test", decision = MenuWindow.audio_test})
table.insert(_menu_items, {label = "To Be Continued...", decision = MenuWindow.continued}) table.insert(_menu_items, {label = "To Be Continued...", decision = MenuWindow.continued})
table.insert(_menu_items, {label = "DDR Test", decision = MenuWindow.ddr_test}) table.insert(_menu_items, {label = "DDR Test", decision = MenuWindow.ddr_test})
end end
table.insert(_menu_items, {label = "Exit", decision = MenuWindow.exit}) table.insert(_menu_items, {label = "Exit", decision = MenuWindow.exit})
_menu_max_w = 0
for _, item in ipairs(_menu_items) do
local w = print(item.label, 0, -10, 0, false, 1, false)
if w > _menu_max_w then _menu_max_w = w end
end
Context.current_menu_item = 1 Context.current_menu_item = 1
_click_timer = 0 _click_timer = 0
_anim = 0
end end

View File

@@ -16,8 +16,8 @@ Window.register("game", GameWindow)
PopupWindow = {} PopupWindow = {}
Window.register("popup", PopupWindow) Window.register("popup", PopupWindow)
ConfigurationWindow = {} ControlsWindow = {}
Window.register("configuration", ConfigurationWindow) Window.register("controls", ControlsWindow)
AudioTestWindow = {} AudioTestWindow = {}
Window.register("audiotest", AudioTestWindow) Window.register("audiotest", AudioTestWindow)