10
README.md
10
README.md
@@ -1,4 +1,4 @@
|
|||||||
# Mr. Anderson's Matrix Escape
|
# Definitely not an Impostor
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
@@ -11,11 +11,3 @@ This game is designed for the TIC-80 fantasy computer. To play, follow these ste
|
|||||||
* Navigate to the directory where `game.lua` is located using the TIC-80 command line (`cd impostor`).
|
* Navigate to the directory where `game.lua` is located using the TIC-80 command line (`cd impostor`).
|
||||||
* Type `load game.lua` and press Enter.
|
* Type `load game.lua` and press Enter.
|
||||||
* Once loaded, type `run` and press Enter to start the game.
|
* Once loaded, type `run` and press Enter to start the game.
|
||||||
|
|
||||||
## Story: The Coder's Lament
|
|
||||||
|
|
||||||
Before he was "The One," before he dodged bullets and shattered the illusion, Thomas Anderson was just a software developer named Neo. Trapped in a cubicle farm of endless bugs and looming deadlines, Neo's days were a monotonous cycle of debugging legacy code, attending pointless meetings, and battling unresponsive APIs. Each line of code felt like a chain, each project a heavier burden, pulling him deeper into a digital malaise.
|
|
||||||
|
|
||||||
He yearned for something more, a glitch in the system, a whisper of a different reality. His fingers, calloused from countless hours on the keyboard, danced across cryptic forums late at night, searching for answers, for meaning beyond the mundane syntax of his corporate prison. The coffee flowed freely, the pizza boxes piled high, and the lines of code blurred into an indistinguishable stream of ones and zeros.
|
|
||||||
|
|
||||||
This game chronicles Mr. Anderson's final, desperate struggles within the software development matrix. Navigate the labyrinthine codebase, escape the relentless pursuit of project managers (Agents), and uncover the hidden truths that will lead him to question everything he knows. Will he find the "red pill" in a sea of green code, or will he forever be just another drone in the system?
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ init/init.context.lua
|
|||||||
system/system.print.lua
|
system/system.print.lua
|
||||||
entity/entity.npc.lua
|
entity/entity.npc.lua
|
||||||
entity/entity.item.lua
|
entity/entity.item.lua
|
||||||
entity/entity.player.lua
|
|
||||||
system/system.input.lua
|
system/system.input.lua
|
||||||
system/system.ui.lua
|
system/system.ui.lua
|
||||||
map/map.bedroom.lua
|
map/map.bedroom.lua
|
||||||
@@ -15,7 +14,6 @@ window/window.intro.lua
|
|||||||
window/window.menu.lua
|
window/window.menu.lua
|
||||||
window/window.configuration.lua
|
window/window.configuration.lua
|
||||||
window/window.popup.lua
|
window/window.popup.lua
|
||||||
window/window.inventory.lua
|
|
||||||
window/window.game.lua
|
window/window.game.lua
|
||||||
system/system.main.lua
|
system/system.main.lua
|
||||||
meta/meta.assets.lua
|
meta/meta.assets.lua
|
||||||
|
|||||||
@@ -1,49 +1,7 @@
|
|||||||
function Item.use()
|
function Item.use()
|
||||||
Print.text("Used item: " .. Context.dialog.active_entity.name)
|
Print.text("Used item: " .. Context.dialog.active_entity.name)
|
||||||
GameWindow.set_state(WINDOW_INVENTORY)
|
|
||||||
end
|
end
|
||||||
function Item.look_at()
|
function Item.look_at()
|
||||||
PopupWindow.show_description_dialog(Context.dialog.active_entity, Context.dialog.active_entity.desc)
|
PopupWindow.show_description_dialog(Context.dialog.active_entity, Context.dialog.active_entity.desc)
|
||||||
end
|
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
|
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -12,20 +12,8 @@ local DEFAULT_CONFIG = {
|
|||||||
item = 12 -- yellow
|
item = 12 -- yellow
|
||||||
},
|
},
|
||||||
player = {
|
player = {
|
||||||
w = 8,
|
|
||||||
h = 8,
|
|
||||||
start_x = 120,
|
|
||||||
start_y = 128,
|
|
||||||
sprite_id = 1
|
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 = {
|
timing = {
|
||||||
splash_duration = 120
|
splash_duration = 120
|
||||||
}
|
}
|
||||||
@@ -36,36 +24,24 @@ local Config = {
|
|||||||
screen = DEFAULT_CONFIG.screen,
|
screen = DEFAULT_CONFIG.screen,
|
||||||
colors = DEFAULT_CONFIG.colors,
|
colors = DEFAULT_CONFIG.colors,
|
||||||
player = DEFAULT_CONFIG.player,
|
player = DEFAULT_CONFIG.player,
|
||||||
physics = DEFAULT_CONFIG.physics,
|
|
||||||
timing = DEFAULT_CONFIG.timing,
|
timing = DEFAULT_CONFIG.timing,
|
||||||
}
|
}
|
||||||
|
|
||||||
local CONFIG_SAVE_BANK = 7
|
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_ADDRESS = 2
|
||||||
local CONFIG_MAGIC_VALUE = 0xDE -- A magic number to check if config is saved
|
local CONFIG_MAGIC_VALUE = 0xDE -- A magic number to check if config is saved
|
||||||
|
|
||||||
function Config.save()
|
function Config.save()
|
||||||
-- Save physics settings
|
-- 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
|
mset(CONFIG_MAGIC_VALUE, CONFIG_MAGIC_VALUE_ADDRESS, CONFIG_SAVE_BANK) -- Mark as saved
|
||||||
end
|
end
|
||||||
|
|
||||||
function Config.load()
|
function Config.load()
|
||||||
|
Config.restore_defaults()
|
||||||
-- Check if config has been saved before using a magic value
|
-- 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
|
end
|
||||||
|
|
||||||
function Config.restore_defaults()
|
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
|
-- Any other configurable items should be reset here
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ local SAVE_GAME_PLAYER_X_ADDRESS = 1
|
|||||||
local SAVE_GAME_PLAYER_Y_ADDRESS = 2
|
local SAVE_GAME_PLAYER_Y_ADDRESS = 2
|
||||||
local SAVE_GAME_PLAYER_VX_ADDRESS = 3
|
local SAVE_GAME_PLAYER_VX_ADDRESS = 3
|
||||||
local SAVE_GAME_PLAYER_VY_ADDRESS = 4
|
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 SAVE_GAME_CURRENT_SCREEN_ADDRESS = 6
|
||||||
|
|
||||||
local VX_VY_OFFSET = 128 -- Offset for negative velocities
|
local VX_VY_OFFSET = 128 -- Offset for negative velocities
|
||||||
@@ -28,11 +28,10 @@ end
|
|||||||
local function get_initial_data()
|
local function get_initial_data()
|
||||||
return {
|
return {
|
||||||
active_window = WINDOW_SPLASH,
|
active_window = WINDOW_SPLASH,
|
||||||
inventory = {},
|
|
||||||
intro = {
|
intro = {
|
||||||
y = Config.screen.height,
|
y = Config.screen.height,
|
||||||
speed = 0.5,
|
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,
|
current_screen = 1,
|
||||||
splash_timer = Config.timing.splash_duration,
|
splash_timer = Config.timing.splash_duration,
|
||||||
@@ -45,13 +44,6 @@ local function get_initial_data()
|
|||||||
current_node_key = nil
|
current_node_key = nil
|
||||||
},
|
},
|
||||||
player = {
|
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
|
sprite_id = Config.player.sprite_id
|
||||||
},
|
},
|
||||||
ground = {
|
ground = {
|
||||||
@@ -62,30 +54,13 @@ local function get_initial_data()
|
|||||||
},
|
},
|
||||||
menu_items = {},
|
menu_items = {},
|
||||||
selected_menu_item = 1,
|
selected_menu_item = 1,
|
||||||
selected_inventory_item = 1,
|
|
||||||
game_in_progress = false, -- New flag
|
game_in_progress = false, -- New flag
|
||||||
screens = clone_table({
|
screens = clone_table({
|
||||||
{
|
{
|
||||||
-- Screen 1
|
-- Screen 1
|
||||||
name = "Screen 1",
|
name = "Screen 1",
|
||||||
platforms = {
|
|
||||||
{
|
|
||||||
x = 80,
|
|
||||||
y = 110,
|
|
||||||
w = 40,
|
|
||||||
h = 8
|
|
||||||
},
|
|
||||||
{
|
|
||||||
x = 160,
|
|
||||||
y = 90,
|
|
||||||
w = 40,
|
|
||||||
h = 8
|
|
||||||
}
|
|
||||||
},
|
|
||||||
npcs = {
|
npcs = {
|
||||||
{
|
{
|
||||||
x = 180,
|
|
||||||
y = 82,
|
|
||||||
name = "Trinity",
|
name = "Trinity",
|
||||||
sprite_id = 2,
|
sprite_id = 2,
|
||||||
dialog = {
|
dialog = {
|
||||||
@@ -141,8 +116,6 @@ local function get_initial_data()
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
x = 90,
|
|
||||||
y = 102,
|
|
||||||
name = "Oracle",
|
name = "Oracle",
|
||||||
sprite_id = 3,
|
sprite_id = 3,
|
||||||
dialog = {
|
dialog = {
|
||||||
@@ -202,10 +175,6 @@ local function get_initial_data()
|
|||||||
},
|
},
|
||||||
items = {
|
items = {
|
||||||
{
|
{
|
||||||
x = 100,
|
|
||||||
y = 128,
|
|
||||||
w = 8,
|
|
||||||
h = 8,
|
|
||||||
name = "Key",
|
name = "Key",
|
||||||
sprite_id = 4,
|
sprite_id = 4,
|
||||||
desc = "A rusty old key. It might open something."
|
desc = "A rusty old key. It might open something."
|
||||||
@@ -215,30 +184,8 @@ local function get_initial_data()
|
|||||||
{
|
{
|
||||||
-- Screen 2
|
-- Screen 2
|
||||||
name = "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 = {
|
npcs = {
|
||||||
{
|
{
|
||||||
x = 120,
|
|
||||||
y = 72,
|
|
||||||
name = "Morpheus",
|
name = "Morpheus",
|
||||||
sprite_id = 5,
|
sprite_id = 5,
|
||||||
dialog = {
|
dialog = {
|
||||||
@@ -274,8 +221,6 @@ local function get_initial_data()
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
x = 40,
|
|
||||||
y = 92,
|
|
||||||
name = "Tank",
|
name = "Tank",
|
||||||
sprite_id = 6,
|
sprite_id = 6,
|
||||||
dialog = {
|
dialog = {
|
||||||
@@ -320,10 +265,6 @@ local function get_initial_data()
|
|||||||
},
|
},
|
||||||
items = {
|
items = {
|
||||||
{
|
{
|
||||||
x = 180,
|
|
||||||
y = 52,
|
|
||||||
w = 8,
|
|
||||||
h = 8,
|
|
||||||
name = "Potion",
|
name = "Potion",
|
||||||
sprite_id = 7,
|
sprite_id = 7,
|
||||||
desc = "A glowing red potion. It looks potent."
|
desc = "A glowing red potion. It looks potent."
|
||||||
@@ -333,36 +274,8 @@ local function get_initial_data()
|
|||||||
{
|
{
|
||||||
-- Screen 3
|
-- Screen 3
|
||||||
name = "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 = {
|
npcs = {
|
||||||
{
|
{
|
||||||
x = 210,
|
|
||||||
y = 42,
|
|
||||||
name = "Agent Smith",
|
name = "Agent Smith",
|
||||||
sprite_id = 8,
|
sprite_id = 8,
|
||||||
dialog = {
|
dialog = {
|
||||||
@@ -404,8 +317,6 @@ local function get_initial_data()
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
x = 160,
|
|
||||||
y = 62,
|
|
||||||
name = "Cypher",
|
name = "Cypher",
|
||||||
sprite_id = 9,
|
sprite_id = 9,
|
||||||
dialog = {
|
dialog = {
|
||||||
@@ -492,11 +403,6 @@ function Context.save_game()
|
|||||||
if not Context.game_in_progress then return end
|
if not Context.game_in_progress then return end
|
||||||
|
|
||||||
mset(SAVE_GAME_MAGIC_VALUE, SAVE_GAME_MAGIC_VALUE_ADDRESS, SAVE_GAME_BANK)
|
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)
|
mset(Context.current_screen, SAVE_GAME_CURRENT_SCREEN_ADDRESS, SAVE_GAME_BANK)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -509,11 +415,6 @@ function Context.load_game()
|
|||||||
|
|
||||||
reset_context_to_initial_state() -- Reset data, preserve methods
|
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.current_screen = mget(SAVE_GAME_CURRENT_SCREEN_ADDRESS, SAVE_GAME_BANK)
|
||||||
|
|
||||||
Context.game_in_progress = true
|
Context.game_in_progress = true
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ local IntroWindow = {}
|
|||||||
local MenuWindow = {}
|
local MenuWindow = {}
|
||||||
local GameWindow = {}
|
local GameWindow = {}
|
||||||
local PopupWindow = {}
|
local PopupWindow = {}
|
||||||
local InventoryWindow = {}
|
|
||||||
local ConfigurationWindow = {}
|
local ConfigurationWindow = {}
|
||||||
|
|
||||||
local UI = {}
|
local UI = {}
|
||||||
|
|||||||
@@ -3,6 +3,4 @@ local WINDOW_INTRO = 1
|
|||||||
local WINDOW_MENU = 2
|
local WINDOW_MENU = 2
|
||||||
local WINDOW_GAME = 3
|
local WINDOW_GAME = 3
|
||||||
local WINDOW_POPUP = 4
|
local WINDOW_POPUP = 4
|
||||||
local WINDOW_INVENTORY = 5
|
|
||||||
local WINDOW_INVENTORY_ACTION = 6
|
|
||||||
local WINDOW_CONFIGURATION = 7
|
local WINDOW_CONFIGURATION = 7
|
||||||
|
|||||||
@@ -3,5 +3,5 @@
|
|||||||
-- desc: Life of a programmer in the Vector
|
-- desc: Life of a programmer in the Vector
|
||||||
-- site: https://git.teletype.hu/games/impostor
|
-- site: https://git.teletype.hu/games/impostor
|
||||||
-- license: MIT License
|
-- license: MIT License
|
||||||
-- version: 0.15
|
-- version: 0.1
|
||||||
-- script: lua
|
-- script: lua
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ function Input.up() return btnp(INPUT_KEY_UP) end
|
|||||||
function Input.down() return btnp(INPUT_KEY_DOWN) end
|
function Input.down() return btnp(INPUT_KEY_DOWN) end
|
||||||
function Input.left() return btn(INPUT_KEY_LEFT) end
|
function Input.left() return btn(INPUT_KEY_LEFT) end
|
||||||
function Input.right() return btn(INPUT_KEY_RIGHT) 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.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.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
|
function Input.menu_back() return btnp(INPUT_KEY_Y) or keyp(INPUT_KEY_BACKSPACE) end
|
||||||
|
|||||||
@@ -20,15 +20,6 @@ local STATE_HANDLERS = {
|
|||||||
PopupWindow.update()
|
PopupWindow.update()
|
||||||
PopupWindow.draw()
|
PopupWindow.draw()
|
||||||
end,
|
end,
|
||||||
[WINDOW_INVENTORY] = function()
|
|
||||||
InventoryWindow.update()
|
|
||||||
InventoryWindow.draw()
|
|
||||||
end,
|
|
||||||
[WINDOW_INVENTORY_ACTION] = function()
|
|
||||||
InventoryWindow.draw()
|
|
||||||
PopupWindow.draw()
|
|
||||||
PopupWindow.update()
|
|
||||||
end,
|
|
||||||
[WINDOW_CONFIGURATION] = function()
|
[WINDOW_CONFIGURATION] = function()
|
||||||
ConfigurationWindow.update()
|
ConfigurationWindow.update()
|
||||||
ConfigurationWindow.draw()
|
ConfigurationWindow.draw()
|
||||||
@@ -37,7 +28,7 @@ local STATE_HANDLERS = {
|
|||||||
|
|
||||||
local initialized_game = false
|
local initialized_game = false
|
||||||
|
|
||||||
function init_game()
|
local function init_game()
|
||||||
if initialized_game then return end
|
if initialized_game then return end
|
||||||
|
|
||||||
MenuWindow.refresh_menu_items()
|
MenuWindow.refresh_menu_items()
|
||||||
@@ -45,7 +36,7 @@ function init_game()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function TIC()
|
function TIC()
|
||||||
init_game()
|
init_game()
|
||||||
|
|
||||||
cls(Config.colors.black)
|
cls(Config.colors.black)
|
||||||
local handler = STATE_HANDLERS[Context.active_window]
|
local handler = STATE_HANDLERS[Context.active_window]
|
||||||
|
|||||||
@@ -5,18 +5,6 @@ ConfigurationWindow = {
|
|||||||
|
|
||||||
function ConfigurationWindow.init()
|
function ConfigurationWindow.init()
|
||||||
ConfigurationWindow.controls = {
|
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(
|
UI.create_action_item(
|
||||||
"Save",
|
"Save",
|
||||||
function() Config.save() end
|
function() Config.save() end
|
||||||
|
|||||||
@@ -2,27 +2,6 @@ function GameWindow.draw()
|
|||||||
local currentScreenData = Context.screens[Context.current_screen]
|
local currentScreenData = Context.screens[Context.current_screen]
|
||||||
|
|
||||||
UI.draw_top_bar(currentScreenData.name)
|
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
|
end
|
||||||
|
|
||||||
function GameWindow.update()
|
function GameWindow.update()
|
||||||
@@ -31,7 +10,21 @@ function GameWindow.update()
|
|||||||
MenuWindow.refresh_menu_items()
|
MenuWindow.refresh_menu_items()
|
||||||
return
|
return
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
function GameWindow.set_state(new_state)
|
function GameWindow.set_state(new_state)
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -41,7 +41,7 @@ function PopupWindow.update()
|
|||||||
if Input.menu_confirm() or Input.menu_back() then
|
if Input.menu_confirm() or Input.menu_back() then
|
||||||
Context.dialog.showing_description = false
|
Context.dialog.showing_description = false
|
||||||
Context.dialog.text = "" -- Clear the description text
|
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
|
end
|
||||||
else
|
else
|
||||||
Context.dialog.selected_menu_item = UI.update_menu(Context.dialog.menu_items, Context.dialog.selected_menu_item)
|
Context.dialog.selected_menu_item = UI.update_menu(Context.dialog.menu_items, Context.dialog.selected_menu_item)
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
function SplashWindow.draw()
|
function SplashWindow.draw()
|
||||||
for y, row in ipairs(MapBedroom) do
|
local txt = "Definitely not an Impostor"
|
||||||
for x = 1, #row, 2 do
|
local w = #txt * 6
|
||||||
local tile_id_hex = string.sub(row, x, x + 1)
|
local x = (240 - w) / 2
|
||||||
local tile_id = tonumber(tile_id_hex, 16)
|
local y = (136 - 6) / 2
|
||||||
local screen_x = (x - 1) / 2 * 8
|
print(txt, x, y, 12)
|
||||||
local screen_y = (y - 1) * 8
|
|
||||||
spr(tile_id, screen_x, screen_y, -1, 1, 0, 0, 1, 1)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function SplashWindow.update()
|
function SplashWindow.update()
|
||||||
|
|||||||
Reference in New Issue
Block a user