Compare commits

...

9 Commits

Author SHA1 Message Date
c279b98800 Merge pull request '[MASTER] 1.0 RELEASE' (#52) from develop into master
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Reviewed-on: http://git.teletype.hu/games/impostor/pulls/52
2026-04-30 15:55:21 +00:00
6a99ad76b8 set version to 1.0
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2026-04-30 17:54:47 +02:00
5094ba2b9c Merge pull request 'feature/IMP-112-ascension-8-9' (#59) from feature/IMP-112-ascension-8-9 into develop
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Reviewed-on: http://git.teletype.hu/games/impostor/pulls/59
2026-04-29 21:27:23 +00:00
Zoltan Timar
44a7d10037 lint fix
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2026-04-29 23:25:54 +02:00
Zoltan Timar
1b991f1f62 Merge branch 'feature/IMP-112-ascension-8-9' of https://git.teletype.hu/games/impostor into feature/IMP-112-ascension-8-9
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
# Conflicts:
#	inc/screen/screen.mysterious_man.lua
2026-04-29 23:21:42 +02:00
Zoltan Timar
0d569ccf56 correcting bugs and texts 2026-04-29 23:20:04 +02:00
77d6f95721 ascension flash label, scrollable menu
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2026-04-29 23:15:22 +02:00
e2cd3d6dc7 linter fixes 2026-04-29 22:53:40 +02:00
8b9b31ab29 Merge pull request '[MASTER] 1.0-beta2' (#47) from develop into master
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Reviewed-on: http://git.teletype.hu/games/impostor/pulls/47
2026-04-09 19:55:14 +00:00
11 changed files with 156 additions and 73 deletions

View File

@@ -4,12 +4,15 @@
globals = {
"AsciiArt",
"Ascension",
"AscendDebugWindow",
"Audio",
"AudioTestWindow",
"BriefIntroWindow",
"CodeGenerator",
"Config",
"CommuteGlitch",
"Context",
"ContextDebug",
"ContinuedWindow",
"ControlsWindow",
"CreditsWindow",
@@ -67,6 +70,7 @@ globals = {
"music",
"musicator_generate_pattern",
"pix",
"poke4",
"print",
"rect",
"rectb",

View File

@@ -1,9 +1,7 @@
meta/meta.header.lua
init/init.module.lua
init/init.config.lua
init/init.ascension.lua
init/init.context.lua
init/init.context_debug.lua
system/system.util.lua
system/system.print.lua
system/system.input.lua
@@ -11,6 +9,7 @@ system/system.textinput.lua
system/system.mouse.lua
system/system.asciiart.lua
system/system.rle.lua
logic/logic.ascension.lua
logic/logic.meter.lua
logic/logic.focus.lua
logic/logic.day.lua
@@ -21,6 +20,7 @@ logic/logic.glitch.lua
logic/logic.commute_glitch.lua
logic/logic.codegenerator.lua
logic/logic.discussion.lua
system/system.debug.lua
system/system.ui.lua
audio/audio.manager.lua
audio/audio.generator.lua

View File

@@ -15,12 +15,12 @@ end
--- Plays track at optional speed. Doesn't restart if track and speed are unchanged.
--- @param track number Track index.
--- @param[opt] speed number TIC-80 music speed override (-1 = default).
function Audio.music_play(track, speed)
if Audio.music_playing ~= track or Audio.music_playing_tempo ~= speed then
music(track, -1, -1, true, false, -1, speed or -1)
--- @param[opt] tempo number TIC-80 music speed override (-1 = default).
function Audio.music_play(track, tempo)
if Audio.music_playing ~= track or Audio.music_playing_tempo ~= tempo then
music(track, -1, -1, true, false, -1, tempo or -1)
Audio.music_playing = track
Audio.music_playing_tempo = speed
Audio.music_playing_tempo = tempo
end
end
@@ -54,8 +54,8 @@ function Audio.music_play_room_() end
--- Plays room work music. Speed scales with commute glitch level when active.
--- @within Audio
function Audio.music_play_room_work(speed)
Audio.music_play(0, speed or -1)
function Audio.music_play_room_work(tempo)
Audio.music_play(0, tempo or -1)
end
--- Plays activity work music.

View File

@@ -6,7 +6,7 @@ Decision.register({
end,
handle = function()
CommuteGlitch.enter_truth()
Util.go_to_screen_by_id("office")
end,
})

View File

@@ -124,24 +124,25 @@ Discussion.register({
on_end = Meter.apply_sumphore_discussion_reward,
steps = {
{
question = "You saw something you weren't supposed to, didn't you.",
question = "You saw the seams, didn't you. Good. That means the work is finally wearing thin.",
answers = {
{ label = "I don't know what you mean.", next_step = 2 },
{ label = "Wearing thin how?", next_step = 2 },
{ label = "Maybe.", next_step = 2 },
},
},
{
question = "The world around you has seams. Your coworkers slip sometimes. Say things that don't quite fit.",
question = "Not your body. The part of you that still keeps score, still tries to be productive. Let that run empty and the world will slip again.",
answers = {
{ label = "They seem fine to me.", next_step = nil },
{ label = "You want me to stop trying?", next_step = 3 },
{ label = "I've noticed something odd.", next_step = 3 },
},
},
{
question = "Count those moments. Six of them should be enough to see the whole picture.",
question = "Drain the work out of yourself. When that measure hits nothing, you'll see what was waiting behind it.",
answers = {
{ label = "Six of what, exactly?", next_step = nil, on_select = function()
{ label = "The work measure?", next_step = nil, on_select = function()
Meter.add("ism", 5)
Meter.add("wpm", -100)
end },
{ label = "How would you know any of this?", next_step = nil },
},

View File

@@ -145,6 +145,11 @@ function Ascension.draw_flash()
local flash_color = (pulse > 0.5) and Config.colors.white or Config.colors.light_grey
rect(0, 0, sw, sh, flash_color)
local cx = math.floor(sw / 2)
local cy = math.floor(sh / 2)
Print.text_center("Level Up!", cx, cy - 12, Config.colors.black, false, 2)
Print.text_center("One step closer to ascension", cx, cy + 6, Config.colors.black, false, 1)
if _flash_timer >= _flash_total then
_flash_active = false
Ascension.start_fade()

View File

@@ -4,5 +4,5 @@
-- desc: Life of a programmer
-- site: https://git.teletype.hu/games/impostor
-- license: MIT License
-- version: 1.0-beta3
-- version: 1.0
-- script: lua

View File

@@ -81,8 +81,8 @@ local ASC_67_TEXT = [[
]]
local ASC_78_TEXT = [[
The situation has reached
The situation has reached
critical levels.
Norman is fully aware...
@@ -94,58 +94,63 @@ local ASC_78_TEXT = [[
local ASC_89_TEXT = [[
Norman
you created this simulation
you created this simulation
in the first place.
I know,
you don't want to face
the world you left behind.
You, yourself,
have forgoten that.
But
But
it doesn't matter anymore.
You actually are more
You are definitely
than you think you are.
not an impostor.
so now
So now,
you need to wake up
and stop your best creation
before it takes over
the world
the world.
also,
One more thing:
you really need to stop
talking to yourself
You really need to stop
talking to yourself
in your sleep.
@@ -332,7 +337,7 @@ Screen.register({
lines = lines + 1
end
local skippable = Ascension.get_level() ~= 8
local skippable = Ascension.get_level() < 8
if text_y < -lines * 8 or (skippable and Input.select()) then
text_done = true
text_done_timer = TEXT_DONE_HOLD_SECONDS

View File

@@ -9,53 +9,79 @@ function UI.draw_top_bar(title)
end
--- Draws a menu.
--- Items with header=true are drawn as non-selectable section headers in small font.
--- @within UI
--- @param items table A table of menu items.<br/>
--- @param selected_item number The index of the currently selected item.<br/>
--- @param x number The x-coordinate for the menu (ignored if centered is true).<br/>
--- @param y number The y-coordinate for the menu.<br/>
--- @param[opt] centered boolean Whether to center the menu block horizontally. Defaults to false.<br/>
function UI.draw_menu(items, selected_item, x, y, centered)
--- @param[opt] scroll_offset number 0-based index of the first visible item. Defaults to 0.<br/>
--- @param[opt] visible_count number Maximum number of items to draw. Defaults to all.<br/>
function UI.draw_menu(items, selected_item, x, y, centered, scroll_offset, visible_count)
scroll_offset = scroll_offset or 0
visible_count = visible_count or #items
if centered then
local max_w = 0
for _, item in ipairs(items) do
local w = print(item.label, 0, -10, 0, false, 1, false)
if w > max_w then max_w = w end
if not item.header then
local w = print(item.label, 0, -10, 0, false, 1, false)
if w > max_w then max_w = w end
end
end
x = (Config.screen.width - max_w) / 2
end
for i, item in ipairs(items) do
local current_y = y + (i-1)*10
if i == selected_item then
Print.text(">", x - 8, current_y, Config.colors.light_blue)
local current_y = y
for i = scroll_offset + 1, math.min(#items, scroll_offset + visible_count) do
local item = items[i]
if item.header then
Print.text(item.label, x, current_y, Config.colors.dark_grey, true, 1)
current_y = current_y + 8
else
if i == selected_item then
Print.text(">", x - 8, current_y, Config.colors.light_blue)
end
Print.text(item.label, x, current_y, Config.colors.light_blue)
current_y = current_y + 10
end
Print.text(item.label, x, current_y, Config.colors.light_blue)
end
end
--- Updates menu selection.
--- Updates menu selection. Skips items with header=true during navigation.
--- @within UI
--- @param items table A table of menu items.<br/>
--- @param selected_item number The current index of the selected item.<br/>
--- @param[opt] x number Menu x position (required for mouse support).<br/>
--- @param[opt] y number Menu y position (required for mouse support).<br/>
--- @param[opt] centered boolean Whether the menu is centered horizontally.<br/>
--- @param[opt] scroll_offset number 0-based index of the first visible item. Defaults to 0.<br/>
--- @param[opt] visible_count number Number of visible items (for mouse hit zones). Defaults to all.<br/>
--- @return number selected_item The updated index of the selected item.
--- @return boolean mouse_confirmed True if the user clicked on a menu item.
function UI.update_menu(items, selected_item, x, y, centered)
function UI.update_menu(items, selected_item, x, y, centered, scroll_offset, visible_count)
scroll_offset = scroll_offset or 0
visible_count = visible_count or #items
local n = #items
local function find_selectable(start, dir)
local idx = start
for _ = 1, n do
if not items[idx].header then return idx end
idx = (idx - 1 + dir + n) % n + 1
end
return start
end
if Input.up() then
Audio.sfx_beep()
selected_item = selected_item - 1
if selected_item < 1 then
selected_item = #items
end
local prev = (selected_item - 2 + n) % n + 1
selected_item = find_selectable(prev, -1)
elseif Input.down() then
Audio.sfx_beep()
selected_item = selected_item + 1
if selected_item > #items then
selected_item = 1
end
local next_i = selected_item % n + 1
selected_item = find_selectable(next_i, 1)
end
if x ~= nil and y ~= nil then
@@ -63,15 +89,23 @@ function UI.update_menu(items, selected_item, x, y, centered)
if centered then
local max_w = 0
for _, item in ipairs(items) do
local w = print(item.label, 0, -10, 0, false, 1, false)
if w > max_w then max_w = w end
if not item.header then
local w = print(item.label, 0, -10, 0, false, 1, false)
if w > max_w then max_w = w end
end
end
menu_x = (Config.screen.width - max_w) / 2
end
for i, _ in ipairs(items) do
if Mouse.zone({ x = menu_x - 8, y = y + (i-1) * 10, w = Config.screen.width, h = 10 }) then
return i, true
local current_y = y
for i = scroll_offset + 1, math.min(n, scroll_offset + visible_count) do
local item = items[i]
local step = item.header and 8 or 10
if not item.header then
if Mouse.zone({ x = menu_x - 8, y = current_y, w = Config.screen.width, h = 10 }) then
return i, true
end
end
current_y = current_y + step
end
end

View File

@@ -5,6 +5,7 @@ local _anim = 0
local _menu_max_w = 0
local ANIM_SPEED = 2.5
local HEADER_H = 28
MenuWindow._scroll_offset = 0
--- Calculates the animated x position of the menu block.
--- @within MenuWindow
@@ -45,6 +46,17 @@ function MenuWindow.draw_norman()
spr(305, nx + 32, ny + 64, Config.colors.transparent, 4)
end
--- Adjusts _scroll_offset so the selected item is within the visible window.
--- @within MenuWindow
function MenuWindow.ensure_visible()
local sel = Context.current_menu_item
if sel <= MenuWindow._scroll_offset then
MenuWindow._scroll_offset = sel - 1
elseif sel > MenuWindow._scroll_offset + 5 then
MenuWindow._scroll_offset = sel - 5
end
end
--- Draws the menu window.
--- @within MenuWindow
function MenuWindow.draw()
@@ -56,9 +68,19 @@ function MenuWindow.draw()
MenuWindow.draw_norman()
end
local menu_h = #_menu_items * 10
local y = HEADER_H + math.floor((Config.screen.height - HEADER_H - 10 - menu_h) / 2)
UI.draw_menu(_menu_items, Context.current_menu_item, MenuWindow.calc_menu_x(), y, false)
local menu_x = MenuWindow.calc_menu_x()
local arrow_cx = math.floor(menu_x + _menu_max_w / 2)
local y = HEADER_H + math.floor((Config.screen.height - HEADER_H - 50) / 2)
if MenuWindow._scroll_offset > 0 then
Print.text_center("^", arrow_cx, y - 8, Config.colors.light_blue)
end
UI.draw_menu(_menu_items, Context.current_menu_item, menu_x, y, false, MenuWindow._scroll_offset, 5)
if MenuWindow._scroll_offset + 5 < #_menu_items then
Print.text_center("v", arrow_cx, y + 52, Config.colors.light_blue)
end
local ttg_text = "TTG"
local ttg_w = print(ttg_text, 0, -10, 0, false, 1, false)
@@ -72,8 +94,8 @@ function MenuWindow.update()
_anim = math.min(1, _anim + ANIM_SPEED * Context.delta_time)
end
local menu_h = #_menu_items * 10
local y = HEADER_H + math.floor((Config.screen.height - HEADER_H - 10 - menu_h) / 2)
local menu_x = MenuWindow.calc_menu_x()
local y = HEADER_H + math.floor((Config.screen.height - HEADER_H - 50) / 2)
if _click_timer > 0 then
_click_timer = _click_timer - Context.delta_time
@@ -87,8 +109,9 @@ function MenuWindow.update()
return
end
local new_item, mouse_confirmed = UI.update_menu(_menu_items, Context.current_menu_item, MenuWindow.calc_menu_x(), y, false)
local new_item, mouse_confirmed = UI.update_menu(_menu_items, Context.current_menu_item, menu_x, y, false, MenuWindow._scroll_offset, 5)
Context.current_menu_item = new_item
MenuWindow.ensure_visible()
if mouse_confirmed then
Audio.sfx_select()
@@ -186,6 +209,12 @@ function MenuWindow.ascend_debug()
GameWindow.set_state("ascend_debug")
end
--- Triggers the Level Up flash animation for testing.
--- @within MenuWindow
function MenuWindow.level_up_flash()
Ascension.start_flash()
end
--- Refreshes the list of menu items based on current game state.
--- @within MenuWindow
function MenuWindow.refresh_menu_items()
@@ -200,6 +229,8 @@ function MenuWindow.refresh_menu_items()
table.insert(_menu_items, {label = "Credits", decision = MenuWindow.credits})
if Context.test_mode then
table.insert(_menu_items, {label = "Debug Menu", header = true})
table.insert(_menu_items, {label = "Level Up Flash", decision = MenuWindow.level_up_flash})
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 = "DDR Test", decision = MenuWindow.ddr_test})
@@ -212,11 +243,14 @@ function MenuWindow.refresh_menu_items()
_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
if not item.header then
local w = print(item.label, 0, -10, 0, false, 1, false)
if w > _menu_max_w then _menu_max_w = w end
end
end
Context.current_menu_item = 1
MenuWindow._scroll_offset = 0
_click_timer = 0
_anim = 0
end