Compare commits

...

4 Commits

Author SHA1 Message Date
787b6656b0 docs
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2026-02-21 23:53:36 +01:00
3b137fd48e docs make target 2026-02-21 23:44:03 +01:00
0b25ecc793 set window objects to global
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2026-02-21 23:18:42 +01:00
f08e4ad1d4 Merge pull request 'sprite handling' (#10) from feature/sprite-handling into master
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Reviewed-on: http://git.teletype.hu/games/impostor/pulls/10
2026-02-21 22:13:31 +00:00
10 changed files with 138 additions and 21 deletions

View File

@@ -14,6 +14,16 @@ globals = {
"Context",
"Meters",
"Minigames",
"SplashWindow",
"IntroWindow",
"MenuWindow",
"GameWindow",
"PopupWindow",
"ConfigurationWindow",
"AudioTestWindow",
"MinigameButtonMashWindow",
"MinigameRhythmWindow",
"MinigameDDRWindow",
"mset",
"mget",
"btnp",

View File

@@ -204,7 +204,22 @@ install_precommit_hook:
@chmod +x .git/hooks/pre-commit
@echo "Pre-commit hook installed successfully."
.PHONY: all build export watch import_assets export_assets clean lint ci-version ci-export ci-upload ci-update install_precommit_hook
docs: build
@echo "==> Checking for ldoc..."
@if ! command -v ldoc &> /dev/null; then \
echo "ldoc not found, attempting to install with luarocks..."; \
if command -v luarocks &> /dev/null; then \
luarocks install ldoc; \
else \
echo "Error: luarocks not found. Please install luarocks and then ldoc manually."; \
exit 1; \
fi; \
fi
@echo "==> Running ldoc..."
@ldoc ${OUTPUT} -d docs
@echo "==> Documentation generated."
.PHONY: all build export watch import_assets export_assets clean lint ci-version ci-export ci-upload ci-update install_precommit_hook docs
#-- <WAVES>
#-- 000:224578acdeeeeddcba95434567653100

View File

@@ -46,7 +46,11 @@ on than meets the eye.]]
minigame_button_mash = Minigames.get_default_button_mash(),
minigame_rhythm = Minigames.get_default_rhythm(),
meters = Meters.get_initial(),
--- Table storing currently active sprites to be drawn.
-- Each entry is a table with `id`, `x`, `y`, and other drawing parameters.
sprites = {},
--- The ID of the currently active situation.
-- Set by `Situation.apply()` and `nil` if no situation is active.
current_situation = nil,
}
end

View File

@@ -1,13 +1,13 @@
local SplashWindow = {}
local IntroWindow = {}
local MenuWindow = {}
local GameWindow = {}
local PopupWindow = {}
local ConfigurationWindow = {}
local AudioTestWindow = {}
local MinigameButtonMashWindow = {}
local MinigameRhythmWindow = {}
local MinigameDDRWindow = {}
SplashWindow = {}
IntroWindow = {}
MenuWindow = {}
GameWindow = {}
PopupWindow = {}
ConfigurationWindow = {}
AudioTestWindow = {}
MinigameButtonMashWindow = {}
MinigameRhythmWindow = {}
MinigameDDRWindow = {}
Util = {}
Meters = {}
Minigames = {}

View File

@@ -1,5 +1,13 @@
local _screens = {}
--- Registers a new screen definition with the Screen manager.
-- Overwrites existing screen if an ID conflict occurs.
-- @param screen_data table A table containing the screen definition.
-- Must include an `id` field (string).
-- Optional fields:
-- - `situations` (table): A table of situation IDs allowed on this screen. Defaults to an empty table.
-- - `init` (function): Function to execute once when the screen becomes active. Defaults to an empty function.
-- - `update` (function): Function to execute each frame while the screen is active. Defaults to an empty function.
function Screen.register(screen_data)
if _screens[screen_data.id] then
trace("Warning: Overwriting screen with id: " .. screen_data.id)
@@ -7,9 +15,18 @@ function Screen.register(screen_data)
if not screen_data.situations then
screen_data.situations = {}
end
if not screen_data.init then
screen_data.init = function() end
end
if not screen_data.update then
screen_data.update = function() end
end
_screens[screen_data.id] = screen_data
end
--- Retrieves a registered screen by its ID.
-- @param screen_id string The ID of the screen to retrieve.
-- @return table The screen table, or `nil` if not found.
function Screen.get_by_id(screen_id)
return _screens[screen_id]
end

View File

