diff --git a/inc/init/init.context.lua b/inc/init/init.context.lua index 3272a3c..bae6880 100644 --- a/inc/init/init.context.lua +++ b/inc/init/init.context.lua @@ -17,6 +17,7 @@ Context = {} --- @return result.minigame_button_mash table Button mash minigame state (see Minigame.get_default_button_mash). --- @return result.minigame_rhythm table Rhythm minigame state (see Minigame.get_default_rhythm). --- @return result.meters table Meter values (see Meter.get_initial). +--- @return result.stat_screen_active boolean Whether the stat screen overlay is currently shown. --- @return result.game table Current game progress state. Contains: `current_screen` (string) active screen ID, `current_situation` (string|nil) active situation ID. function Context.initial_data() return { @@ -27,6 +28,7 @@ function Context.initial_data() content = {} }, game_in_progress = false, + stat_screen_active = false, minigame_ddr = Minigame.get_default_ddr(), minigame_button_mash = Minigame.get_default_button_mash(), minigame_rhythm = Minigame.get_default_rhythm(), diff --git a/inc/init/init.meter.lua b/inc/init/init.meter.lua index 3a890a6..938b2f6 100644 --- a/inc/init/init.meter.lua +++ b/inc/init/init.meter.lua @@ -89,9 +89,6 @@ function Meter.update() local m = Context.meters local in_minigame = string.find(Window.get_current_id(), "^minigame_") ~= nil if not in_minigame then - m.ism = math.max(0, m.ism - METER_DECAY_PER_FRAME) - m.wpm = math.max(0, m.wpm - METER_DECAY_PER_FRAME) - m.bm = math.max(0, m.bm - METER_DECAY_PER_FRAME) if m.combo > 0 then m.combo_timer = m.combo_timer + 1 if m.combo_timer >= COMBO_TIMEOUT_FRAMES then @@ -121,6 +118,13 @@ function Meter.add(key, amount) end end +--- Gets the timer decay as a percentage of the max meter value. +--- @within Meter +--- @return number The decay percentage per revolution (e.g. 2 means -2%). +function Meter.get_timer_decay_percentage() + return math.floor(meter_timer_decay_per_revolution / METER_MAX * 100) +end + --- Called on minigame completion. --- @within Meter function Meter.on_minigame_complete() diff --git a/inc/screen/screen.manager.lua b/inc/screen/screen.manager.lua index 66b1b59..5edb0b5 100644 --- a/inc/screen/screen.manager.lua +++ b/inc/screen/screen.manager.lua @@ -11,6 +11,7 @@ local _screens = {} --- @param[opt] screen_data.situations table Array of situation ID strings. Defaults to {}. --- @param[opt] screen_data.init function Called when the screen is entered. Defaults to noop. --- @param[opt] screen_data.update function Called each frame while screen is active. Defaults to noop. +--- @param[opt] screen_data.draw function Called after the focus overlay to draw screen-specific overlays. Defaults to noop. function Screen.register(screen_data) if _screens[screen_data.id] then trace("Warning: Overwriting screen with id: " .. screen_data.id) @@ -24,6 +25,9 @@ function Screen.register(screen_data) if not screen_data.update then screen_data.update = function() end end + if not screen_data.draw then + screen_data.draw = function() end + end _screens[screen_data.id] = screen_data end diff --git a/inc/screen/screen.toilet.lua b/inc/screen/screen.toilet.lua index 075bf8d..dae74c3 100644 --- a/inc/screen/screen.toilet.lua +++ b/inc/screen/screen.toilet.lua @@ -3,5 +3,74 @@ Screen.register({ name = "Toilet", decisions = { "go_to_home", - } + }, + background = "bedroom", + init = function() + Context.stat_screen_active = true + Meter.hide() + local cx = Config.screen.width * 0.75 + local cy = Config.screen.height * 0.75 + Focus.start_driven(cx, cy) + Focus.set_percentage(0.15) + end, + update = function() + if not Context.stat_screen_active then return end + if Input.select() or Input.player_interact() then + Focus.stop() + Context.stat_screen_active = false + Meter.show() + end + end, + draw = function() + if not Context.stat_screen_active then return end + + local sw = Config.screen.width + local cx = sw / 2 + local bar_w = math.floor(sw * 0.75) + local bar_x = math.floor((sw - bar_w) / 2) + local bar_h = 4 + + -- TODO: Add day counter + Print.text_center("day 1", cx, 10, Config.colors.white) + + local narrative = "reflecting on my past and present\n...\nboth eventually flushed." + local wrapped = UI.word_wrap(narrative, 38) + local text_y = 24 + for _, line in ipairs(wrapped) do + Print.text_center(line, cx, text_y, Config.colors.light_grey) + text_y = text_y + 8 + end + + local m = Context.meters + local max_val = Meter.get_max() + local decay_pct = Meter.get_timer_decay_percentage() + local decay_text = string.format("-%d%%", decay_pct) + local combo_mult = Meter.get_combo_multiplier() + local combo_pct = math.floor((combo_mult - 1) * 100) + local mult_text = string.format("+%d%%", combo_pct) + local meter_start_y = text_y + 10 + + local meter_list = { + { key = "wpm", label = "Work Productivity Meter" }, + { key = "ism", label = "Impostor Syndrome Meter" }, + { key = "bm", label = "Burnout Meter" }, + } + + for i, meter in ipairs(meter_list) do + local y = meter_start_y + (i - 1) * 20 + + Print.text_center(meter.label, cx, y, Config.colors.white) + + local bar_y = y + 8 + local fill_w = math.max(0, math.floor((m[meter.key] / max_val) * bar_w)) + rect(bar_x, bar_y, bar_w, bar_h, Meter.COLOR_BG) + if fill_w > 0 then + rect(bar_x, bar_y, fill_w, bar_h, Config.colors.blue) + end + + local decay_w = print(decay_text, 0, -6, 0, false, 1) + Print.text(decay_text, bar_x - decay_w - 4, bar_y, Config.colors.light_blue) + Print.text(mult_text, bar_x + bar_w + 4, bar_y, Config.colors.light_blue) + end + end, }) diff --git a/inc/system/system.ui.lua b/inc/system/system.ui.lua index fea3aaf..03faca3 100644 --- a/inc/system/system.ui.lua +++ b/inc/system/system.ui.lua @@ -155,11 +155,10 @@ end --- Draws the clock timer indicator as a circular progress bar in the top-left area. --- Color transitions: white (0-50%), yellow (50-75%), red (75-100%). ---- Only visible when meters are visible. --- @within UI function UI.draw_timer() if not Context or not Context.game_in_progress or not Context.meters then return end - if Context.meters.hidden then return end + if Context.meters.hidden and not Context.stat_screen_active then return end local m = Context.meters local cx = 10 @@ -205,7 +204,7 @@ function UI.draw_timer() local hand_angle = start_angle + progress_angle local hand_x = math.floor(cx + math.cos(hand_angle) * (r_inner - 1) + 0.5) local hand_y = math.floor(cy + math.sin(hand_angle) * (r_inner - 1) + 0.5) - line(cx, cy, hand_x, hand_y, Config.colors.black) + line(cx, cy, hand_x, hand_y, Config.colors.white) end --- Draws meters. diff --git a/inc/window/window.game.lua b/inc/window/window.game.lua index ec18904..b61f199 100644 --- a/inc/window/window.game.lua +++ b/inc/window/window.game.lua @@ -12,11 +12,12 @@ function GameWindow.draw() rect(0, 0, Config.screen.width, Config.screen.height, screen.background_color) end UI.draw_top_bar(screen.name) - if #_available_decisions > 0 then + if not Context.stat_screen_active and #_available_decisions > 0 then UI.draw_decision_selector(_available_decisions, _selected_decision_index) end Sprite.draw() Focus.draw() + screen.draw() end --- Updates the game window logic. @@ -40,6 +41,8 @@ function GameWindow.update() end end + if Context.stat_screen_active then return end + -- Fetch and filter decisions locally local all_decisions_for_screen = Decision.get_for_screen(screen) _available_decisions = Decision.filter_available(all_decisions_for_screen)