purge
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed

This commit is contained in:
2026-01-17 00:10:11 +01:00
parent b3158bdc37
commit 3fbce5aced
16 changed files with 29 additions and 371 deletions

View File

@@ -1,49 +1,7 @@
function Item.use()
Print.text("Used item: " .. Context.dialog.active_entity.name)
GameWindow.set_state(WINDOW_INVENTORY)
end
function Item.look_at()
PopupWindow.show_description_dialog(Context.dialog.active_entity, Context.dialog.active_entity.desc)
end
function Item.put_away()
-- Add item to inventory
table.insert(Context.inventory, Context.dialog.active_entity)
-- Remove item from screen
local currentScreenData = Context.screens[Context.current_screen]
for i, item in ipairs(currentScreenData.items) do
if item == Context.dialog.active_entity then
table.remove(currentScreenData.items, i)
break
end
end
-- Go back to game
GameWindow.set_state(WINDOW_GAME)
end
function Item.go_back_from_item_dialog()
GameWindow.set_state(WINDOW_GAME)
end
function Item.go_back_from_inventory_action()
GameWindow.set_state(WINDOW_GAME)
end
function Item.drop()
-- Remove item from inventory
for i, item in ipairs(Context.inventory) do
if item == Context.dialog.active_entity then
table.remove(Context.inventory, i)
break
end
end
-- Add item to screen
local currentScreenData = Context.screens[Context.current_screen]
Context.dialog.active_entity.x = Context.player.x
Context.dialog.active_entity.y = Context.player.y
table.insert(currentScreenData.items, Context.dialog.active_entity)
-- Go back to inventory
GameWindow.set_state(WINDOW_INVENTORY)
end

View File

@@ -1,98 +0,0 @@
function Player.draw()
spr(Context.player.sprite_id, Context.player.x, Context.player.y, 0)
end
function Player.update()
-- Handle input
if Input.left() then
Context.player.vx = -Config.physics.move_speed
elseif Input.right() then
Context.player.vx = Config.physics.move_speed
else
Context.player.vx = 0
end
if Input.player_jump() and Context.player.jumps < Config.physics.max_jumps then
Context.player.vy = Config.physics.jump_power
Context.player.jumps = Context.player.jumps + 1
end
-- Update player position
Context.player.x = Context.player.x + Context.player.vx
Context.player.y = Context.player.y + Context.player.vy
-- Screen transition
if Context.player.x > Config.screen.width - Context.player.w then
if Context.current_screen < #Context.screens then
Context.current_screen = Context.current_screen + 1
Context.player.x = 0
else
Context.player.x = Config.screen.width - Context.player.w
end
elseif Context.player.x < 0 then
if Context.current_screen > 1 then
Context.current_screen = Context.current_screen - 1
Context.player.x = Config.screen.width - Context.player.w
else
Context.player.x = 0
end
end
-- Apply gravity
Context.player.vy = Context.player.vy + Config.physics.gravity
local currentScreenData = Context.screens[Context.current_screen]
-- Collision detection with platforms
for _, p in ipairs(currentScreenData.platforms) do
if Context.player.vy > 0 and Context.player.y + Context.player.h >= p.y and Context.player.y + Context.player.h <= p.y + p.h and Context.player.x + Context.player.w > p.x and Context.player.x < p.x + p.w then
Context.player.y = p.y - Context.player.h
Context.player.vy = 0
Context.player.jumps = 0
end
end
-- Collision detection with ground
if Context.player.y + Context.player.h > Context.ground.y then
Context.player.y = Context.ground.y - Context.player.h
Context.player.vy = 0
Context.player.jumps = 0
end
-- Entity interaction
if Input.player_interact() then
local interaction_found = false
-- NPC interaction
for _, npc in ipairs(currentScreenData.npcs) do
if math.abs(Context.player.x - npc.x) < Config.physics.interaction_radius_npc and math.abs(Context.player.y - npc.y) < Config.physics.interaction_radius_npc then
PopupWindow.show_menu_dialog(npc, {
{label = "Talk to", action = NPC.talk_to},
{label = "Fight", action = NPC.fight},
{label = "Go back", action = NPC.go_back}
}, WINDOW_POPUP)
interaction_found = true
break
end
end
if not interaction_found then
-- Item interaction
for _, item in ipairs(currentScreenData.items) do
if math.abs(Context.player.x - item.x) < Config.physics.interaction_radius_item and math.abs(Context.player.y - item.y) < Config.physics.interaction_radius_item then
PopupWindow.show_menu_dialog(item, {
{label = "Use", action = Item.use},
{label = "Look at", action = Item.look_at},
{label = "Put away", action = Item.put_away},
{label = "Go back", action = Item.go_back_from_item_dialog}
}, WINDOW_POPUP)
interaction_found = true
break
end
end
end
-- If no interaction happened, open inventory
if not interaction_found then
GameWindow.set_state(WINDOW_INVENTORY)
end
end
end

