Compare commits

...

7 Commits

Author SHA1 Message Date
9ae6c12582 sprite handling
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/pr/woodpecker Pipeline was successful
ci/woodpecker/pull_request_closed/woodpecker Pipeline was successful
2026-02-21 23:12:46 +01:00
4e35cd4bd3 Merge pull request 'situation handling' (#9) from feature/situation-handling into master
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Reviewed-on: http://git.teletype.hu/games/impostor/pulls/9
2026-02-21 21:34:10 +00:00
ed2354b0fa situation handling
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/pr/woodpecker Pipeline was successful
ci/woodpecker/pull_request_closed/woodpecker Pipeline was successful
2026-02-21 22:33:24 +01:00
7854dc8a9f situation handling
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2026-02-21 22:33:01 +01:00
3b9b67e2fa Merge pull request 'remove manager postfixes' (#8) from feature-remove-manager-postfixes into master
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Reviewed-on: http://git.teletype.hu/games/impostor/pulls/8
2026-02-21 20:36:29 +00:00
1a4565428d remove manager postfixes
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/pr/woodpecker Pipeline was successful
ci/woodpecker/pull_request_closed/woodpecker Pipeline was successful
2026-02-21 21:35:48 +01:00
f02bb75e4f Merge pull request 'feat/imp-28-context-minigame-meter-table' (#7) from feat/imp-28-context-minigame-meter-table into master
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Reviewed-on: http://git.teletype.hu/games/impostor/pulls/7
2026-02-18 22:24:11 +00:00
27 changed files with 199 additions and 45 deletions

View File

@@ -3,19 +3,24 @@
globals = { globals = {
"Util", "Util",
"DecisionManager", "Decision",
"ScreenManager", "Situation",
"Screen",
"Sprite",
"UI", "UI",
"Print", "Print",
"Input", "Input",
"Audio", "Audio",
"Context", "Context",
"Meters",
"Minigames",
"mset", "mset",
"mget", "mget",
"btnp", "btnp",
"keyp", "keyp",
"music", "music",
"sfx", "sfx",
"spr",
"rect", "rect",
"rectb", "rectb",
"circ", "circ",
@@ -30,7 +35,7 @@ globals = {
"exit", "exit",
"trace", "trace",
"index_menu", "index_menu",
"MapManager", "Map",
"map", "map",
} }

View File

@@ -5,7 +5,12 @@ init/init.minigames.lua
init/init.meters.lua init/init.meters.lua
system/system.util.lua system/system.util.lua
init/init.windows.lua init/init.windows.lua
sprite/sprite.manager.lua
sprite/sprite.norman.lua
situation/situation.manager.lua
situation/situation.drink_coffee.lua
decision/decision.manager.lua decision/decision.manager.lua
decision/decision.have_a_coffee.lua
decision/decision.go_to_home.lua decision/decision.go_to_home.lua
decision/decision.go_to_toilet.lua decision/decision.go_to_toilet.lua
decision/decision.go_to_walking_to_office.lua decision/decision.go_to_walking_to_office.lua

View File

@@ -1,4 +1,4 @@
DecisionManager.register({ Decision.register({
id = "go_to_home", id = "go_to_home",
label = "Go to Home", label = "Go to Home",
handle = function() handle = function()

View File

@@ -1,4 +1,4 @@
DecisionManager.register({ Decision.register({
id = "go_to_office", id = "go_to_office",
label = "Go to Office", label = "Go to Office",
handle = function() handle = function()

View File

@@ -1,4 +1,4 @@
DecisionManager.register({ Decision.register({
id = "go_to_toilet", id = "go_to_toilet",
label = "Go to Toilet", label = "Go to Toilet",
handle = function() handle = function()

View File

@@ -1,4 +1,4 @@
DecisionManager.register({ Decision.register({
id = "go_to_walking_to_home", id = "go_to_walking_to_home",
label = "Walking to home", label = "Walking to home",
handle = function() handle = function()

View File

@@ -1,4 +1,4 @@
DecisionManager.register({ Decision.register({
id = "go_to_walking_to_office", id = "go_to_walking_to_office",
label = "Walking to office", label = "Walking to office",
handle = function() handle = function()

View File

@@ -0,0 +1,8 @@
Decision.register({
id = "have_a_coffee",
label = "Have a Coffee",
handle = function()
Situation.apply("drink_coffee")
end,
condition = function() return true end
})

View File

@@ -1,6 +1,6 @@
local _decisions = {} local _decisions = {}
function DecisionManager.register(decision) function Decision.register(decision)
if not decision or not decision.id then if not decision or not decision.id then
PopupWindow.show({"Error: Invalid decision object registered (missing id)!"}) PopupWindow.show({"Error: Invalid decision object registered (missing id)!"})
return return
@@ -22,10 +22,10 @@ function DecisionManager.register(decision)
_decisions[decision.id] = decision _decisions[decision.id] = decision
end end
function DecisionManager.get(id) function Decision.get(id)
return _decisions[id] return _decisions[id]
end end
function DecisionManager.get_all() function Decision.get_all()
return _decisions return _decisions
end end

View File

@@ -1,4 +1,4 @@
DecisionManager.register({ Decision.register({
id = "play_button_mash", id = "play_button_mash",
label = "Play Button Mash", label = "Play Button Mash",
handle = function() Meters.hide() MinigameButtonMashWindow.start(WINDOW_GAME) end, handle = function() Meters.hide() MinigameButtonMashWindow.start(WINDOW_GAME) end,

View File

@@ -1,4 +1,4 @@
DecisionManager.register({ Decision.register({
id = "play_ddr", id = "play_ddr",
label = "Play DDR (Random)", label = "Play DDR (Random)",
handle = function() Meters.hide() MinigameDDRWindow.start(WINDOW_GAME, nil) end, handle = function() Meters.hide() MinigameDDRWindow.start(WINDOW_GAME, nil) end,

View File

@@ -1,4 +1,4 @@
DecisionManager.register({ Decision.register({
id = "play_rhythm", id = "play_rhythm",
label = "Play Rhythm Game", label = "Play Rhythm Game",
handle = function() Meters.hide() MinigameRhythmWindow.start(WINDOW_GAME) end, handle = function() Meters.hide() MinigameRhythmWindow.start(WINDOW_GAME) end,

View File

@@ -45,7 +45,9 @@ on than meets the eye.]]
minigame_ddr = Minigames.get_default_ddr(), minigame_ddr = Minigames.get_default_ddr(),
minigame_button_mash = Minigames.get_default_button_mash(), minigame_button_mash = Minigames.get_default_button_mash(),
minigame_rhythm = Minigames.get_default_rhythm(), minigame_rhythm = Minigames.get_default_rhythm(),
meters = Meters.get_initial() meters = Meters.get_initial(),
sprites = {},
current_situation = nil,
} }
end end
@@ -67,7 +69,7 @@ local function reset_context_to_initial_state()
Context.screen_indices_by_id = {} Context.screen_indices_by_id = {}
local screen_order = {"home", "toilet", "walking_to_office", "office", "walking_to_home"} local screen_order = {"home", "toilet", "walking_to_office", "office", "walking_to_home"}
for i, screen_id in ipairs(screen_order) do for i, screen_id in ipairs(screen_order) do
local screen_data = ScreenManager.get_by_id(screen_id) local screen_data = Screen.get_by_id(screen_id)
if screen_data then if screen_data then
table.insert(Context.screens, screen_data) table.insert(Context.screens, screen_data)
Context.screen_indices_by_id[screen_id] = i Context.screen_indices_by_id[screen_id] = i

View File

@@ -11,11 +11,12 @@ local MinigameDDRWindow = {}
Util = {} Util = {}
Meters = {} Meters = {}
Minigames = {} Minigames = {}
DecisionManager = {} Decision = {}
ScreenManager = {} Situation = {}
MapManager = {} Screen = {}
Map = {}
UI = {} UI = {}
Print = {} Print = {}
Input = {} Input = {}
Sprite = {}
Audio = {} Audio = {}

View File

@@ -1,4 +1,4 @@
MapManager.register({ Map.register({
id = "bedroom", id = "bedroom",
from_x = 0, from_x = 0,
from_y = 0, from_y = 0,

View File

@@ -1,6 +1,6 @@
local _maps = {} local _maps = {}
function MapManager.get_maps_array() function Map.get_maps_array()
local maps_array = {} local maps_array = {}
for _, map_data in pairs(_maps) do for _, map_data in pairs(_maps) do
table.insert(maps_array, map_data) table.insert(maps_array, map_data)
@@ -8,19 +8,19 @@ function MapManager.get_maps_array()
return maps_array return maps_array
end end
function MapManager.register(map_data) function Map.register(map_data)
if _maps[map_data.id] then if _maps[map_data.id] then
trace("Warning: Overwriting map with id: " .. map_data.id) trace("Warning: Overwriting map with id: " .. map_data.id)
end end
_maps[map_data.id] = map_data _maps[map_data.id] = map_data
end end
function MapManager.get_by_id(map_id) function Map.get_by_id(map_id)
return _maps[map_id] return _maps[map_id]
end end
function MapManager.draw(map_id) function Map.draw(map_id)
local map_data = MapManager.get_by_id(map_id) local map_data = Map.get_by_id(map_id)
if not map_data then if not map_data then
return return
end end

View File

@@ -1,4 +1,4 @@
ScreenManager.register({ Screen.register({
id = "home", id = "home",
name = "Home", name = "Home",
decisions = { decisions = {

View File

@@ -1,20 +1,15 @@
local _screens = {} local _screens = {}
function ScreenManager.get_screens_array() function Screen.register(screen_data)
local screens_array = {}
for _, screen_data in pairs(_screens) do
table.insert(screens_array, screen_data)
end
return screens_array
end
function ScreenManager.register(screen_data)
if _screens[screen_data.id] then if _screens[screen_data.id] then
trace("Warning: Overwriting screen with id: " .. screen_data.id) trace("Warning: Overwriting screen with id: " .. screen_data.id)
end end
if not screen_data.situations then
screen_data.situations = {}
end
_screens[screen_data.id] = screen_data _screens[screen_data.id] = screen_data
end end
function ScreenManager.get_by_id(screen_id) function Screen.get_by_id(screen_id)
return _screens[screen_id] return _screens[screen_id]
end end

View File

@@ -1,4 +1,4 @@
ScreenManager.register({ Screen.register({
id = "office", id = "office",
name = "Office", name = "Office",
decisions = { decisions = {
@@ -6,5 +6,9 @@ ScreenManager.register({
"play_rhythm", "play_rhythm",
"play_ddr", "play_ddr",
"go_to_walking_to_home", "go_to_walking_to_home",
} "have_a_coffee",
},
situations = {
"drink_coffee",
},
}) })

View File

@@ -1,4 +1,4 @@
ScreenManager.register({ Screen.register({
id = "toilet", id = "toilet",
name = "Toilet", name = "Toilet",
decisions = { decisions = {

View File

@@ -1,4 +1,4 @@
ScreenManager.register({ Screen.register({
id = "walking_to_home", id = "walking_to_home",
name = "Walking to home", name = "Walking to home",
decisions = { decisions = {

View File

@@ -1,4 +1,4 @@
ScreenManager.register({ Screen.register({
id = "walking_to_office", id = "walking_to_office",
name = "Walking to office", name = "Walking to office",
decisions = { decisions = {

View File

@@ -0,0 +1,7 @@
Situation.register({
id = "drink_coffee",
handle = function()
Audio.sfx_select()
Sprite.show("norman", 100, 100)
end,
})

View File

@@ -0,0 +1,37 @@
local _situations = {}
function Situation.register(situation)
if not situation or not situation.id then
PopupWindow.show({"Error: Invalid situation object registered (missing id)!"})
return
end
if not situation.handle then
situation.handle = function() end
end
if _situations[situation.id] then
trace("Warning: Overwriting situation with id: " .. situation.id)
end
_situations[situation.id] = situation
end
function Situation.get(id)
return _situations[id]
end
function Situation.apply(id)
local situation = Situation.get(id)
if not situation then
trace("Error: No situation found with id: " .. id)
return
end
local current_screen_obj = Screen.get_by_id(Context.current_screen)
if current_screen_obj and not current_screen_obj.situations[id] then
trace("Info: Situation " .. id .. " cannot be applied to current screen (id: " .. Context.current_screen .. ").")
return
end
Context.current_situation = id
situation.handle()
end

View File

@@ -0,0 +1,72 @@
local _sprites = {}
function Sprite.register(sprite_data)
if not sprite_data or not sprite_data.id then
trace("Error: Invalid sprite object registered (missing id)!")
return
end
if _sprites[sprite_data.id] then
trace("Warning: Overwriting sprite with id: " .. sprite_data.id)
end
_sprites[sprite_data.id] = sprite_data
end
function Sprite.show(id, x, y, colorkey, scale, flip_x, flip_y, rot)
-- Ensure the sprite exists before attempting to show it
if not _sprites[id] then
trace("Error: Attempted to show non-registered sprite with id: " .. id)
return
end
Context.sprites[id] = {
id = id,
x = x,
y = y,
colorkey = colorkey,
scale = scale,
flip_x = flip_x,
flip_y = flip_y,
rot = rot,
}
end
function Sprite.hide(id)
Context.sprites[id] = nil
end
function Sprite.draw()
for id, params in pairs(Context.sprites) do
local sprite_data = _sprites[id]
if not sprite_data then
trace("Error: Sprite id " .. id .. " in Context.sprites is not registered.")
Context.sprites[id] = nil -- Clean up invalid entry
-- We should probably continue to the next sprite instead of returning
-- so that other valid sprites can still be drawn.
end
-- Use parameters from Context.sprites, or fall back to sprite_data, then to defaults
local colorkey = params.colorkey or sprite_data.colorkey or 0
local scale = params.scale or sprite_data.scale or 1
local flip_x = params.flip_x or sprite_data.flip_x or 0
local flip_y = params.flip_y or sprite_data.flip_y or 0
local rot = params.rot or sprite_data.rot or 0
if sprite_data.sprites then -- Complex sprite
for i = 1, #sprite_data.sprites do
local sub_sprite = sprite_data.sprites[i]
spr(
sub_sprite.s,
params.x + (sub_sprite.x_offset or 0),
params.y + (sub_sprite.y_offset or 0),
sub_sprite.colorkey or colorkey,
sub_sprite.scale or scale,
sub_sprite.flip_x or flip_x,
sub_sprite.flip_y or flip_y,
sub_sprite.rot or rot
)
end
else -- Simple sprite
spr(sprite_data.s, params.x, params.y, colorkey, scale, flip_x, flip_y, rot)
end
end
end

View File

@@ -0,0 +1,17 @@
Sprite.register({
id = "norman",
sprites = {
-- Body
{ s = 0, x_offset = 0, y_offset = 0 },
-- Head
{ s = 1, x_offset = 0, y_offset = -8 },
-- Left Arm
{ s = 2, x_offset = -4, y_offset = 4 },
-- Right Arm
{ s = 3, x_offset = 4, y_offset = 4, flip_x = 1 }, -- Flipped arm
-- Left Leg
{ s = 4, x_offset = -2, y_offset = 8 },
-- Right Leg
{ s = 5, x_offset = 2, y_offset = 8, flip_x = 1 } -- Flipped leg
}
})

View File

@@ -1,11 +1,11 @@
function GameWindow.draw() function GameWindow.draw()
local screen = Context.screens[Context.current_screen] local screen = Context.screens[Context.current_screen]
MapManager.draw(screen.background) Map.draw(screen.background)
UI.draw_top_bar(screen.name) UI.draw_top_bar(screen.name)
if screen and screen.decisions and #screen.decisions > 0 then if screen and screen.decisions and #screen.decisions > 0 then
local available_decisions = {} local available_decisions = {}
for _, decision_id in ipairs(screen.decisions) do for _, decision_id in ipairs(screen.decisions) do
local decision = DecisionManager.get(decision_id) local decision = Decision.get(decision_id)
if decision and decision.condition() then if decision and decision.condition() then
table.insert(available_decisions, decision) table.insert(available_decisions, decision)
end end
@@ -14,6 +14,7 @@ function GameWindow.draw()
UI.draw_decision_selector(available_decisions, Context.selected_decision_index) UI.draw_decision_selector(available_decisions, Context.selected_decision_index)
end end
end end
Sprite.draw()
end end
function GameWindow.update() function GameWindow.update()
@@ -39,7 +40,7 @@ function GameWindow.update()
if screen and screen.decisions and #screen.decisions > 0 then if screen and screen.decisions and #screen.decisions > 0 then
local available_decisions = {} local available_decisions = {}
for _, decision_id in ipairs(screen.decisions) do for _, decision_id in ipairs(screen.decisions) do
local decision = DecisionManager.get(decision_id) local decision = Decision.get(decision_id)
if decision and decision.condition() then table.insert(available_decisions, decision) if decision and decision.condition() then table.insert(available_decisions, decision)
end end
end end