Files
impostor/inc/init/init.ascension.lua
Zoltan Timar b4dcdaba58
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
ci/woodpecker/pr/woodpecker Pipeline failed
feat: added ascension meter, done 0-1 asc logic, fixed mysterious man behaviours
2026-03-19 18:22:06 +01:00

170 lines
4.8 KiB
Lua

--- @section Ascension
local ASCENSION_MAX_LEVEL = 9
local ASCENSION_WORD = "ASCENSION"
local _increased_this_cycle = false
local _flash_active = false
local _flash_timer = 0
local _flash_total = 0
local FLASH_DURATION = 120
local _fade_active = false
local _fade_timer = 0
local FADE_DURATION = 120
local FADE_COLORS = nil
--- Gets initial ascension state.
--- @within Ascension
--- @return result table Initial ascension state. </br>
--- Fields: </br>
--- * level (number) Current ascension level (0-9).
function Ascension.get_initial()
_increased_this_cycle = false
return {
level = 0,
}
end
--- Gets the current ascension level.
--- @within Ascension
--- @return number The current ascension level (0-9).
function Ascension.get_level()
if not Context or not Context.ascension then return 0 end
return Context.ascension.level
end
--- Gets the maximum ascension level.
--- @within Ascension
--- @return number The maximum ascension level.
function Ascension.get_max_level()
return ASCENSION_MAX_LEVEL
end
--- Increases the ascension level by 1, clamped to the max.
--- @within Ascension
function Ascension.increase()
if not Context or not Context.ascension then return end
Context.ascension.level = math.min(ASCENSION_MAX_LEVEL, Context.ascension.level + 1)
_increased_this_cycle = true
end
--- Returns true if ascension was incremented since the last consume call.
--- @within Ascension
--- @return boolean Whether ascension increased this cycle.
function Ascension.did_increase()
return _increased_this_cycle
end
--- Consumes the increase flag, returning its value and resetting it.
--- @within Ascension
--- @return boolean Whether ascension had increased this cycle.
function Ascension.consume_increase()
local result = _increased_this_cycle
_increased_this_cycle = false
return result
end
--- Returns true when the ascension meter is fully complete (level 10).
--- @within Ascension
--- @return boolean Whether the cycle can be broken.
function Ascension.is_complete()
return Ascension.get_level() >= ASCENSION_MAX_LEVEL
end
--- Draws the ascension meter as individual letters of "ASCENSION".
--- Each letter lights up per level. Drawn beneath existing meter bars.
--- @within Ascension
--- @param x number Left x position.
--- @param y number Top y position.
--- @param options table Optional overrides: lit_color, dim_color, spacing.
function Ascension.draw(x, y, options)
if not Context or not Context.ascension then return end
options = options or {}
local level = Context.ascension.level
if level < 1 then return end
local lit_color = options.lit_color or Config.colors.white
local spacing = options.spacing or 5
for i = 1, level do
local ch = ASCENSION_WORD:sub(i, i)
local color
if i == level and _fade_active then
color = Ascension.get_fade_color()
else
color = lit_color
end
print(ch, x + (i - 1) * spacing, y, color, false, 1, true)
end
end
--- Returns the current fade-in color based on progress through the palette.
--- @within Ascension
--- @return number The palette color index for the current fade step.
function Ascension.get_fade_color()
if not FADE_COLORS then
FADE_COLORS = {
Config.colors.black,
Config.colors.dark_grey,
Config.colors.light_grey,
Config.colors.white,
}
end
if not _fade_active then return Config.colors.white end
local progress = math.min(_fade_timer / FADE_DURATION, 1)
local idx = math.floor(progress * (#FADE_COLORS - 1)) + 1
return FADE_COLORS[idx]
end
--- Starts the fade-in effect for the most recently gained letter.
--- @within Ascension
function Ascension.start_fade()
_fade_active = true
_fade_timer = 0
end
--- Starts the ascension flash effect.
--- @within Ascension
function Ascension.start_flash()
_flash_active = true
_flash_timer = 0
_flash_total = FLASH_DURATION
end
--- Updates and draws the ascension flash overlay.
--- Call once per frame from the main loop.
--- @within Ascension
function Ascension.draw_flash()
if not _flash_active then return end
_flash_timer = _flash_timer + 1
local sw = Config.screen.width
local sh = Config.screen.height
local progress = _flash_timer / FLASH_DURATION
local pulse = math.abs(math.sin(progress * math.pi * 6))
local flash_color = (pulse > 0.5) and Config.colors.white or Config.colors.light_grey
rect(0, 0, sw, sh, flash_color)
if _flash_timer >= _flash_total then
_flash_active = false
Ascension.start_fade()
end
end
--- Updates the fade-in timer. Call once per frame from the main loop.
--- @within Ascension
function Ascension.update_fade()
if not _fade_active then return end
_fade_timer = _fade_timer + 1
if _fade_timer >= FADE_DURATION then
_fade_active = false
end
end
--- Returns whether a flash effect is currently active.
--- @within Ascension
--- @return boolean Whether the flash is playing.
function Ascension.is_flashing()
return _flash_active
end