@@ -1,5 +1,12 @@
local _situations = {}
--- Registers a new situation with the Situation manager.
-- Overwrites existing situation if an ID conflict occurs.
-- @param situation table A table containing the situation definition.
-- Must include an `id` field (string).
-- Optional fields:
-- - `handle` (function): Function to execute when the situation is applied. Defaults to an empty function.
-- - `update` (function): Function to execute each frame while the situation is active. Defaults to an empty function.
function Situation.register(situation)
if not situation or not situation.id then
PopupWindow.show({"Error: Invalid situation object registered (missing id)!"})
@@ -8,16 +15,28 @@ function Situation.register(situation)
if not situation.handle then
situation.handle = function() end
end
if not situation.update then
situation.update = function() end
end
if _situations[situation.id] then
trace("Warning: Overwriting situation with id: " .. situation.id)
end
_situations[situation.id] = situation
end
--- Retrieves a registered situation by its ID.
-- @param id string The ID of the situation to retrieve.
-- @return table The situation table, or `nil` if not found.
function Situation.get(id)
return _situations[id]
end
--- Applies a situation, making it the current active situation.
-- The situation's `handle` function is executed.
-- This function first checks if the situation is valid and if it's allowed
-- on the current screen (as defined in `Context.screens[Context.current_screen].situations`).
-- If successful, `Context.current_situation` is updated with the ID of the applied situation.
-- @param id string The ID of the situation to apply.
function Situation.apply(id)
local situation = Situation.get(id)
if not situation then
@@ -34,4 +53,3 @@ function Situation.apply(id)
Context.current_situation = id
situation.handle()
end

View File

@@ -1,5 +1,15 @@
local _sprites = {}
--- Registers a new sprite or complex sprite definition with the Sprite manager.
-- Overwrites existing sprite if an ID conflict occurs.
-- @param sprite_data table A table containing the sprite definition.
-- Must include an `id` field (string) and either an `s` field (number, for simple sprites)
-- or a `sprites` field (table, for complex sprites).
-- For complex sprites, `sprites` is a table of sub-sprite definitions, each with:
-- - `s` (number): Sprite index.
-- - `x_offset` (number): X-offset relative to the parent sprite's position.
-- - `y_offset` (number): Y-offset relative to the parent sprite's position.
-- - Optional `colorkey`, `scale`, `flip_x`, `flip_y`, `rot` for individual sub-sprites.
function Sprite.register(sprite_data)
if not sprite_data or not sprite_data.id then
trace("Error: Invalid sprite object registered (missing id)!")
@@ -11,6 +21,17 @@ function Sprite.register(sprite_data)
_sprites[sprite_data.id] = sprite_data
end
--- Schedules a registered sprite to be drawn at a specific position with optional transformations.
-- The sprite's parameters are stored in `Context.sprites` for deferred rendering by `Sprite.draw()`.
-- If the sprite with the given `id` is already scheduled, its parameters will be updated.
-- @param id string The unique identifier of the sprite to show. Must be registered via `Sprite.register`.
-- @param x number The x-coordinate on the screen where the sprite will be drawn.
-- @param y number The y-coordinate on the screen where the sprite will be drawn.
-- @param[opt] colorkey number The color index to be treated as transparent (default: 0).
-- @param[opt] scale number The scaling factor for the sprite (default: 1).
-- @param[opt] flip_x number Set to 1 to flip the sprite horizontally (default: 0).
-- @param[opt] flip_y number Set to 1 to flip the sprite vertically (default: 0).
-- @param[opt] rot number The rotation of the sprite in degrees (default: 0).
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
@@ -30,10 +51,16 @@ function Sprite.show(id, x, y, colorkey, scale, flip_x, flip_y, rot)
}
end
--- Hides a currently displayed sprite by removing it from the `Context.sprites` table.
-- The sprite will no longer be drawn in subsequent frames.
-- @param id string The unique identifier of the sprite to hide.
function Sprite.hide(id)
Context.sprites[id] = nil
end
--- Draws all sprites currently scheduled in `Context.sprites`.
-- This function retrieves the registered sprite definitions and applies the stored
-- position and transformation parameters. It handles both simple and complex sprites.
function Sprite.draw()
for id, params in pairs(Context.sprites) do
local sprite_data = _sprites[id]

View File

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

View File

@@ -1,3 +1,6 @@
--- Draws the main game window content.
-- This includes the current screen's background, top bar, decisions, and all active sprites.
-- @function GameWindow.draw
function GameWindow.draw()
local screen = Context.screens[Context.current_screen]
Map.draw(screen.background)
@@ -17,7 +20,13 @@ function GameWindow.draw()
Sprite.draw()
end
--- Updates the logic for the main game window.
-- Handles input, navigates between screens, calls the current screen's and situation's update functions,
-- and processes player decisions.
-- @function GameWindow.update
function GameWindow.update()
local previous_screen_index = Context.current_screen
if Input.menu_back() then
Context.active_window = WINDOW_MENU
MenuWindow.refresh_menu_items()
@@ -37,6 +46,19 @@ function GameWindow.update()
Context.selected_decision_index = 1 end
local screen = Context.screens[Context.current_screen]
screen.update()
if previous_screen_index ~= Context.current_screen then
screen.init()
end
if Context.current_situation then
local current_situation_obj = Situation.get(Context.current_situation)
if current_situation_obj and current_situation_obj.update then
current_situation_obj.update()
end
end
if screen and screen.decisions and #screen.decisions > 0 then
local available_decisions = {}
for _, decision_id in ipairs(screen.decisions) do
@@ -64,6 +86,10 @@ function GameWindow.update()
end
end
--- Sets the active window state for the game.
-- This function is typically called when transitioning between different game states (e.g., to a minigame).
-- @param new_state number The ID of the new active window (e.g., `WINDOW_MENU`, `WINDOW_GAME`).
-- @function GameWindow.set_state
function GameWindow.set_state(new_state)
Context.active_window = new_state
end
end