View File

@@ -12,20 +12,8 @@ local DEFAULT_CONFIG = {
item = 12 -- yellow
},
player = {
w = 8,
h = 8,
start_x = 120,
start_y = 128,
sprite_id = 1
},
physics = {
gravity = 0.5,
jump_power = -5,
move_speed = 1.5,
max_jumps = 2,
interaction_radius_npc = 12,
interaction_radius_item = 8
},
timing = {
splash_duration = 120
}
@@ -36,36 +24,24 @@ local Config = {
screen = DEFAULT_CONFIG.screen,
colors = DEFAULT_CONFIG.colors,
player = DEFAULT_CONFIG.player,
physics = DEFAULT_CONFIG.physics,
timing = DEFAULT_CONFIG.timing,
}
local CONFIG_SAVE_BANK = 7
local CONFIG_SAVE_ADDRESS_MOVE_SPEED = 0
local CONFIG_SAVE_ADDRESS_MAX_JUMPS = 1
local CONFIG_MAGIC_VALUE_ADDRESS = 2
local CONFIG_MAGIC_VALUE = 0xDE -- A magic number to check if config is saved
function Config.save()
-- Save physics settings
mset(Config.physics.move_speed * 10, CONFIG_SAVE_ADDRESS_MOVE_SPEED, CONFIG_SAVE_BANK)
mset(Config.physics.max_jumps, CONFIG_SAVE_ADDRESS_MAX_JUMPS, CONFIG_SAVE_BANK)
mset(CONFIG_MAGIC_VALUE, CONFIG_MAGIC_VALUE_ADDRESS, CONFIG_SAVE_BANK) -- Mark as saved
end
function Config.load()
Config.restore_defaults()
-- Check if config has been saved before using a magic value
if mget(CONFIG_MAGIC_VALUE_ADDRESS, CONFIG_SAVE_BANK) == CONFIG_MAGIC_VALUE then
Config.physics.move_speed = mget(CONFIG_SAVE_ADDRESS_MOVE_SPEED, CONFIG_SAVE_BANK) / 10
Config.physics.max_jumps = mget(CONFIG_SAVE_ADDRESS_MAX_JUMPS, CONFIG_SAVE_BANK)
else
Config.restore_defaults()
end
end
function Config.restore_defaults()
Config.physics.move_speed = DEFAULT_CONFIG.physics.move_speed
Config.physics.max_jumps = DEFAULT_CONFIG.physics.max_jumps
-- Any other configurable items should be reset here
end

View File

