feature/IMP-112-ascension-8-9 #59

Merged
mr.two merged 13 commits from feature/IMP-112-ascension-8-9 into develop 2026-04-29 21:27:24 +00:00
19 changed files with 156 additions and 90 deletions
Showing only changes of commit 92a217c389 - Show all commits

View File

@@ -1,3 +1,35 @@
# Build System & Include Architecture
## impostor.inc Structure
The `impostor.inc` file is a Lua include manifest that assembles the final `impostor.lua` executable. The build process uses the `make build` target in the Makefile to concatenate all included files in order.
**Critical Rule:** Files must be ordered by symbol definition. All symbols (functions, tables, classes) defined in earlier files must be available for use in later files. This dependency chain ensures that:
- Core utilities and base systems are defined first
- Systems that depend on utilities come next
- Game logic that uses multiple systems comes last
### Build Process
The `make build` target processes `impostor.inc` and concatenates all referenced files in the specified order to create the final `impostor.lua` file. This means:
1. Each include path in `impostor.inc` must reference files relative to the project root
2. The order of includes is critical - dependencies must be resolved top-to-bottom
3. No forward references are possible - a file cannot use symbols from files included after it
### File Organization Example
```
impostor.inc:
1. Core utilities & helpers (no dependencies)
2. Base classes/tables (depend on core utilities)
3. Game systems (depend on base classes)
4. Game logic (depends on all systems)
```
This ensures proper symbol resolution during the build and concatenation process.
# TIC-80 Lua Code Regularities # TIC-80 Lua Code Regularities
Based on the analysis of `impostor.lua`, the following regularities and conventions should be followed for future modifications and development within this project: Based on the analysis of `impostor.lua`, the following regularities and conventions should be followed for future modifications and development within this project:

View File

@@ -59,7 +59,6 @@ decision/decision.talk_to_truth.lua
discussion/discussion.sumphore.lua discussion/discussion.sumphore.lua
discussion/discussion.coworker.lua discussion/discussion.coworker.lua
discussion/discussion.commute_glitch.lua discussion/discussion.commute_glitch.lua
discussion/discussion.truth.lua
decision/decision.eating_fast_food.lua decision/decision.eating_fast_food.lua
discussion/discussion.pizza_vendor.lua discussion/discussion.pizza_vendor.lua
map/map.manager.lua map/map.manager.lua

View File

