Timer and Day modules
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
This commit is contained in:
@@ -3,6 +3,8 @@
|
||||
|
||||
globals = {
|
||||
"Focus",
|
||||
"Day",
|
||||
"Timer",
|
||||
"Util",
|
||||
"Decision",
|
||||
"Situation",
|
||||
|
||||
@@ -8,6 +8,8 @@ system/system.util.lua
|
||||
system/system.print.lua
|
||||
system/system.input.lua
|
||||
system/system.focus.lua
|
||||
system/system.day.lua
|
||||
system/system.timer.lua
|
||||
system/system.ui.lua
|
||||
audio/audio.manager.lua
|
||||
audio/audio.songs.lua
|
||||
|
||||
@@ -19,7 +19,6 @@ function Audio.music_play_room_street_1() end
|
||||
--- @within Audio
|
||||
function Audio.music_play_room_street_2() end
|
||||
--- Plays room music.
|
||||
-- TODO: function name is incomplete, determine the correct room identifier
|
||||
--- @within Audio
|
||||
function Audio.music_play_room_() end
|
||||
--- Plays room work music.
|
||||
|
||||
@@ -34,10 +34,12 @@ function Context.initial_data()
|
||||
minigame_button_mash = Minigame.get_default_button_mash(),
|
||||
minigame_rhythm = Minigame.get_default_rhythm(),
|
||||
meters = Meter.get_initial(),
|
||||
timer = Timer.get_initial(),
|
||||
game = {
|
||||
current_screen = "home",
|
||||
current_situation = nil,
|
||||
}
|
||||
},
|
||||
day_count = 1,
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
@@ -6,30 +6,12 @@ local COMBO_BASE_BONUS = 0.02
|
||||
local COMBO_MAX_BONUS = 0.16
|
||||
local COMBO_TIMEOUT_FRAMES = 600
|
||||
|
||||
-- 1800 frames = 30 seconds (1800 ÷ 60 = 30)
|
||||
local meter_timer_duration = 1800
|
||||
local meter_timer_decay_per_revolution = 20
|
||||
|
||||
-- Internal meters for tracking game progress and player stats.
|
||||
Meter.COLOR_ISM = Config.colors.red
|
||||
Meter.COLOR_WPM = Config.colors.blue
|
||||
Meter.COLOR_BM = Config.colors.black
|
||||
Meter.COLOR_BG = Config.colors.meter_bg
|
||||
|
||||
--- Sets the number of frames for one full timer revolution.
|
||||
--- @within Meter
|
||||
--- @param frames number Frames per revolution (controls degradation speed).
|
||||
function Meter.set_timer_duration(frames)
|
||||
meter_timer_duration = frames
|
||||
end
|
||||
|
||||
--- Sets the degradation amount applied to all meters per revolution.
|
||||
--- @within Meter
|
||||
--- @param amount number Amount to subtract from each meter per revolution.
|
||||
function Meter.set_timer_decay(amount)
|
||||
meter_timer_decay_per_revolution = amount
|
||||
end
|
||||
|
||||
--- Gets initial meter values.
|
||||
--- @within Meter
|
||||
--- @return result table Initial meter values. </br>
|
||||
@@ -39,8 +21,7 @@ end
|
||||
--- * bm (number) Initial BM meter value.<br/>
|
||||
--- * combo (number) Current combo count.<br/>
|
||||
--- * combo_timer (number) Frames since last combo action.<br/>
|
||||
--- * hidden (boolean) Whether meters are hidden.<br/>
|
||||
--- * timer_progress (number) Clock timer revolution progress (0 to 1).
|
||||
--- * hidden (boolean) Whether meters are hidden.
|
||||
function Meter.get_initial()
|
||||
return {
|
||||
ism = METER_DEFAULT,
|
||||
@@ -49,7 +30,6 @@ function Meter.get_initial()
|
||||
combo = 0,
|
||||
combo_timer = 0,
|
||||
hidden = false,
|
||||
timer_progress = 0,
|
||||
}
|
||||
end
|
||||
|
||||
@@ -96,13 +76,6 @@ function Meter.update()
|
||||
m.combo_timer = 0
|
||||
end
|
||||
end
|
||||
m.timer_progress = m.timer_progress + (1 / meter_timer_duration)
|
||||
if m.timer_progress >= 1 then
|
||||
m.timer_progress = m.timer_progress - 1
|
||||
m.ism = math.max(0, m.ism - meter_timer_decay_per_revolution)
|
||||
m.wpm = math.max(0, m.wpm - meter_timer_decay_per_revolution)
|
||||
m.bm = math.max(0, m.bm - meter_timer_decay_per_revolution)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -118,13 +91,6 @@ 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()
|
||||
|
||||
@@ -12,3 +12,5 @@ Input = {}
|
||||
Sprite = {}
|
||||
Audio = {}
|
||||
Focus = {}
|
||||
Day = {}
|
||||
Timer = {}
|
||||
@@ -30,8 +30,7 @@ Screen.register({
|
||||
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)
|
||||
Print.text_center("day " .. Context.day_count, cx, 10, Config.colors.white)
|
||||
|
||||
local narrative = "reflecting on my past and present\n...\nboth eventually flushed."
|
||||
local wrapped = UI.word_wrap(narrative, 38)
|
||||
@@ -43,7 +42,7 @@ Screen.register({
|
||||
|
||||
local m = Context.meters
|
||||
local max_val = Meter.get_max()
|
||||
local decay_pct = Meter.get_timer_decay_percentage()
|
||||
local decay_pct = Timer.get_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)
|
||||
|
||||
11
inc/system/system.day.lua
Normal file
11
inc/system/system.day.lua
Normal file
@@ -0,0 +1,11 @@
|
||||
local _day_increase_handlers = {}
|
||||
|
||||
function Day.increase()
|
||||
Context.day_count = Context.day_count + 1
|
||||
for _, handler in ipairs(_day_increase_handlers) do
|
||||
handler()
|
||||
end
|
||||
end
|
||||
function Day.register_handler(handler)
|
||||
table.insert(_day_increase_handlers, handler)
|
||||
end
|
||||
@@ -22,8 +22,9 @@ function TIC()
|
||||
handler()
|
||||
end
|
||||
Meter.update()
|
||||
Timer.update()
|
||||
if Context.game_in_progress then
|
||||
UI.draw_meters()
|
||||
UI.draw_timer()
|
||||
Timer.draw()
|
||||
end
|
||||
end
|
||||
|
||||
107
inc/system/system.timer.lua
Normal file
107
inc/system/system.timer.lua
Normal file
@@ -0,0 +1,107 @@
|
||||
--- @section Timer
|
||||
|
||||
local timer_duration = 1800
|
||||
local timer_decay_per_revolution = 20
|
||||
|
||||
--- Gets initial timer values.
|
||||
--- @within Timer
|
||||
--- @return result table Initial timer values. </br>
|
||||
--- Fields: </br>
|
||||
--- * progress (number) Clock timer revolution progress (0 to 1).
|
||||
function Timer.get_initial()
|
||||
return {
|
||||
progress = 0,
|
||||
}
|
||||
end
|
||||
|
||||
--- Sets the number of frames for one full timer revolution.
|
||||
--- @within Timer
|
||||
--- @param frames number Frames per revolution.
|
||||
function Timer.set_duration(frames)
|
||||
timer_duration = frames
|
||||
end
|
||||
|
||||
--- Sets the decay amount applied to all meters per revolution.
|
||||
--- @within Timer
|
||||
--- @param amount number Amount to subtract from each meter.
|
||||
function Timer.set_decay(amount)
|
||||
timer_decay_per_revolution = amount
|
||||
end
|
||||
|
||||
--- Gets the timer decay as a percentage of the max meter value.
|
||||
--- @within Timer
|
||||
--- @return number The decay percentage per revolution.
|
||||
function Timer.get_decay_percentage()
|
||||
return math.floor(timer_decay_per_revolution / Meter.get_max() * 100)
|
||||
end
|
||||
|
||||
--- Updates the timer and handles revolution events.
|
||||
--- @within Timer
|
||||
function Timer.update()
|
||||
if not Context or not Context.game_in_progress or not Context.meters or not Context.timer then return end
|
||||
local m = Context.meters
|
||||
local t = Context.timer
|
||||
local in_minigame = string.find(Window.get_current_id(), "^minigame_") ~= nil
|
||||
|
||||
if not in_minigame then
|
||||
t.progress = t.progress + (1 / timer_duration)
|
||||
if t.progress >= 1 then
|
||||
Day.increase()
|
||||
t.progress = t.progress - 1
|
||||
m.ism = math.max(0, m.ism - timer_decay_per_revolution)
|
||||
m.wpm = math.max(0, m.wpm - timer_decay_per_revolution)
|
||||
m.bm = math.max(0, m.bm - timer_decay_per_revolution)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Draws the clock timer indicator as a circular progress bar.
|
||||
--- @within Timer
|
||||
function Timer.draw()
|
||||
if not Context or not Context.game_in_progress or not Context.meters or not Context.timer then return end
|
||||
if Context.meters.hidden and not Context.stat_screen_active then return end
|
||||
|
||||
local cx = 10
|
||||
local cy = 20
|
||||
local r_outer = 5
|
||||
local r_inner = 3
|
||||
local progress = Context.timer.progress
|
||||
|
||||
local fg_color
|
||||
if progress <= 0.25 then
|
||||
fg_color = Config.colors.white
|
||||
elseif progress <= 0.5 then
|
||||
fg_color = Config.colors.light_blue
|
||||
elseif progress <= 0.75 then
|
||||
fg_color = Config.colors.blue
|
||||
elseif progress <= 1 then
|
||||
fg_color = Config.colors.red
|
||||
end
|
||||
|
||||
local bg_color = Config.colors.dark_grey
|
||||
local start_angle = -math.pi * 0.5
|
||||
local progress_angle = progress * 2 * math.pi
|
||||
local r_outer_sq = r_outer * r_outer
|
||||
local r_inner_sq = r_inner * r_inner
|
||||
|
||||
for dy = -r_outer, r_outer do
|
||||
for dx = -r_outer, r_outer do
|
||||
local dist_sq = dx * dx + dy * dy
|
||||
if dist_sq <= r_outer_sq and dist_sq > r_inner_sq then
|
||||
local angle = math.atan(dy, dx)
|
||||
local relative = angle - start_angle
|
||||
if relative < 0 then relative = relative + 2 * math.pi end
|
||||
if relative <= progress_angle then
|
||||
pix(cx + dx, cy + dy, fg_color)
|
||||
else
|
||||
pix(cx + dx, cy + dy, bg_color)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
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.white)
|
||||
end
|
||||
@@ -155,60 +155,6 @@ function UI.draw_decision_selector(decisions, selected_decision_index)
|
||||
end
|
||||
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%).
|
||||
--- @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 and not Context.stat_screen_active then return end
|
||||
|
||||
local m = Context.meters
|
||||
local cx = 10
|
||||
local cy = 20
|
||||
local r_outer = 5
|
||||
local r_inner = 3
|
||||
local progress = m.timer_progress
|
||||
|
||||
local fg_color
|
||||
if progress <= 0.25 then
|
||||
fg_color = Config.colors.white
|
||||
elseif progress <= 0.5 then
|
||||
fg_color = Config.colors.light_blue
|
||||
elseif progress <= 0.75 then
|
||||
fg_color = Config.colors.blue
|
||||
elseif progress <= 1 then
|
||||
fg_color = Config.colors.red
|
||||
end
|
||||
|
||||
|
||||
local bg_color = Config.colors.dark_grey
|
||||
local start_angle = -math.pi * 0.5
|
||||
local progress_angle = progress * 2 * math.pi
|
||||
local r_outer_sq = r_outer * r_outer
|
||||
local r_inner_sq = r_inner * r_inner
|
||||
|
||||
for dy = -r_outer, r_outer do
|
||||
for dx = -r_outer, r_outer do
|
||||
local dist_sq = dx * dx + dy * dy
|
||||
if dist_sq <= r_outer_sq and dist_sq > r_inner_sq then
|
||||
local angle = math.atan(dy, dx)
|
||||
local relative = angle - start_angle
|
||||
if relative < 0 then relative = relative + 2 * math.pi end
|
||||
if relative <= progress_angle then
|
||||
pix(cx + dx, cy + dy, fg_color)
|
||||
else
|
||||
pix(cx + dx, cy + dy, bg_color)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
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.white)
|
||||
end
|
||||
|
||||
--- Draws meters.
|
||||
--- @within UI
|
||||
function UI.draw_meters()
|
||||
|
||||
Reference in New Issue
Block a user