@@ -6,7 +6,7 @@ local SAVE_GAME_PLAYER_X_ADDRESS = 1
local SAVE_GAME_PLAYER_Y_ADDRESS = 2
local SAVE_GAME_PLAYER_VX_ADDRESS = 3
local SAVE_GAME_PLAYER_VY_ADDRESS = 4
local SAVE_GAME_PLAYER_JUMPS_ADDRESS = 5
local SAVE_GAME_selectS_ADDRESS = 5
local SAVE_GAME_CURRENT_SCREEN_ADDRESS = 6
local VX_VY_OFFSET = 128 -- Offset for negative velocities
@@ -28,11 +28,10 @@ end
local function get_initial_data()
return {
active_window = WINDOW_SPLASH,
inventory = {},
intro = {
y = Config.screen.height,
speed = 0.5,
text = "Mr. Anderson is an average\nprogrammer. His daily life\nrevolves around debugging,\npull requests, and end-of-sprint\nmeetings, all while secretly\ndreaming of being destined\nfor something more."
text = "Norman Reds everyday life\nseems ordinary: work,\nmeetings, coffee, and\nendless notifications.\nBut beneath the surface\n— within him, or around\nhim — something is\nconstantly building, and\nit soon becomes clear\nthat there is more going\non than meets the eye."
},
current_screen = 1,
splash_timer = Config.timing.splash_duration,
@@ -45,13 +44,6 @@ local function get_initial_data()
current_node_key = nil
},
player = {
x = Config.player.start_x,
y = Config.player.start_y,
w = Config.player.w,
h = Config.player.h,
vx = 0,
vy = 0,
jumps = 0,
sprite_id = Config.player.sprite_id
},
ground = {
@@ -62,30 +54,13 @@ local function get_initial_data()
},
menu_items = {},
selected_menu_item = 1,
selected_inventory_item = 1,
game_in_progress = false, -- New flag
screens = clone_table({
{
-- Screen 1
name = "Screen 1",
platforms = {
{
x = 80,
y = 110,
w = 40,
h = 8
},
{
x = 160,
y = 90,
w = 40,
h = 8
}
},
npcs = {
{
x = 180,
y = 82,
name = "Trinity",
sprite_id = 2,
dialog = {
@@ -141,8 +116,6 @@ local function get_initial_data()
}
},
{
x = 90,
y = 102,
name = "Oracle",
sprite_id = 3,
dialog = {
@@ -202,10 +175,6 @@ local function get_initial_data()
},
items = {
{
x = 100,
y = 128,
w = 8,
h = 8,
name = "Key",
sprite_id = 4,
desc = "A rusty old key. It might open something."
@@ -215,30 +184,8 @@ local function get_initial_data()
{
-- Screen 2
name = "Screen 2",
platforms = {
{
x = 30,
y = 100,
w = 50,
h = 8
},
{
x = 100,
y = 80,
w = 50,
h = 8
},
{
x = 170,
y = 60,
w = 50,
h = 8
}
},
npcs = {
{
x = 120,
y = 72,
name = "Morpheus",
sprite_id = 5,
dialog = {
@@ -274,8 +221,6 @@ local function get_initial_data()
}
},
{
x = 40,
y = 92,
name = "Tank",
sprite_id = 6,
dialog = {
@@ -320,10 +265,6 @@ local function get_initial_data()
},
items = {
{
x = 180,
y = 52,
w = 8,
h = 8,
name = "Potion",
sprite_id = 7,
desc = "A glowing red potion. It looks potent."
@@ -333,36 +274,8 @@ local function get_initial_data()
{
-- Screen 3
name = "Screen 3",
platforms = {
{
x = 50,
y = 110,
w = 30,
h = 8
},
{
x = 100,
y = 90,
w = 30,
h = 8
},
{
x = 150,
y = 70,
w = 30,
h = 8
},
{
x = 200,
y = 50,
w = 30,
h = 8
}
},
npcs = {
{
x = 210,
y = 42,
name = "Agent Smith",
sprite_id = 8,
dialog = {
@@ -404,8 +317,6 @@ local function get_initial_data()
}
},
{
x = 160,
y = 62,
name = "Cypher",
sprite_id = 9,
dialog = {
@@ -492,11 +403,6 @@ function Context.save_game()
if not Context.game_in_progress then return end
mset(SAVE_GAME_MAGIC_VALUE, SAVE_GAME_MAGIC_VALUE_ADDRESS, SAVE_GAME_BANK)
mset(Context.player.x * 10, SAVE_GAME_PLAYER_X_ADDRESS, SAVE_GAME_BANK)
mset(Context.player.y * 10, SAVE_GAME_PLAYER_Y_ADDRESS, SAVE_GAME_BANK)
mset( (Context.player.vx * 100) + VX_VY_OFFSET, SAVE_GAME_PLAYER_VX_ADDRESS, SAVE_GAME_BANK)
mset( (Context.player.vy * 100) + VX_VY_OFFSET, SAVE_GAME_PLAYER_VY_ADDRESS, SAVE_GAME_BANK)
mset(Context.player.jumps, SAVE_GAME_PLAYER_JUMPS_ADDRESS, SAVE_GAME_BANK)
mset(Context.current_screen, SAVE_GAME_CURRENT_SCREEN_ADDRESS, SAVE_GAME_BANK)
end
@@ -509,11 +415,6 @@ function Context.load_game()
reset_context_to_initial_state() -- Reset data, preserve methods
Context.player.x = mget(SAVE_GAME_PLAYER_X_ADDRESS, SAVE_GAME_BANK) / 10
Context.player.y = mget(SAVE_GAME_PLAYER_Y_ADDRESS, SAVE_GAME_BANK) / 10
Context.player.vx = (mget(SAVE_GAME_PLAYER_VX_ADDRESS, SAVE_GAME_BANK) - VX_VY_OFFSET) / 100
Context.player.vy = (mget(SAVE_GAME_PLAYER_VY_ADDRESS, SAVE_GAME_BANK) - VX_VY_OFFSET) / 100
Context.player.jumps = mget(SAVE_GAME_PLAYER_JUMPS_ADDRESS, SAVE_GAME_BANK)
Context.current_screen = mget(SAVE_GAME_CURRENT_SCREEN_ADDRESS, SAVE_GAME_BANK)
Context.game_in_progress = true

View File

@@ -3,7 +3,6 @@ local IntroWindow = {}
local MenuWindow = {}
local GameWindow = {}
local PopupWindow = {}
local InventoryWindow = {}
local ConfigurationWindow = {}
local UI = {}

View File

@@ -3,6 +3,4 @@ local WINDOW_INTRO = 1
local WINDOW_MENU = 2
local WINDOW_GAME = 3
local WINDOW_POPUP = 4
local WINDOW_INVENTORY = 5
local WINDOW_INVENTORY_ACTION = 6
local WINDOW_CONFIGURATION = 7

View File

@@ -3,5 +3,5 @@
-- desc: Life of a programmer in the Vector
-- site: https://git.teletype.hu/games/impostor
-- license: MIT License
-- version: 0.15
-- version: 0.1
-- script: lua

View File

@@ -18,7 +18,7 @@ function Input.up() return btnp(INPUT_KEY_UP) end
function Input.down() return btnp(INPUT_KEY_DOWN) end
function Input.left() return btn(INPUT_KEY_LEFT) end
function Input.right() return btn(INPUT_KEY_RIGHT) end
function Input.player_jump() return btnp(INPUT_KEY_A) or keyp(INPUT_KEY_SPACE) end
function Input.select() return btnp(INPUT_KEY_A) or keyp(INPUT_KEY_SPACE) end
function Input.menu_confirm() return btnp(INPUT_KEY_A) or keyp(INPUT_KEY_ENTER) end
function Input.player_interact() return btnp(INPUT_KEY_B) or keyp(INPUT_KEY_ENTER) end -- B button
function Input.menu_back() return btnp(INPUT_KEY_Y) or keyp(INPUT_KEY_BACKSPACE) end

View File

@@ -20,15 +20,6 @@ local STATE_HANDLERS = {
PopupWindow.update()
PopupWindow.draw()
end,
[WINDOW_INVENTORY] = function()
InventoryWindow.update()
InventoryWindow.draw()
end,
[WINDOW_INVENTORY_ACTION] = function()
InventoryWindow.draw()
PopupWindow.draw()
PopupWindow.update()
end,
[WINDOW_CONFIGURATION] = function()
ConfigurationWindow.update()
ConfigurationWindow.draw()
@@ -37,7 +28,7 @@ local STATE_HANDLERS = {
local initialized_game = false
function init_game()
local function init_game()
if initialized_game then return end
MenuWindow.refresh_menu_items()
@@ -45,7 +36,7 @@ function init_game()
end
function TIC()
init_game()
init_game()
cls(Config.colors.black)
local handler = STATE_HANDLERS[Context.active_window]

View File

@@ -5,18 +5,6 @@ ConfigurationWindow = {
function ConfigurationWindow.init()
ConfigurationWindow.controls = {
UI.create_numeric_stepper(
"Move Speed",
function() return Config.physics.move_speed end,
function(v) Config.physics.move_speed = v end,
0.5, 3, 0.1, "%.1f"
),
UI.create_numeric_stepper(
"Max Jumps",
function() return Config.physics.max_jumps end,
function(v) Config.physics.max_jumps = v end,
1, 5, 1, "%d"
),
UI.create_action_item(
"Save",
function() Config.save() end

View File

@@ -2,27 +2,6 @@ function GameWindow.draw()
local currentScreenData = Context.screens[Context.current_screen]
UI.draw_top_bar(currentScreenData.name)
-- Draw platforms
for _, p in ipairs(currentScreenData.platforms) do
rect(p.x, p.y, p.w, p.h, Config.colors.green)
end
-- Draw items
for _, item in ipairs(currentScreenData.items) do
spr(item.sprite_id, item.x, item.y, 0)
end
-- Draw NPCs
for _, npc in ipairs(currentScreenData.npcs) do
spr(npc.sprite_id, npc.x, npc.y, 0)
end
-- Draw ground
rect(Context.ground.x, Context.ground.y, Context.ground.w, Context.ground.h, Config.colors.dark_grey)
-- Draw player
Player.draw()
end
function GameWindow.update()
@@ -31,7 +10,21 @@ function GameWindow.update()
MenuWindow.refresh_menu_items()
return
end
Player.update() -- Call the encapsulated player update logic
if Input.select() then
if Context.current_screen == #Context.screens then
Context.current_screen = 1
else
Context.current_screen = Context.current_screen + 1
end
end
if Input.player_interact() then
PopupWindow.show_menu_dialog(npc, {
{label = "Talk to", action = NPC.talk_to},
{label = "Fight", action = NPC.fight},
{label = "Go back", action = NPC.go_back}
}, WINDOW_POPUP)
end
end
function GameWindow.set_state(new_state)

View File

@@ -1,34 +0,0 @@
function InventoryWindow.draw()
UI.draw_top_bar("Inventory")
if #Context.inventory == 0 then
Print.text("Inventory is empty.", 70, 70, Config.colors.light_grey)
else
for i, item in ipairs(Context.inventory) do
local color = Config.colors.light_grey
if i == Context.selected_inventory_item then
color = Config.colors.green
Print.text(">", 60, 20 + i * 10, color)
end
Print.text(item.name, 70, 20 + i * 10, color)
end
end
end
function InventoryWindow.update()
Context.selected_inventory_item = UI.update_menu(Context.inventory, Context.selected_inventory_item)
if Input.menu_confirm() and #Context.inventory > 0 then
local selected_item = Context.inventory[Context.selected_inventory_item]
PopupWindow.show_menu_dialog(selected_item, {
{label = "Use", action = Item.use},
{label = "Drop", action = Item.drop},
{label = "Look at", action = Item.look_at},
{label = "Go back", action = Item.go_back_from_inventory_action}
}, WINDOW_INVENTORY_ACTION)
end
if Input.menu_back() then
GameWindow.set_state(WINDOW_GAME)
end
end

View File

@@ -41,7 +41,7 @@ function PopupWindow.update()
if Input.menu_confirm() or Input.menu_back() then
Context.dialog.showing_description = false
Context.dialog.text = "" -- Clear the description text
-- No need to change active_window, as it remains in WINDOW_POPUP or WINDOW_INVENTORY_ACTION
-- No need to change active_window, as it remains in WINDOW_POPUP
end
else
Context.dialog.selected_menu_item = UI.update_menu(Context.dialog.menu_items, Context.dialog.selected_menu_item)

View File

@@ -1,13 +1,9 @@
function SplashWindow.draw()
for y, row in ipairs(MapBedroom) do
for x = 1, #row, 2 do
local tile_id_hex = string.sub(row, x, x + 1)
local tile_id = tonumber(tile_id_hex, 16)
local screen_x = (x - 1) / 2 * 8
local screen_y = (y - 1) * 8
spr(tile_id, screen_x, screen_y, -1, 1, 0, 0, 1, 1)
end
end
local txt = "Definitely not an Impostor"
local w = #txt * 6
local x = (240 - w) / 2
local y = (136 - 6) / 2
print(txt, x, y, 12)
end
function SplashWindow.update()