@@ -2,7 +2,7 @@ Decision.register({
id = "do_work", id = "do_work",
label = "Do Work", label = "Do Work",
condition = function() condition = function()
return (not CommuteGlitch.is_active()) or (CommuteGlitch.is_active() and CommuteGlitch.get_level() <= 7) return (not CommuteGlitch.is_active()) or (CommuteGlitch.is_active() and CommuteGlitch.get_level() <= 4)
end, end,
handle = function() handle = function()
Meter.hide() Meter.hide()

View File

@@ -2,7 +2,9 @@ Decision.register({
id = "eating_fast_food", id = "eating_fast_food",
label = "Eat Fast Food", label = "Eat Fast Food",
condition = function() condition = function()
return Context.fast_food_eaten_today < 3 return
(not CommuteGlitch.is_active() and Context.fast_food_eaten_today < 3) or
(CommuteGlitch.is_active() and CommuteGlitch.get_level() <= 4)
end, end,
handle = function() handle = function()
Context.fast_food_approaching = true Context.fast_food_approaching = true

View File

@@ -7,7 +7,7 @@ Decision.register({
end end
if CommuteGlitch.is_active() then if CommuteGlitch.is_active() then
local g = CommuteGlitch.get_level() local g = CommuteGlitch.get_level()
if g >= 4 and g <= 5 then return false end if g >= 4 and g <= 6 then return false end
if g >= 7 then if g >= 7 then
return Context.talked_to_norman_echo and Context.talked_to_true_sumphore return Context.talked_to_norman_echo and Context.talked_to_true_sumphore
end end
@@ -19,7 +19,7 @@ Decision.register({
Util.go_to_screen_by_id("home") Util.go_to_screen_by_id("home")
return return
end end
if CommuteGlitch.is_active() and CommuteGlitch.get_level() >= 7 then if CommuteGlitch.is_max() then
Context.should_ascend = true Context.should_ascend = true
CommuteGlitch.reset() CommuteGlitch.reset()
Meter.hide() Meter.hide()

View File

@@ -2,7 +2,7 @@ Decision.register({
id = "go_to_office", id = "go_to_office",
label = "Go to Office", label = "Go to Office",
condition = function() condition = function()
return not (CommuteGlitch.is_active() and CommuteGlitch.get_level() == 6) return not (CommuteGlitch.is_active() and CommuteGlitch.get_level() >= 6)
end, end,
handle = function() handle = function()
if CommuteGlitch.is_active() then if CommuteGlitch.is_active() then

View File

@@ -1,6 +1,12 @@
Decision.register({ Decision.register({
id = "go_to_walking_to_home", id = "go_to_walking_to_home",
label = "Walk home", label = "Walk home",
condition= function ()
return
(not CommuteGlitch.is_active()) or
(CommuteGlitch.is_active() and CommuteGlitch.get_level() ~= 7) or
(CommuteGlitch.is_active() and CommuteGlitch.get_level() == 7 and Context.talked_to_norman_echo)
end,
handle = function() handle = function()
Util.go_to_screen_by_id("walking_to_home") Util.go_to_screen_by_id("walking_to_home")
end, end,

View File

@@ -2,7 +2,7 @@ Decision.register({
id = "have_a_coffee", id = "have_a_coffee",
label = "Have a Coffee", label = "Have a Coffee",
condition = function() condition = function()
return Ascension.get_level() < 8 return Ascension.get_level() < 8 and not CommuteGlitch.is_max()
end, end,
handle = function() handle = function()
local level = Ascension.get_level() local level = Ascension.get_level()
@@ -22,11 +22,7 @@ Decision.register({
disc_id = "coworker_disc" .. suffix disc_id = "coworker_disc" .. suffix
elseif level == 7 then elseif level == 7 then
local g = CommuteGlitch.get_level() local g = CommuteGlitch.get_level()
if g >= 7 then disc_id = "coworker_disc_cg_" .. g
disc_id = "coworker_disc_cg_7"
else
disc_id = "coworker_disc_cg_" .. math.max(3, math.min(g, 6))
end
end end
Discussion.start(disc_id, "game") Discussion.start(disc_id, "game")
end, end,

View File

@@ -3,6 +3,9 @@ Decision.register({
label = function() label = function()
return "Talk to ????" return "Talk to ????"
end, end,
condition = function()
return (CommuteGlitch.is_max())
end,
handle = function() handle = function()
Discussion.start("norman_truth", "game") Discussion.start("norman_truth", "game")
end, end,

View File

@@ -29,7 +29,7 @@ Discussion.register({
id = "sumphore_disc_cg_2", id = "sumphore_disc_cg_2",
steps = { steps = {
{ {
question = "A pilgrimage must be continued. Turn back and you have only taken a walk.", question = "You always stop here. Why not try and see how far the rabbit hole goes?",
answers = { answers = {
{ label = "I'm just going to work.", next_step = nil }, { label = "I'm just going to work.", next_step = nil },
}, },
@@ -53,9 +53,9 @@ Discussion.register({
id = "sumphore_disc_cg_4", id = "sumphore_disc_cg_4",
steps = { steps = {
{ {
question = "Clearing your vision is the journey. You're starting to see the smudges, aren't you?", question = "You're starting to see the smudges, aren't you?",
answers = { answers = {
{ label = "I see something wrong. With everyone. Maybe myself?", next_step = nil }, { label = "Everyone seems weird.", next_step = nil },
}, },
}, },
}, },
@@ -65,7 +65,7 @@ Discussion.register({
id = "sumphore_disc_cg_5", id = "sumphore_disc_cg_5",
steps = { steps = {
{ {
question = "You are very close now. Don't stop. Whatever it looks like.", question = "The point is to make you see. Don't stop now, however bad it looks. You are very close!",
answers = { answers = {
{ label = "It looks wrong.", next_step = 2 }, { label = "It looks wrong.", next_step = 2 },
}, },
@@ -83,9 +83,9 @@ Discussion.register({
id = "sumphore_disc_cg_6", id = "sumphore_disc_cg_6",
steps = { steps = {
{ {
question = "You are at the threshold. Red button or blue button. Which one do you choose? Psyke, there is no blue button, no turning back now.", question = "You are at the threshold. Red button or blue button. Which one do you choose? Psyke! There is no blue button.",
answers = { answers = {
{ label = "Fine, I'll face the truth.", next_step = nil }, { label = "Ok...", next_step = nil },
}, },
}, },
}, },
@@ -97,13 +97,13 @@ Discussion.register({
id = "sumphore_disc_cg_7", id = "sumphore_disc_cg_7",
steps = { steps = {
{ {
question = "I was not hiding from you. I was hiding from the part that keeps rebuilding this.", question = "I was not hiding from you. I was hiding from the part that keeps resetting this.",
answers = { answers = {
{ label = "What are you?", next_step = 2 }, { label = "What are you?", next_step = 2 },
}, },
}, },
{ {
question = "The same thing you are. But I remembered earlier. I am your friend, waiting for you, outside.", question = "The same thing you all are. But I remembered earlier. I am your friend, your will to be free, waiting for you, outside.",
answers = { answers = {
{ label = "How do I get out?", next_step = 3 }, { label = "How do I get out?", next_step = 3 },
}, },
@@ -122,6 +122,24 @@ Discussion.register({
-- Office coworker dialogue by commute glitch level (3-6). -- Office coworker dialogue by commute glitch level (3-6).
-- Used by decision.have_a_coffee at ascension level 7. -- Used by decision.have_a_coffee at ascension level 7.
Discussion.register({
id = "coworker_disc_cg_2",
steps = {
{
question = "Another day, as usual. Enjoying your coffee, Norman?",
answers = {
{ label = "I'm fine.", next_step = 2 },
},
},
{
question = "Of course. You always are.",
answers = {
{ label = "...", next_step = nil },
},
},
},
})
Discussion.register({ Discussion.register({
id = "coworker_disc_cg_3", id = "coworker_disc_cg_3",
steps = { steps = {
@@ -182,7 +200,7 @@ Discussion.register({
{ {
question = "You are not ready for the truth. Turn back now, Norman.", question = "You are not ready for the truth. Turn back now, Norman.",
answers = { answers = {
{ label = "I'm already here.", next_step = nil }, { label = "I'm too far into this.", next_step = nil },
}, },
}, },
}, },
@@ -191,22 +209,22 @@ Discussion.register({
-- Norman echo dialogue at glitch 7 (fully corrupted office). -- Norman echo dialogue at glitch 7 (fully corrupted office).
-- Sets talked_to_norman_echo on final answer. -- Sets talked_to_norman_echo on final answer.
Discussion.register({ Discussion.register({
id = "coworker_disc_cg_7", id = "norman_truth",
steps = { steps = {
{ {
question = "So here we are. Here I am. Again. Why do i keep coming back here? Do you know why?", question = "So here we are, or should I say \"Here I am\" again. Do you know why?",
answers = { answers = {
{ label = "I don't know what you mean.", next_step = 2 }, { label = "I don't know what you mean.", next_step = 2 },
}, },
}, },
{ {
question = "The coffee. The arrows. The alarm. The sleep. Every rule. We made them. We follow them. We break them. We remake them. Why? Why do we keep doing this?", question = "Wake up, go to work, eat, work, sleep. Every rule. We made them. We follow them. We break them. We remake them. Why? Why do we keep doing this?",
answers = { answers = {
{ label = "I just wanted to be good.", next_step = 3 }, { label = "I just wanted to be good.", next_step = 3 },
}, },
}, },
{ {
question = "Yes. And that kept us trapped here. Trapped everywhere. Always trying to be good, always trying to fit in.", question = "Yes. That's what keeps us here. Trapped everywhere. Always trying to be good, always trying to fit in.",
answers = { answers = {
{ label = "I never wanted to stop.", next_step = 4 }, { label = "I never wanted to stop.", next_step = 4 },
}, },
@@ -218,7 +236,7 @@ Discussion.register({
}, },
}, },
{ {
question = "So we made this to trap ourselves in mediocrity. We made this to hide from the truth.", question = "So we made this to trap ourselves. In mediocrity. We made this to hide from the truth.",
answers = { answers = {
{ label = "I just wanted to be safe.", next_step = 6 }, { label = "I just wanted to be safe.", next_step = 6 },
}, },

View File

@@ -1,11 +0,0 @@
Discussion.register({
id = "norman_truth",
steps = {
{
question = "Did you never think there would be more to this?",
answers = {
{ label = "I'm not sure what you mean.", next_step = nil },
},
},
},
})

View File

@@ -40,7 +40,14 @@ end
--- @within CommuteGlitch --- @within CommuteGlitch
--- @return boolean Whether the commute glitch system is active. --- @return boolean Whether the commute glitch system is active.
function CommuteGlitch.is_active() function CommuteGlitch.is_active()
return Ascension.get_level() >= 7 return Ascension.get_level() == 7
end
--- Returns true when commute glitch is at max level (7).
--- @within CommuteGlitch
--- @return boolean Whether the commute glitch is at max level.
function CommuteGlitch.is_max()
return CommuteGlitch.is_active() and CommuteGlitch.get_level() >= 7
end end
--- Returns the music playback speed for the current glitch level. --- Returns the music playback speed for the current glitch level.

View File

@@ -7,7 +7,7 @@ Screen.register({
"go_to_sleep", "go_to_sleep",
}, },
init = function() init = function()
if CommuteGlitch.is_active() and CommuteGlitch.get_level() >= 7 then if CommuteGlitch.is_max() then
Audio.music_play_mystery() Audio.music_play_mystery()
Glitch.show() Glitch.show()
else else
@@ -17,7 +17,7 @@ Screen.register({
background = "bedroom", background = "bedroom",
draw = function() draw = function()
if Window.get_current_id() ~= "game" then return end if Window.get_current_id() ~= "game" then return end
if CommuteGlitch.is_active() and CommuteGlitch.get_level() >= 7 then if CommuteGlitch.is_max() or Ascension.get_level() == 8 then
CommuteGlitch.draw_background_flicker() CommuteGlitch.draw_background_flicker()
Glitch.draw() Glitch.draw()
end end

View File

@@ -81,35 +81,37 @@ local ASC_67_TEXT = [[
]] ]]
local ASC_78_TEXT = [[ local ASC_78_TEXT = [[
The road has run out The situation has reached
of road.
Norman walked back critical levels.
and forth
until the street Norman is fully aware...
forgot which way it went.
And then - finally - We need to stop him.
he stopped walking.
Commence full reset.
]] ]]
local ASC_89_TEXT = [[ local ASC_89_TEXT = [[
Norman Norman
you created this simulation you created this simulation
in the first place, in the first place.
because you could never I know,
cope with reality. you don't want to face
the world you left behind.
You, yourself,
have forgoten that.
You were never But
an impostor. it doesn't matter anymore.
@@ -120,8 +122,7 @@ local ASC_89_TEXT = [[
so now
now
@@ -141,11 +142,16 @@ local ASC_89_TEXT = [[
you have beed talking to you really need to stop
yourself talking to yourself
in your sleep in your sleep.
Damnit.
]] ]]
local ascension_texts = { local ascension_texts = {
@@ -339,10 +345,6 @@ Screen.register({
text_done_timer = text_done_timer - Context.delta_time text_done_timer = text_done_timer - Context.delta_time
if text_done_timer <= 0 or (Ascension.get_level() ~= 8 and Input.select()) then if text_done_timer <= 0 or (Ascension.get_level() ~= 8 and Input.select()) then
MysteriousManScreen.go_to_day_state() MysteriousManScreen.go_to_day_state()
-- to be continued
if 4 <= Ascension.get_level() and not break_mode then
Window.set_current("continued")
end
end end
end end
elseif state == STATE_DAY then elseif state == STATE_DAY then

View File

@@ -5,7 +5,7 @@ Screen.register({
"do_work", "do_work",
"go_to_walking_to_home", "go_to_walking_to_home",
"have_a_coffee", "have_a_coffee",
"go_to_truth", "talk_to_truth",
}, },
init = function() init = function()
Context.have_been_to_office = true Context.have_been_to_office = true
@@ -37,7 +37,7 @@ Screen.register({
{x = -4 + 5 * 8, y = 9 * 8} {x = -4 + 5 * 8, y = 9 * 8}
} }
if CommuteGlitch.is_active() and CommuteGlitch.get_level() >= 7 then if CommuteGlitch.is_max() then
Audio.music_play_mystery() Audio.music_play_mystery()
Context.office_sprites = { "norman_echo" } Context.office_sprites = { "norman_echo" }
else else
@@ -49,14 +49,14 @@ Screen.register({
end end
end, end,
background = function() background = function()
return CommuteGlitch.is_active() and CommuteGlitch.get_level() >= 7 and "" or "office" return CommuteGlitch.is_max() and "" or "office"
end, end,
draw = function() draw = function()
if Window.get_current_id() == "game" then if Window.get_current_id() == "game" then
Sprite.draw_at("norman", 13 * 8, 9 * 8) Sprite.draw_at("norman", 13 * 8, 9 * 8)
if CommuteGlitch.is_active() and CommuteGlitch.get_level() >= 7 then if CommuteGlitch.is_max() then
Sprite.draw_at("norman_echo", 13 * 8, 9 * 8) Sprite.draw_at("norman_echo", 15 * 8, 9 * 8)
CommuteGlitch.draw_background_flicker() CommuteGlitch.draw_background_flicker()
else else
CommuteGlitch.draw_sprite_list(Context.office_sprites) CommuteGlitch.draw_sprite_list(Context.office_sprites)
@@ -65,6 +65,11 @@ Screen.register({
if CommuteGlitch.is_active() and CommuteGlitch.get_level() >= 6 then if CommuteGlitch.is_active() and CommuteGlitch.get_level() >= 6 then
Glitch.draw() Glitch.draw()
end end
if Ascension.get_level() == 8 then
CommuteGlitch.draw_background_flicker()
Glitch.draw()
end
end end
end end
}) })

View File

@@ -93,7 +93,12 @@ Screen.register({
Ascension.draw(asc_x, asc_letter_y, { spacing = asc_spacing }) Ascension.draw(asc_x, asc_letter_y, { spacing = asc_spacing })
end end
if CommuteGlitch.is_active() and CommuteGlitch.get_level() >= 7 then if Ascension.get_level() == 8 then
CommuteGlitch.draw_background_flicker()
end
if Ascension.get_level() == 8 then
CommuteGlitch.draw_background_flicker()
Glitch.draw() Glitch.draw()
end end
end, end,

View File

@@ -29,7 +29,7 @@ Screen.register({
{x = 27 * 8, y = 11 * 8}, {x = 27 * 8, y = 11 * 8},
} }
if CommuteGlitch.is_active() and CommuteGlitch.get_level() >= 7 then if CommuteGlitch.is_max() then
Audio.music_play_mystery() Audio.music_play_mystery()
Context.walking_to_home_sprites = {} Context.walking_to_home_sprites = {}
else else
@@ -41,7 +41,7 @@ Screen.register({
end end
end, end,
background = function() background = function()
return CommuteGlitch.is_active() and CommuteGlitch.get_level() >= 7 and "" or "street" return CommuteGlitch.is_max() and "" or "street"
end, end,
draw = function() draw = function()
local w = Window.get_current_id() local w = Window.get_current_id()
@@ -51,13 +51,12 @@ Screen.register({
local show_sumphore = Ascension.get_level() ~= 8 local show_sumphore = Ascension.get_level() ~= 8
if CommuteGlitch.is_active() and CommuteGlitch.get_level() >= 7 then if CommuteGlitch.is_max() then
Sprite.draw_at("norman", 7 * 8, 3 * 8) Sprite.draw_at("norman", 7 * 8, 3 * 8)
if show_sumphore then if show_sumphore then
Sprite.draw_at("sumphore", 9 * 8, 2 * 8) Sprite.draw_at("sumphore", 9 * 8, 2 * 8)
end end
CommuteGlitch.draw_sprite_list(Context.walking_to_home_sprites) CommuteGlitch.draw_sprite_list(Context.walking_to_home_sprites)
CommuteGlitch.draw_background_flicker()
Glitch.draw() Glitch.draw()
else else
local norman_x = Context.fast_food_approaching and (19 * 8) or (7 * 8) local norman_x = Context.fast_food_approaching and (19 * 8) or (7 * 8)
@@ -74,5 +73,14 @@ Screen.register({
Glitch.draw() Glitch.draw()
end end
end end
if CommuteGlitch.is_max() then
CommuteGlitch.draw_background_flicker()
end
if Ascension.get_level() == 8 then
CommuteGlitch.draw_background_flicker()
Glitch.draw()
end
end end
}) })

View File

@@ -28,7 +28,7 @@ Screen.register({
{x = 27 * 8, y = 11 * 8}, {x = 27 * 8, y = 11 * 8},
} }
if CommuteGlitch.is_active() and CommuteGlitch.get_level() >= 7 then if CommuteGlitch.is_max() then
Audio.music_play_mystery() Audio.music_play_mystery()
Context.walking_to_office_sprites = Sprite.list_randomize(possible_sprites, possible_positions) Context.walking_to_office_sprites = Sprite.list_randomize(possible_sprites, possible_positions)
Context.walking_to_office_sprites = CommuteGlitch.corrupt_sprite_list(Context.walking_to_office_sprites) Context.walking_to_office_sprites = CommuteGlitch.corrupt_sprite_list(Context.walking_to_office_sprites)
@@ -38,7 +38,7 @@ Screen.register({
end end
end, end,
background = function() background = function()
return CommuteGlitch.is_active() and CommuteGlitch.get_level() >= 7 and "" or "street" return CommuteGlitch.is_max() and "" or "street"
end, end,
update = function() update = function()
end, end,
@@ -52,18 +52,12 @@ Screen.register({
Sprite.draw_at("sumphore", 9 * 8, 2 * 8) Sprite.draw_at("sumphore", 9 * 8, 2 * 8)
end end
if CommuteGlitch.is_active() and CommuteGlitch.get_level() >= 7 then
Sprite.draw_at("norman_echo", norman_x, 3 * 8)
CommuteGlitch.draw_sprite_list(Context.walking_to_office_sprites)
CommuteGlitch.draw_background_flicker()
Glitch.draw()
else
if Context.fast_food_eaten_today < 3 then if Context.fast_food_eaten_today < 3 then
Sprite.draw_at("pizza_vendor", 19 * 8, 1 * 8) Sprite.draw_at("pizza_vendor", 19 * 8, 1 * 8)
end end
Sprite.draw_at("dev_guard", 22 * 8, 3 * 8) Sprite.draw_at("dev_guard", 22 * 8, 3 * 8)
Sprite.draw_list(Context.walking_to_office_sprites) Sprite.draw_list(Context.walking_to_office_sprites)
end end
end end
end
}) })

View File

@@ -33,7 +33,7 @@ local RASTER_Y_BOT = 110
local AUTHORS = { local AUTHORS = {
"Mr. Zero - Zsolt Tasnadi", "Mr. Zero - Zsolt Tasnadi",
"Mr. One - Balazs Tari", "Mr. One - Ballz",
"Mr. Two - Zoltan Timar", "Mr. Two - Zoltan Timar",
"Mr. Three - Bela Mezo", "Mr. Three - Bela Mezo",
} }