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 = {
|
globals = {
|
||||||
"Focus",
|
"Focus",
|
||||||
|
"Day",
|
||||||
|
"Timer",
|
||||||
"Util",
|
"Util",
|
||||||
"Decision",
|
"Decision",
|
||||||
"Situation",
|
"Situation",
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ system/system.util.lua
|
|||||||
system/system.print.lua
|
system/system.print.lua
|
||||||
system/system.input.lua
|
system/system.input.lua
|
||||||
system/system.focus.lua
|
system/system.focus.lua
|
||||||
|
system/system.day.lua
|
||||||
|
system/system.timer.lua
|
||||||
system/system.ui.lua
|
system/system.ui.lua
|
||||||
audio/audio.manager.lua
|
audio/audio.manager.lua
|
||||||
audio/audio.songs.lua
|
audio/audio.songs.lua
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ function Audio.music_play_room_street_1() end
|
|||||||
--- @within Audio
|
--- @within Audio
|
||||||
function Audio.music_play_room_street_2() end
|
function Audio.music_play_room_street_2() end
|
||||||
--- Plays room music.
|
--- Plays room music.
|
||||||
-- TODO: function name is incomplete, determine the correct room identifier
|
|
||||||
--- @within Audio
|
--- @within Audio
|
||||||
function Audio.music_play_room_() end
|
function Audio.music_play_room_() end
|
||||||
--- Plays room work music.
|
--- Plays room work music.
|
||||||
|
|||||||
@@ -34,10 +34,12 @@ function Context.initial_data()
|
|||||||
minigame_button_mash = Minigame.get_default_button_mash(),
|
minigame_button_mash = Minigame.get_default_button_mash(),
|
||||||
minigame_rhythm = Minigame.get_default_rhythm(),
|
minigame_rhythm = Minigame.get_default_rhythm(),
|
||||||
meters = Meter.get_initial(),
|
meters = Meter.get_initial(),
|
||||||
|
timer = Timer.get_initial(),
|
||||||
game = {
|
game = {
|
||||||
current_screen = "home",
|
current_screen = "home",
|
||||||
current_situation = nil,
|
current_situation = nil,
|
||||||
}
|
},
|
||||||
|
day_count = 1,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -6,30 +6,12 @@ local COMBO_BASE_BONUS = 0.02
|
|||||||
local COMBO_MAX_BONUS = 0.16
|
local COMBO_MAX_BONUS = 0.16
|
||||||
local COMBO_TIMEOUT_FRAMES = 600
|
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.
|
-- Internal meters for tracking game progress and player stats.
|
||||||
Meter.COLOR_ISM = Config.colors.red
|
Meter.COLOR_ISM = Config.colors.red
|
||||||
Meter.COLOR_WPM = Config.colors.blue
|
Meter.COLOR_WPM = Config.colors.blue
|
||||||
Meter.COLOR_BM = Config.colors.black
|
Meter.COLOR_BM = Config.colors.black
|
||||||
Meter.COLOR_BG = Config.colors.meter_bg
|
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.
|
--- Gets initial meter values.
|
||||||
--- @within Meter
|
--- @within Meter
|
||||||
--- @return result table Initial meter values. </br>
|
--- @return result table Initial meter values. </br>
|
||||||
@@ -39,8 +21,7 @@ end
|
|||||||
--- * bm (number) Initial BM meter value.<br/>
|
--- * bm (number) Initial BM meter value.<br/>
|
||||||
--- * combo (number) Current combo count.<br/>
|
--- * combo (number) Current combo count.<br/>
|
||||||
--- * combo_timer (number) Frames since last combo action.<br/>
|
--- * combo_timer (number) Frames since last combo action.<br/>
|
||||||
--- * hidden (boolean) Whether meters are hidden.<br/>
|
--- * hidden (boolean) Whether meters are hidden.
|
||||||
--- * timer_progress (number) Clock timer revolution progress (0 to 1).
|
|
||||||
function Meter.get_initial()
|
function Meter.get_initial()
|
||||||
return {
|
return {
|
||||||
ism = METER_DEFAULT,
|
ism = METER_DEFAULT,
|
||||||
@@ -49,7 +30,6 @@ function Meter.get_initial()
|
|||||||
combo = 0,
|
combo = 0,
|
||||||
combo_timer = 0,
|
combo_timer = 0,
|
||||||
hidden = false,
|
hidden = false,
|
||||||
timer_progress = 0,
|
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -96,13 +76,6 @@ function Meter.update()
|
|||||||
m.combo_timer = 0
|
m.combo_timer = 0
|
||||||
end
|
end
|
||||||
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
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -118,13 +91,6 @@ function Meter.add(key, amount)
|
|||||||
end
|
end
|
||||||
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.
|
--- Called on minigame completion.
|
||||||
--- @within Meter
|
--- @within Meter
|
||||||
function Meter.on_minigame_complete()
|
function Meter.on_minigame_complete()
|
||||||
|
|||||||
@@ -12,3 +12,5 @@ Input = {}
|
|||||||
Sprite = {}
|
Sprite = {}
|
||||||
Audio = {}
|
Audio = {}
|
||||||
Focus = {}
|
Focus = {}
|
||||||
|
Day = {}
|
||||||
|
Timer = {}
|
||||||
@@ -30,8 +30,7 @@ Screen.register({
|
|||||||
local bar_x = math.floor((sw - bar_w) / 2)
|
local bar_x = math.floor((sw - bar_w) / 2)
|
||||||
local bar_h = 4
|
local bar_h = 4
|
||||||
|
|
||||||
-- TODO: Add day counter
|
Print.text_center("day " .. Context.day_count, cx, 10, Config.colors.white)
|
||||||
Print.text_center("day 1", cx, 10, Config.colors.white)
|
|
||||||
|
|
||||||
local narrative = "reflecting on my past and present\n...\nboth eventually flushed."
|
local narrative = "reflecting on my past and present\n...\nboth eventually flushed."
|
||||||
local wrapped = UI.word_wrap(narrative, 38)
|
local wrapped = UI.word_wrap(narrative, 38)
|
||||||
@@ -43,7 +42,7 @@ Screen.register({
|
|||||||
|
|
||||||
local m = Context.meters
|
local m = Context.meters
|
||||||
local max_val = Meter.get_max()
|
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 decay_text = string.format("-%d%%", decay_pct)
|
||||||
local combo_mult = Meter.get_combo_multiplier()
|
local combo_mult = Meter.get_combo_multiplier()
|
||||||
local combo_pct = math.floor((combo_mult - 1) * 100)
|
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()
|
handler()
|
||||||
end
|
end
|
||||||
Meter.update()
|
Meter.update()
|
||||||
|
Timer.update()
|
||||||
if Context.game_in_progress then
|
if Context.game_in_progress then
|
||||||
UI.draw_meters()
|
UI.draw_meters()
|
||||||
UI.draw_timer()
|
Timer.draw()
|
||||||
|
end
|
||||||
end
|
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
|
||||||
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.
|
--- Draws meters.
|
||||||
--- @within UI
|
--- @within UI
|
||||||
function UI.draw_meters()
|
function UI.draw_meters()
|
||||||
|
|||||||
Reference in New Issue
Block a user