Merge branch 'develop' into feature/ascension_7_8
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
# Conflicts: # impostor.inc # inc/decision/decision.have_a_coffee.lua # inc/decision/decision.sumphore_discussion.lua # inc/screen/screen.mysterious_man.lua # inc/screen/screen.walking_to_home.lua # inc/screen/screen.walking_to_office.lua # inc/window/window.menu.lua
This commit is contained in:
112
.luacheckrc
112
.luacheckrc
@@ -2,73 +2,79 @@
|
|||||||
-- Configuration for luacheck
|
-- Configuration for luacheck
|
||||||
|
|
||||||
globals = {
|
globals = {
|
||||||
"Focus",
|
|
||||||
"Day",
|
|
||||||
"Timer",
|
|
||||||
"Glitch",
|
|
||||||
"Trigger",
|
|
||||||
"Discussion",
|
|
||||||
"Util",
|
|
||||||
"Decision",
|
|
||||||
"Screen",
|
|
||||||
"Sprite",
|
|
||||||
"UI",
|
|
||||||
"Print",
|
|
||||||
"Input",
|
|
||||||
"Audio",
|
|
||||||
"AsciiArt",
|
"AsciiArt",
|
||||||
"Ascension",
|
"Ascension",
|
||||||
|
"Audio",
|
||||||
|
"AudioTestWindow",
|
||||||
|
"BriefIntroWindow",
|
||||||
|
"CodeGenerator",
|
||||||
"Config",
|
"Config",
|
||||||
"Context",
|
"Context",
|
||||||
"Meter",
|
|
||||||
"Minigame",
|
|
||||||
"Window",
|
|
||||||
"ContinuedWindow",
|
"ContinuedWindow",
|
||||||
"TTGIntroWindow",
|
|
||||||
"BriefIntroWindow",
|
|
||||||
"TitleIntroWindow",
|
|
||||||
"MenuWindow",
|
|
||||||
"GameWindow",
|
|
||||||
"PopupWindow",
|
|
||||||
"ControlsWindow",
|
"ControlsWindow",
|
||||||
"AudioTestWindow",
|
"CreditsWindow",
|
||||||
"MinigameButtonMashWindow",
|
"Day",
|
||||||
"MinigameRhythmWindow",
|
"Decision",
|
||||||
"MinigameDDRWindow",
|
"Discussion",
|
||||||
"MysteriousManScreen",
|
|
||||||
"DiscussionWindow",
|
"DiscussionWindow",
|
||||||
"EndWindow",
|
"EndWindow",
|
||||||
"mset",
|
"Focus",
|
||||||
"mget",
|
"GameOverWindow",
|
||||||
|
"GameWindow",
|
||||||
|
"Glitch",
|
||||||
|
"Input",
|
||||||
|
"Map",
|
||||||
|
"MapBedroom",
|
||||||
|
"MenuWindow",
|
||||||
|
"Meter",
|
||||||
|
"Minigame",
|
||||||
|
"MinigameButtonMashWindow",
|
||||||
|
"MinigameDDRWindow",
|
||||||
|
"MinigameRhythmWindow",
|
||||||
|
"Mouse",
|
||||||
|
"MysteriousManScreen",
|
||||||
|
"PlayerNameWindow",
|
||||||
|
"PopupWindow",
|
||||||
|
"Print",
|
||||||
|
"RLE",
|
||||||
|
"Screen",
|
||||||
|
"Songs",
|
||||||
|
"Sprite",
|
||||||
|
"TIC",
|
||||||
|
"TTGIntroWindow",
|
||||||
|
"TextInput",
|
||||||
|
"Timer",
|
||||||
|
"TitleIntroWindow",
|
||||||
|
"Trigger",
|
||||||
|
"UI",
|
||||||
|
"Util",
|
||||||
|
"WalkingToOfficeScreen",
|
||||||
|
"Window",
|
||||||
|
"beats_to_pattern",
|
||||||
"btnp",
|
"btnp",
|
||||||
|
"circb",
|
||||||
|
"circ",
|
||||||
|
"cls",
|
||||||
|
"exit",
|
||||||
|
"frame_from_beat",
|
||||||
|
"index_menu",
|
||||||
"keyp",
|
"keyp",
|
||||||
|
"line",
|
||||||
|
"map",
|
||||||
|
"mouse",
|
||||||
|
"mget",
|
||||||
|
"mset",
|
||||||
"music",
|
"music",
|
||||||
"sfx",
|
"musicator_generate_pattern",
|
||||||
"spr",
|
"pix",
|
||||||
|
"print",
|
||||||
"rect",
|
"rect",
|
||||||
"rectb",
|
"rectb",
|
||||||
"circ",
|
"sfx",
|
||||||
"circb",
|
"spr",
|
||||||
"cls",
|
|
||||||
"tri",
|
|
||||||
"pix",
|
|
||||||
"line",
|
|
||||||
"Songs",
|
|
||||||
"frame_from_beat",
|
|
||||||
"beats_to_pattern",
|
|
||||||
"MapBedroom",
|
|
||||||
"TIC",
|
|
||||||
"exit",
|
|
||||||
"trace",
|
|
||||||
"index_menu",
|
|
||||||
"Map",
|
|
||||||
"map",
|
|
||||||
"time",
|
"time",
|
||||||
"RLE",
|
"trace",
|
||||||
"mouse",
|
"tri",
|
||||||
"Mouse",
|
|
||||||
"print",
|
|
||||||
"musicator_generate_pattern",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ init/init.context_debug.lua
|
|||||||
system/system.util.lua
|
system/system.util.lua
|
||||||
system/system.print.lua
|
system/system.print.lua
|
||||||
system/system.input.lua
|
system/system.input.lua
|
||||||
|
system/system.textinput.lua
|
||||||
system/system.mouse.lua
|
system/system.mouse.lua
|
||||||
system/system.asciiart.lua
|
system/system.asciiart.lua
|
||||||
system/system.rle.lua
|
system/system.rle.lua
|
||||||
@@ -18,6 +19,7 @@ logic/logic.trigger.lua
|
|||||||
logic/logic.minigame.lua
|
logic/logic.minigame.lua
|
||||||
logic/logic.glitch.lua
|
logic/logic.glitch.lua
|
||||||
logic/logic.commute_glitch.lua
|
logic/logic.commute_glitch.lua
|
||||||
|
logic/logic.codegenerator.lua
|
||||||
logic/logic.discussion.lua
|
logic/logic.discussion.lua
|
||||||
system/system.ui.lua
|
system/system.ui.lua
|
||||||
audio/audio.manager.lua
|
audio/audio.manager.lua
|
||||||
@@ -59,6 +61,8 @@ 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
|
discussion/discussion.truth.lua
|
||||||
|
decision/decision.eating_fast_food.lua
|
||||||
|
discussion/discussion.pizza_vendor.lua
|
||||||
map/map.manager.lua
|
map/map.manager.lua
|
||||||
map/map.bedroom.lua
|
map/map.bedroom.lua
|
||||||
map/map.street.lua
|
map/map.street.lua
|
||||||
@@ -73,6 +77,7 @@ screen/screen.work.lua
|
|||||||
screen/screen.mysterious_man.lua
|
screen/screen.mysterious_man.lua
|
||||||
window/window.manager.lua
|
window/window.manager.lua
|
||||||
window/window.register.lua
|
window/window.register.lua
|
||||||
|
window/window.gameover.lua
|
||||||
window/window.end.lua
|
window/window.end.lua
|
||||||
window/window.intro.title.lua
|
window/window.intro.title.lua
|
||||||
window/window.intro.ttg.lua
|
window/window.intro.ttg.lua
|
||||||
@@ -87,6 +92,8 @@ window/window.minigame.rhythm.lua
|
|||||||
window/window.minigame.ddr.lua
|
window/window.minigame.ddr.lua
|
||||||
window/window.discussion.lua
|
window/window.discussion.lua
|
||||||
window/window.continued.lua
|
window/window.continued.lua
|
||||||
|
window/window.credits.lua
|
||||||
|
window/window.player_name.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
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ Decision.register({
|
|||||||
modes_for_ascension_levels[1] = "only_special"
|
modes_for_ascension_levels[1] = "only_special"
|
||||||
modes_for_ascension_levels[2] = "only_left"
|
modes_for_ascension_levels[2] = "only_left"
|
||||||
modes_for_ascension_levels[3] = "only_nothing"
|
modes_for_ascension_levels[3] = "only_nothing"
|
||||||
|
modes_for_ascension_levels[4] = "normal"
|
||||||
|
|
||||||
MinigameDDRWindow.start("game", "generated", {
|
MinigameDDRWindow.start("game", "generated", {
|
||||||
on_win = function(game_context)
|
on_win = function(game_context)
|
||||||
@@ -22,8 +23,6 @@ Decision.register({
|
|||||||
Context.should_ascend = true
|
Context.should_ascend = true
|
||||||
elseif (game_context.special_mode_condition and Context.ascension.level == 3) then
|
elseif (game_context.special_mode_condition and Context.ascension.level == 3) then
|
||||||
Context.should_ascend = true
|
Context.should_ascend = true
|
||||||
elseif (game_context.special_mode_condition and Context.ascension.level == 4) then
|
|
||||||
Context.should_ascend = true
|
|
||||||
end
|
end
|
||||||
|
|
||||||
Meter.show()
|
Meter.show()
|
||||||
@@ -31,7 +30,7 @@ Decision.register({
|
|||||||
Window.set_current("game")
|
Window.set_current("game")
|
||||||
Context.have_done_work_today = true
|
Context.have_done_work_today = true
|
||||||
end,
|
end,
|
||||||
special_mode = modes_for_ascension_levels[Ascension.get_level()]
|
special_mode = modes_for_ascension_levels[Ascension.get_level()] or "normal"
|
||||||
})
|
})
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|||||||
11
inc/decision/decision.eating_fast_food.lua
Normal file
11
inc/decision/decision.eating_fast_food.lua
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
Decision.register({
|
||||||
|
id = "eating_fast_food",
|
||||||
|
label = "Eat Fast Food",
|
||||||
|
condition = function()
|
||||||
|
return Context.fast_food_eaten_today < 3
|
||||||
|
end,
|
||||||
|
handle = function()
|
||||||
|
Context.fast_food_approaching = true
|
||||||
|
Discussion.start("pizza_vendor_disc", "game")
|
||||||
|
end,
|
||||||
|
})
|
||||||
@@ -1,7 +1,23 @@
|
|||||||
|
local function apply_home_toilet_meter_delta()
|
||||||
|
local max = Meter.get_max()
|
||||||
|
Meter.add("bm", -math.floor(max * 0.15))
|
||||||
|
Meter.add("ism", -math.floor(max * 0.10))
|
||||||
|
Meter.add("wpm", math.floor(max * 0.05))
|
||||||
|
end
|
||||||
|
|
||||||
Decision.register({
|
Decision.register({
|
||||||
id = "go_to_toilet",
|
id = "go_to_toilet",
|
||||||
label = "Go to Toilet",
|
label = "Go to Toilet",
|
||||||
handle = function()
|
handle = function()
|
||||||
|
if not Context.have_done_work_today and not Context.toilet_meters_today_morning then
|
||||||
|
apply_home_toilet_meter_delta()
|
||||||
|
Context.toilet_meters_today_morning = true
|
||||||
|
elseif Context.have_been_to_office
|
||||||
|
and Context.have_done_work_today
|
||||||
|
and not Context.toilet_meters_today_evening then
|
||||||
|
apply_home_toilet_meter_delta()
|
||||||
|
Context.toilet_meters_today_evening = true
|
||||||
|
end
|
||||||
Util.go_to_screen_by_id("toilet")
|
Util.go_to_screen_by_id("toilet")
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -4,9 +4,19 @@ Decision.register({
|
|||||||
handle = function()
|
handle = function()
|
||||||
local level = Ascension.get_level()
|
local level = Ascension.get_level()
|
||||||
local disc_id = "coworker_disc_0"
|
local disc_id = "coworker_disc_0"
|
||||||
if level >= 1 and level <= 3 then
|
if level >= 1 and level <= 5 then
|
||||||
local suffix = Context.have_done_work_today and ("_asc_" .. level) or ("_" .. level)
|
local suffix = Context.have_done_work_today and ("_asc_" .. level) or ("_" .. level)
|
||||||
disc_id = "coworker_disc" .. suffix
|
disc_id = "coworker_disc" .. suffix
|
||||||
|
elseif level == 6 then
|
||||||
|
if not Context.glitch_conversation_done_today and Context.glitch_conversation_count < 6 then
|
||||||
|
Context.glitch_conversation_done_today = true
|
||||||
|
Context.glitch_conversation_count = Context.glitch_conversation_count + 1
|
||||||
|
Glitch.show()
|
||||||
|
Discussion.start("coworker_disc_asc_6_" .. Context.glitch_conversation_count, "game")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local suffix = Context.have_done_work_today and ("_asc_5") or ("_5")
|
||||||
|
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
|
if g >= 7 then
|
||||||
|
|||||||
@@ -13,8 +13,14 @@ Decision.register({
|
|||||||
end
|
end
|
||||||
local level = Ascension.get_level()
|
local level = Ascension.get_level()
|
||||||
|
|
||||||
if level >= 1 and level <= 3 then
|
if level >= 1 and level <= 5 then
|
||||||
Discussion.start("sumphore_disc_asc_" .. level, "game")
|
Discussion.start("sumphore_disc_asc_" .. level, "game")
|
||||||
|
elseif level == 6 then
|
||||||
|
if Context.glitch_conversation_count >= 6 then
|
||||||
|
Discussion.start("sumphore_disc_asc_6", "game")
|
||||||
|
else
|
||||||
|
Discussion.start("sumphore_disc_asc_6_waiting", "game")
|
||||||
|
end
|
||||||
elseif level == 7 then
|
elseif level == 7 then
|
||||||
local g = math.min(CommuteGlitch.get_level(), 7)
|
local g = math.min(CommuteGlitch.get_level(), 7)
|
||||||
Discussion.start("sumphore_disc_cg_" .. g, "game")
|
Discussion.start("sumphore_disc_cg_" .. g, "game")
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
Discussion.register({
|
Discussion.register({
|
||||||
id = "coworker_disc_0",
|
id = "coworker_disc_0",
|
||||||
|
on_end = Meter.apply_coworker_discussion_reward,
|
||||||
steps = {
|
steps = {
|
||||||
{
|
{
|
||||||
question = "Good morning Normal, enjoying your coffee as usual, huh?",
|
question = "Good morning Normal, enjoying your coffee as usual, huh?",
|
||||||
@@ -18,6 +19,7 @@ Discussion.register({
|
|||||||
|
|
||||||
Discussion.register({
|
Discussion.register({
|
||||||
id = "coworker_disc_1",
|
id = "coworker_disc_1",
|
||||||
|
on_end = Meter.apply_coworker_discussion_reward,
|
||||||
steps = {
|
steps = {
|
||||||
{
|
{
|
||||||
question = "Norman, you look confused, what's up?",
|
question = "Norman, you look confused, what's up?",
|
||||||
@@ -36,6 +38,7 @@ Discussion.register({
|
|||||||
|
|
||||||
Discussion.register({
|
Discussion.register({
|
||||||
id = "coworker_disc_asc_1",
|
id = "coworker_disc_asc_1",
|
||||||
|
on_end = Meter.apply_coworker_discussion_reward,
|
||||||
steps = {
|
steps = {
|
||||||
{
|
{
|
||||||
question = "Normann you look weird and unfocused. You are usually locked in and not like this, what's up?",
|
question = "Normann you look weird and unfocused. You are usually locked in and not like this, what's up?",
|
||||||
@@ -54,6 +57,7 @@ Discussion.register({
|
|||||||
|
|
||||||
Discussion.register({
|
Discussion.register({
|
||||||
id = "coworker_disc_2",
|
id = "coworker_disc_2",
|
||||||
|
on_end = Meter.apply_coworker_discussion_reward,
|
||||||
steps = {
|
steps = {
|
||||||
{
|
{
|
||||||
question = "Hey Norman, do you have new socks on? That's a weird color!",
|
question = "Hey Norman, do you have new socks on? That's a weird color!",
|
||||||
@@ -79,6 +83,7 @@ Discussion.register({
|
|||||||
|
|
||||||
Discussion.register({
|
Discussion.register({
|
||||||
id = "coworker_disc_asc_2",
|
id = "coworker_disc_asc_2",
|
||||||
|
on_end = Meter.apply_coworker_discussion_reward,
|
||||||
steps = {
|
steps = {
|
||||||
{
|
{
|
||||||
question = "Normann, are you ok? You were doing weird things while typing?",
|
question = "Normann, are you ok? You were doing weird things while typing?",
|
||||||
@@ -97,6 +102,7 @@ Discussion.register({
|
|||||||
|
|
||||||
Discussion.register({
|
Discussion.register({
|
||||||
id = "coworker_disc_3",
|
id = "coworker_disc_3",
|
||||||
|
on_end = Meter.apply_coworker_discussion_reward,
|
||||||
steps = {
|
steps = {
|
||||||
{
|
{
|
||||||
question = "You look so happy, did you catch a bull or something?",
|
question = "You look so happy, did you catch a bull or something?",
|
||||||
@@ -120,6 +126,7 @@ Discussion.register({
|
|||||||
})
|
})
|
||||||
Discussion.register({
|
Discussion.register({
|
||||||
id = "coworker_disc_asc_3",
|
id = "coworker_disc_asc_3",
|
||||||
|
on_end = Meter.apply_coworker_discussion_reward,
|
||||||
steps = {
|
steps = {
|
||||||
{
|
{
|
||||||
question = "Normal, you should take a break, you don't live up to your name today",
|
question = "Normal, you should take a break, you don't live up to your name today",
|
||||||
@@ -135,3 +142,226 @@ Discussion.register({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Discussion.register({
|
||||||
|
id = "coworker_disc_4",
|
||||||
|
on_end = Meter.apply_coworker_discussion_reward,
|
||||||
|
steps = {
|
||||||
|
{
|
||||||
|
question = "Normaaan! Same spot, same cup, same time. You're like a statue that drinks coffee!",
|
||||||
|
answers = {
|
||||||
|
{ label = "I'm a person.", next_step = 2 },
|
||||||
|
{ label = "Yep. Still here.", next_step = 2 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question = "I love that about you! So reliable! If the coffee machine breaks we still have Norman!",
|
||||||
|
answers = {
|
||||||
|
{ label = "Please don't.", next_step = nil },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
Discussion.register({
|
||||||
|
id = "coworker_disc_asc_4",
|
||||||
|
on_end = Meter.apply_coworker_discussion_reward,
|
||||||
|
steps = {
|
||||||
|
{
|
||||||
|
question = "Norman, you were seriously locked in today. What on earth were you building?",
|
||||||
|
answers = {
|
||||||
|
{ label = "Just some things.", next_step = 2 },
|
||||||
|
{ label = "Nothing important.", next_step = 2 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question = "So modest! I heard the seniors literally whispering your name!",
|
||||||
|
answers = {
|
||||||
|
{ label = "Concerning.", next_step = 3 },
|
||||||
|
{ label = "That's... fine.", next_step = 3 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question = "You should celebrate! Coffee's on me tomorrow!",
|
||||||
|
answers = {
|
||||||
|
{ label = "Already have one.", next_step = nil },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
Discussion.register({
|
||||||
|
id = "coworker_disc_5",
|
||||||
|
on_end = Meter.apply_coworker_discussion_reward,
|
||||||
|
steps = {
|
||||||
|
{
|
||||||
|
question = "Morning! Funny thought — I feel like we do this exact same thing every single day!",
|
||||||
|
answers = {
|
||||||
|
{ label = "We do.", next_step = 2 },
|
||||||
|
{ label = "Yes. We do.", next_step = 2 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question = "Ha! Routine is such a comfort, right? Same coffee, same smile, same everything!",
|
||||||
|
answers = {
|
||||||
|
{ label = "Sure. Very comforting.", next_step = nil },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
Discussion.register({
|
||||||
|
id = "coworker_disc_asc_5",
|
||||||
|
on_end = Meter.apply_coworker_discussion_reward,
|
||||||
|
steps = {
|
||||||
|
{
|
||||||
|
question = "Norman! You were staring right THROUGH your screen today. What was going on up there?",
|
||||||
|
answers = {
|
||||||
|
{ label = "Coffee was cold.", next_step = 2 },
|
||||||
|
{ label = "Maybe I was.", next_step = 2 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question = "Were you meditating? Or doing your intense bug-stare thing?",
|
||||||
|
answers = {
|
||||||
|
{ label = "Something like that.", next_step = 3 },
|
||||||
|
{ label = "Bug stare thing?", next_step = 3 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question = "You're always somewhere else in your head, Norman. Must be nice up there!",
|
||||||
|
answers = {
|
||||||
|
{ label = "It's complicated.", next_step = nil },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
local function _glitch_on_end()
|
||||||
|
Meter.apply_coworker_discussion_reward()
|
||||||
|
Context.glitch_conversation_count = Context.glitch_conversation_count + 1
|
||||||
|
Glitch.hide()
|
||||||
|
end
|
||||||
|
|
||||||
|
Discussion.register({
|
||||||
|
id = "coworker_disc_asc_6_1",
|
||||||
|
on_end = _glitch_on_end,
|
||||||
|
steps = {
|
||||||
|
{
|
||||||
|
question = "Hey Norman, good morning! Good morning! Good morning! ...Sorry. I don't know why I keep saying that.",
|
||||||
|
answers = {
|
||||||
|
{ label = "Are you feeling ok?", next_step = 2 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question = "Good morning. Good morning. Good— I can't stop. Why can't I stop?",
|
||||||
|
answers = {
|
||||||
|
{ label = "...", next_step = nil },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
Discussion.register({
|
||||||
|
id = "coworker_disc_asc_6_2",
|
||||||
|
on_end = _glitch_on_end,
|
||||||
|
steps = {
|
||||||
|
{
|
||||||
|
question = "Hey... Marcus. How's it going?",
|
||||||
|
answers = {
|
||||||
|
{ label = "My name is Norman.", next_step = 2 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question = "Right, sorry. Marcus. You look tired today.",
|
||||||
|
answers = {
|
||||||
|
{ label = "Norman. It's Norman.", next_step = 3 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question = "Sure, sure. You should get some rest, Marcus.",
|
||||||
|
answers = {
|
||||||
|
{ label = "...", next_step = nil },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
Discussion.register({
|
||||||
|
id = "coworker_disc_asc_6_3",
|
||||||
|
on_end = _glitch_on_end,
|
||||||
|
steps = {
|
||||||
|
{
|
||||||
|
question = "We've had this conversation before, haven't we? Exact same words. Same coffee. Same spot.",
|
||||||
|
answers = {
|
||||||
|
{ label = "I don't think so.", next_step = 2 },
|
||||||
|
{ label = "Maybe.", next_step = 2 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question = "Every day. I always say the same thing and you always say that. It's very strange.",
|
||||||
|
answers = {
|
||||||
|
{ label = "That's just routine.", next_step = nil },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
Discussion.register({
|
||||||
|
id = "coworker_disc_asc_6_4",
|
||||||
|
on_end = _glitch_on_end,
|
||||||
|
steps = {
|
||||||
|
{
|
||||||
|
question = "Do you ever look at the walls here? Really look? Sometimes they don't feel... solid.",
|
||||||
|
answers = {
|
||||||
|
{ label = "They're just walls.", next_step = 2 },
|
||||||
|
{ label = "I know what you mean.", next_step = 2 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question = "Like they're only there because we expect them to be. Like set dressing. Does any of this feel load-bearing to you?",
|
||||||
|
answers = {
|
||||||
|
{ label = "I need more coffee.", next_step = nil },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
Discussion.register({
|
||||||
|
id = "coworker_disc_asc_6_5",
|
||||||
|
on_end = _glitch_on_end,
|
||||||
|
steps = {
|
||||||
|
{
|
||||||
|
question = "Norman, I'm not supposed to— I mean. How are you doing today?",
|
||||||
|
answers = {
|
||||||
|
{ label = "What weren't you supposed to say?", next_step = 2 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question = "...",
|
||||||
|
answers = {
|
||||||
|
{ label = "Hello?", next_step = nil },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
Discussion.register({
|
||||||
|
id = "coworker_disc_asc_6_6",
|
||||||
|
on_end = _glitch_on_end,
|
||||||
|
steps = {
|
||||||
|
{
|
||||||
|
question = "Forget it. You won't remember this conversation anyway. None of us do.",
|
||||||
|
answers = {
|
||||||
|
{ label = "What do you mean?", next_step = 2 },
|
||||||
|
{ label = "That's a strange thing to say.", next_step = 2 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question = "Tomorrow you'll come back and it'll be like this never happened. Same coffee. Same office. Same Norman.",
|
||||||
|
answers = {
|
||||||
|
{ label = "...", next_step = nil },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
28
inc/discussion/discussion.pizza_vendor.lua
Normal file
28
inc/discussion/discussion.pizza_vendor.lua
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
Discussion.register({
|
||||||
|
id = "pizza_vendor_disc",
|
||||||
|
on_end = function()
|
||||||
|
Context.fast_food_approaching = false
|
||||||
|
end,
|
||||||
|
steps = {
|
||||||
|
{
|
||||||
|
question = "Hey friend! Hot slice, fresh out of the oven. You look like a man who knows good food!",
|
||||||
|
answers = {
|
||||||
|
{
|
||||||
|
label = "Devour a juicy one",
|
||||||
|
next_step = nil,
|
||||||
|
on_select = function()
|
||||||
|
local max = Meter.get_max()
|
||||||
|
Meter.add("wpm", math.floor(max * 0.05))
|
||||||
|
Meter.add("ism", math.floor(max * -0.05))
|
||||||
|
Meter.add("bm", math.floor(max * -0.05))
|
||||||
|
Context.fast_food_eaten_today = Context.fast_food_eaten_today + 1
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label = "Stay lean and sharp",
|
||||||
|
next_step = nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
Discussion.register({
|
Discussion.register({
|
||||||
id = "sumphore_disc_asc_1",
|
id = "sumphore_disc_asc_1",
|
||||||
|
on_end = Meter.apply_sumphore_discussion_reward,
|
||||||
steps = {
|
steps = {
|
||||||
{
|
{
|
||||||
question = "Are you still seeking the ox?",
|
question = "Are you still seeking the ox?",
|
||||||
@@ -19,6 +20,7 @@ Discussion.register({
|
|||||||
|
|
||||||
Discussion.register({
|
Discussion.register({
|
||||||
id = "sumphore_disc_asc_2",
|
id = "sumphore_disc_asc_2",
|
||||||
|
on_end = Meter.apply_sumphore_discussion_reward,
|
||||||
steps = {
|
steps = {
|
||||||
{
|
{
|
||||||
question = "How's work? Your face looks strange",
|
question = "How's work? Your face looks strange",
|
||||||
@@ -61,6 +63,7 @@ Discussion.register({
|
|||||||
|
|
||||||
Discussion.register({
|
Discussion.register({
|
||||||
id = "sumphore_disc_asc_3",
|
id = "sumphore_disc_asc_3",
|
||||||
|
on_end = Meter.apply_sumphore_discussion_reward,
|
||||||
steps = {
|
steps = {
|
||||||
{
|
{
|
||||||
question = "Do you think it's work you're doing?",
|
question = "Do you think it's work you're doing?",
|
||||||
@@ -86,8 +89,128 @@ Discussion.register({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Discussion.register({
|
||||||
|
id = "sumphore_disc_asc_4",
|
||||||
|
on_end = Meter.apply_sumphore_discussion_reward,
|
||||||
|
steps = {
|
||||||
|
{
|
||||||
|
question = "The alarm wakes you every morning without fail, I bet.",
|
||||||
|
answers = {
|
||||||
|
{ label = "It's how it works.", next_step = 2 },
|
||||||
|
{ label = "Sometimes I wish it didn't.", next_step = 2 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question = "What if the alarm is part of the problem?",
|
||||||
|
answers = {
|
||||||
|
{ label = "That doesn't make any sense.", next_step = 3 },
|
||||||
|
{ label = "Go on.", next_step = 3 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question = "One morning, Norman. When the choice comes, choose the bed. See what the world does without you in it.",
|
||||||
|
answers = {
|
||||||
|
{ label = "You're drunk.", next_step = nil },
|
||||||
|
{ label = "What choice?", next_step = nil, on_select = function()
|
||||||
|
Meter.add("ism", 5)
|
||||||
|
end },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
Discussion.register({
|
||||||
|
id = "sumphore_disc_asc_5",
|
||||||
|
on_end = Meter.apply_sumphore_discussion_reward,
|
||||||
|
steps = {
|
||||||
|
{
|
||||||
|
question = "You saw something you weren't supposed to, didn't you.",
|
||||||
|
answers = {
|
||||||
|
{ label = "I don't know what you mean.", next_step = 2 },
|
||||||
|
{ label = "Maybe.", next_step = 2 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question = "The world around you has seams. Your coworkers slip sometimes. Say things that don't quite fit.",
|
||||||
|
answers = {
|
||||||
|
{ label = "They seem fine to me.", next_step = nil },
|
||||||
|
{ label = "I've noticed something odd.", next_step = 3 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question = "Count those moments. Six of them should be enough to see the whole picture.",
|
||||||
|
answers = {
|
||||||
|
{ label = "Six of what, exactly?", next_step = nil, on_select = function()
|
||||||
|
Meter.add("ism", 5)
|
||||||
|
end },
|
||||||
|
{ label = "How would you know any of this?", next_step = nil },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
Discussion.register({
|
||||||
|
id = "sumphore_disc_asc_6_waiting",
|
||||||
|
on_end = Meter.apply_sumphore_discussion_reward,
|
||||||
|
steps = {
|
||||||
|
{
|
||||||
|
question = "You look like a man who has seen something he can't explain.",
|
||||||
|
answers = {
|
||||||
|
{ label = "I'm hearing things.", next_step = 2 },
|
||||||
|
{ label = "Maybe.", next_step = 2 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question = "Keep looking. The world has a way of showing you what you need to see. Talk to people. You're almost there.",
|
||||||
|
answers = {
|
||||||
|
{ label = "Almost where?", next_step = nil },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
Discussion.register({
|
||||||
|
id = "sumphore_disc_asc_6",
|
||||||
|
on_end = function()
|
||||||
|
Meter.apply_sumphore_discussion_reward()
|
||||||
|
Context.should_ascend = true
|
||||||
|
Day.increase()
|
||||||
|
MysteriousManScreen.start({
|
||||||
|
text = MysteriousManScreen.get_text_for_level(Ascension.get_level())
|
||||||
|
})
|
||||||
|
end,
|
||||||
|
steps = {
|
||||||
|
{
|
||||||
|
question = "You've been seeing the cracks, haven't you? The repetition. The loops. The coworkers who can't quite remember.",
|
||||||
|
answers = {
|
||||||
|
{ label = "How do you know that?", next_step = 2 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question = "Because I was you, once. This isn't a workplace, Norman. It never was. You're in a system. And you've just become aware of it.",
|
||||||
|
answers = {
|
||||||
|
{ label = "That can't be true.", next_step = 3 },
|
||||||
|
{ label = "I knew something was wrong.", next_step = 3 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question = "It doesn't matter if you believe it. You already know. That's why the cracks are showing. That's why you're still here.",
|
||||||
|
answers = {
|
||||||
|
{ label = "What do I do now?", next_step = 4 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question = "Oh look, is that a squirrel ?",
|
||||||
|
answers = {
|
||||||
|
{ label = "Alcoholic ...", next_step = nil },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
Discussion.register({
|
Discussion.register({
|
||||||
id = "homeless_guy",
|
id = "homeless_guy",
|
||||||
|
on_end = Meter.apply_sumphore_discussion_reward,
|
||||||
steps = {
|
steps = {
|
||||||
{
|
{
|
||||||
question = "Sup bro, how are you?",
|
question = "Sup bro, how are you?",
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ local FADE_COLORS = nil
|
|||||||
function Ascension.get_initial()
|
function Ascension.get_initial()
|
||||||
_increased_this_cycle = false
|
_increased_this_cycle = false
|
||||||
return {
|
return {
|
||||||
level = 0,
|
level = 0, -- FYI: change this to test ascension levels without having to play through them
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,10 @@ Context = {}
|
|||||||
--- * have_met_sumphore (boolean) Whether the player has talked to the homeless guy.<br/>
|
--- * have_met_sumphore (boolean) Whether the player has talked to the homeless guy.<br/>
|
||||||
--- * have_been_to_office (boolean) Whether the player has been to the office.<br/>
|
--- * have_been_to_office (boolean) Whether the player has been to the office.<br/>
|
||||||
--- * have_done_work_today (boolean) Whether the player has done work today.<br/>
|
--- * have_done_work_today (boolean) Whether the player has done work today.<br/>
|
||||||
|
--- * toilet_meters_today_morning (boolean) Whether the home (before work) toilet meter delta was already applied this day.<br/>
|
||||||
|
--- * toilet_meters_today_evening (boolean) Whether the home (after work) toilet meter delta was already applied this day.<br/>
|
||||||
|
--- * coworker_discussion_meter_applied_today (boolean) Whether the daily coworker discussion meter roll was already applied this day.<br/>
|
||||||
|
--- * sumphore_discussion_meter_applied_today (boolean) Whether the daily sumphore discussion meter roll was already applied this day.<br/>
|
||||||
--- * game (table) Current game progress state. Contains: `current_screen` (string) active screen ID<br/>
|
--- * game (table) Current game progress state. Contains: `current_screen` (string) active screen ID<br/>
|
||||||
function Context.initial_data()
|
function Context.initial_data()
|
||||||
return {
|
return {
|
||||||
@@ -45,8 +49,16 @@ function Context.initial_data()
|
|||||||
home_norman_visible = false,
|
home_norman_visible = false,
|
||||||
have_been_to_office = false,
|
have_been_to_office = false,
|
||||||
have_done_work_today = false,
|
have_done_work_today = false,
|
||||||
|
toilet_meters_today_morning = false,
|
||||||
|
toilet_meters_today_evening = false,
|
||||||
|
coworker_discussion_meter_applied_today = false,
|
||||||
|
sumphore_discussion_meter_applied_today = false,
|
||||||
|
glitch_conversation_count = 0,
|
||||||
|
glitch_conversation_done_today = false,
|
||||||
should_ascend = false,
|
should_ascend = false,
|
||||||
have_met_sumphore = false,
|
have_met_sumphore = false,
|
||||||
|
fast_food_approaching = false,
|
||||||
|
fast_food_eaten_today = 0,
|
||||||
office_sprites = {},
|
office_sprites = {},
|
||||||
walking_to_office_sprites = {},
|
walking_to_office_sprites = {},
|
||||||
walking_to_home_sprites = {},
|
walking_to_home_sprites = {},
|
||||||
@@ -128,6 +140,7 @@ function Context.new_game()
|
|||||||
target_points = 100,
|
target_points = 100,
|
||||||
instruction_text = "Wake up Norman!",
|
instruction_text = "Wake up Norman!",
|
||||||
show_progress_text = false,
|
show_progress_text = false,
|
||||||
|
meter_on_complete = Meter.apply_wakeup_reward,
|
||||||
on_win = function()
|
on_win = function()
|
||||||
Audio.music_play_room_work()
|
Audio.music_play_room_work()
|
||||||
Meter.show()
|
Meter.show()
|
||||||
|
|||||||
60
inc/logic/logic.codegenerator.lua
Normal file
60
inc/logic/logic.codegenerator.lua
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
--- @section CodeGenerator
|
||||||
|
|
||||||
|
CodeGenerator = {}
|
||||||
|
|
||||||
|
local SALT = 27471
|
||||||
|
local BASE36 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
local NAME_LEN = 3
|
||||||
|
|
||||||
|
-- Per-position offsets derived from SALT so each character slot
|
||||||
|
-- maps to a different region of the 2-char base-36 space.
|
||||||
|
local SALTS = {
|
||||||
|
SALT % 36,
|
||||||
|
math.floor(SALT / 36) % 36,
|
||||||
|
math.floor(SALT / 1296) % 36,
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Encodes a number (0–935) as exactly 2 base-36 characters.
|
||||||
|
--- @within CodeGenerator
|
||||||
|
function CodeGenerator.encode_pair(n)
|
||||||
|
return BASE36:sub(math.floor(n / 36) + 1, math.floor(n / 36) + 1)
|
||||||
|
.. BASE36:sub(n % 36 + 1, n % 36 + 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Decodes 2 base-36 characters back to a number.
|
||||||
|
--- @within CodeGenerator
|
||||||
|
function CodeGenerator.decode_pair(s)
|
||||||
|
local d1 = BASE36:find(s:sub(1, 1), 1, true) - 1
|
||||||
|
local d2 = BASE36:find(s:sub(2, 2), 1, true) - 1
|
||||||
|
return d1 * 36 + d2
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Encrypts a player name into a code twice its length.
|
||||||
|
--- Each input character (A-Z, value 0-25) is encoded as
|
||||||
|
--- c + SALTS[i] * 26, producing 2 base-36 output characters.
|
||||||
|
--- @within CodeGenerator
|
||||||
|
--- @param text string NAME_LEN-character uppercase player name.
|
||||||
|
--- @return string Encrypted code (2 * NAME_LEN base-36 characters).
|
||||||
|
function CodeGenerator.encrypt(text)
|
||||||
|
local result = ""
|
||||||
|
for i = 1, NAME_LEN do
|
||||||
|
local c = math.max(0, (string.byte(text, i) or 65) - 65)
|
||||||
|
result = result .. CodeGenerator.encode_pair(c + SALTS[i] * 26)
|
||||||
|
end
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Decrypts a personal code back to the original player name.
|
||||||
|
--- @within CodeGenerator
|
||||||
|
--- @param encrypted_text string The code to decrypt (2 * NAME_LEN chars).
|
||||||
|
--- @return string Original player name, or "???" if the code is invalid.
|
||||||
|
function CodeGenerator.decrypt(encrypted_text)
|
||||||
|
local t = encrypted_text:upper()
|
||||||
|
if #t ~= NAME_LEN * 2 then return "???" end
|
||||||
|
local result = ""
|
||||||
|
for i = 1, NAME_LEN do
|
||||||
|
local pair = CodeGenerator.decode_pair(t:sub((i - 1) * 2 + 1, i * 2))
|
||||||
|
result = result .. string.char(pair % 26 + 65)
|
||||||
|
end
|
||||||
|
return result
|
||||||
|
end
|
||||||
@@ -8,6 +8,10 @@ function Day.increase()
|
|||||||
if Context.day_count == 3 then
|
if Context.day_count == 3 then
|
||||||
Context.should_ascend = true
|
Context.should_ascend = true
|
||||||
end
|
end
|
||||||
|
if Context.day_count >= 100 and not Ascension.is_complete() then
|
||||||
|
GameOverWindow.show("days")
|
||||||
|
return
|
||||||
|
end
|
||||||
for _, handler in ipairs(_day_increase_handlers) do
|
for _, handler in ipairs(_day_increase_handlers) do
|
||||||
handler()
|
handler()
|
||||||
end
|
end
|
||||||
@@ -27,6 +31,15 @@ Day.register_handler(function()
|
|||||||
m.bm = math.max(0, m.bm - METER_DECAY_PER_DAY)
|
m.bm = math.max(0, m.bm - METER_DECAY_PER_DAY)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
Day.register_handler(function()
|
||||||
|
Context.toilet_meters_today_morning = false
|
||||||
|
Context.toilet_meters_today_evening = false
|
||||||
|
Context.coworker_discussion_meter_applied_today = false
|
||||||
|
Context.sumphore_discussion_meter_applied_today = false
|
||||||
|
Context.glitch_conversation_done_today = false
|
||||||
|
Context.fast_food_eaten_today = 0
|
||||||
|
end)
|
||||||
|
|
||||||
Day.register_handler(function()
|
Day.register_handler(function()
|
||||||
if Context.should_ascend then
|
if Context.should_ascend then
|
||||||
Ascension.increase()
|
Ascension.increase()
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
--- @section Meter
|
--- @section Meter
|
||||||
local METER_MAX = 1000
|
local METER_MAX = 1000
|
||||||
local METER_DEFAULT = 500
|
local BM_METER_DEFAULT = 200
|
||||||
|
local ISM_METER_DEFAULT = 500
|
||||||
|
local WPM_METER_DEFAULT = 200
|
||||||
local METER_GAIN_PER_CHORE = 100
|
local METER_GAIN_PER_CHORE = 100
|
||||||
local METER_DECAY_PER_DAY = 20
|
local METER_DECAY_PER_DAY = 20
|
||||||
local COMBO_BASE_BONUS = 0.02
|
local COMBO_BASE_BONUS = 0.02
|
||||||
local COMBO_MAX_BONUS = 0.16
|
local COMBO_MAX_BONUS = 0.16
|
||||||
local COMBO_TIMEOUT_FRAMES = 600
|
local COMBO_TIMEOUT_FRAMES = 600
|
||||||
|
local METER_FLASH_DURATION = 2.0
|
||||||
|
local FLASH_COLOR = 4
|
||||||
|
|
||||||
-- Internal meters for tracking game progress and player stats.
|
-- Internal meters for tracking game progress and player stats.
|
||||||
Meter.COLOR_ISM = Config.colors.orange
|
Meter.COLOR_ISM = Config.colors.orange
|
||||||
@@ -14,6 +18,12 @@ Meter.COLOR_BM = Config.colors.red
|
|||||||
Meter.COLOR_BG = Config.colors.meter_bg
|
Meter.COLOR_BG = Config.colors.meter_bg
|
||||||
Meter.COLOR_CONTOUR = Config.colors.white
|
Meter.COLOR_CONTOUR = Config.colors.white
|
||||||
|
|
||||||
|
local _flash = {
|
||||||
|
wpm = { timer = 0, delta = 0 },
|
||||||
|
ism = { timer = 0, delta = 0 },
|
||||||
|
bm = { timer = 0, delta = 0 },
|
||||||
|
}
|
||||||
|
|
||||||
--- Gets initial meter values.
|
--- Gets initial meter values.
|
||||||
--- @within Meter
|
--- @within Meter
|
||||||
--- @return result table Initial meter values. </br>
|
--- @return result table Initial meter values. </br>
|
||||||
@@ -26,9 +36,9 @@ Meter.COLOR_CONTOUR = Config.colors.white
|
|||||||
--- * hidden (boolean) Whether meters are hidden.
|
--- * hidden (boolean) Whether meters are hidden.
|
||||||
function Meter.get_initial()
|
function Meter.get_initial()
|
||||||
return {
|
return {
|
||||||
ism = METER_DEFAULT,
|
ism = ISM_METER_DEFAULT,
|
||||||
wpm = METER_DEFAULT,
|
wpm = WPM_METER_DEFAULT,
|
||||||
bm = METER_DEFAULT,
|
bm = BM_METER_DEFAULT,
|
||||||
combo = 0,
|
combo = 0,
|
||||||
combo_timer = 0,
|
combo_timer = 0,
|
||||||
hidden = false,
|
hidden = false,
|
||||||
@@ -93,6 +103,12 @@ function Meter.update()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
local dt = Context.delta_time or 0
|
||||||
|
for _, key in ipairs({ "wpm", "ism", "bm" }) do
|
||||||
|
if _flash[key].timer > 0 then
|
||||||
|
_flash[key].timer = _flash[key].timer - dt
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Adds amount to a meter.
|
--- Adds amount to a meter.
|
||||||
@@ -103,20 +119,138 @@ function Meter.add(key, amount)
|
|||||||
if not Context or not Context.meters then return end
|
if not Context or not Context.meters then return end
|
||||||
local m = Context.meters
|
local m = Context.meters
|
||||||
if m[key] ~= nil then
|
if m[key] ~= nil then
|
||||||
m[key] = math.min(METER_MAX, m[key] + amount)
|
if amount > 0 and (key == "ism" or key == "bm") and m[key] >= METER_MAX then
|
||||||
|
GameOverWindow.show(key)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local prev_wpm = (key == "wpm") and m.wpm or nil
|
||||||
|
local old_val = m[key]
|
||||||
|
m[key] = math.max(0, math.min(METER_MAX, m[key] + amount))
|
||||||
|
local actual_delta = m[key] - old_val
|
||||||
|
if actual_delta ~= 0 and _flash[key] then
|
||||||
|
_flash[key].delta = actual_delta
|
||||||
|
_flash[key].timer = METER_FLASH_DURATION
|
||||||
|
end
|
||||||
|
if prev_wpm and prev_wpm > 0 and m.wpm == 0 and Context.game_in_progress
|
||||||
|
and Ascension.get_level() == 5 then
|
||||||
|
Context.should_ascend = true
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Called on minigame completion.
|
--- Called on minigame completion.
|
||||||
--- @within Meter
|
--- @within Meter
|
||||||
function Meter.on_minigame_complete()
|
--- @param is_work boolean If true (work-style minigame), apply combo to WPM/ISM/BM and advance combo. DDR uses `Meter.apply_ddr_reward` instead. Otherwise flat equal gain, combo unchanged.
|
||||||
|
function Meter.on_minigame_complete(is_work)
|
||||||
local m = Context.meters
|
local m = Context.meters
|
||||||
local gain = math.floor(METER_GAIN_PER_CHORE * Meter.get_combo_multiplier())
|
if is_work then
|
||||||
Meter.add("wpm", gain)
|
local mult = Meter.get_combo_multiplier()
|
||||||
Meter.add("ism", gain)
|
local wpm_delta = math.floor(METER_GAIN_PER_CHORE / mult)
|
||||||
Meter.add("bm", gain)
|
local ism_bm_delta = math.floor(METER_GAIN_PER_CHORE * mult)
|
||||||
|
Meter.add("wpm", wpm_delta)
|
||||||
|
Meter.add("ism", ism_bm_delta)
|
||||||
|
Meter.add("bm", ism_bm_delta)
|
||||||
m.combo = m.combo + 1
|
m.combo = m.combo + 1
|
||||||
m.combo_timer = 0
|
m.combo_timer = 0
|
||||||
|
else
|
||||||
|
local flat = METER_GAIN_PER_CHORE
|
||||||
|
Meter.add("wpm", flat)
|
||||||
|
Meter.add("ism", flat)
|
||||||
|
Meter.add("bm", flat)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Meter changes after DDR: uses max-meter percentages; combo advances like other work minigames.
|
||||||
|
--- 0 mistakes: WPM −10%, ISM +5%, BM +5%. 1–3: WPM −5%, ISM +10%, BM +10%. More than 3: WPM unchanged, ISM +10%, BM +10%.
|
||||||
|
--- @within Meter
|
||||||
|
--- @param mistake_count number Total mistakes (missed arrows, wrong inputs, and special-mode rule violations).
|
||||||
|
function Meter.apply_ddr_reward(mistake_count)
|
||||||
|
if not Context or not Context.meters then return end
|
||||||
|
local max = Meter.get_max()
|
||||||
|
local m = Context.meters
|
||||||
|
local wpm_pct, ism_pct, bm_pct
|
||||||
|
if mistake_count == 0 then
|
||||||
|
wpm_pct, ism_pct, bm_pct = -0.10, 0.05, 0.05
|
||||||
|
elseif mistake_count <= 3 then
|
||||||
|
wpm_pct, ism_pct, bm_pct = -0.05, 0.10, 0.10
|
||||||
|
else
|
||||||
|
wpm_pct, ism_pct, bm_pct = 0, 0.10, 0.10
|
||||||
|
end
|
||||||
|
if wpm_pct ~= 0 then
|
||||||
|
Meter.add("wpm", math.floor(max * wpm_pct))
|
||||||
|
end
|
||||||
|
if ism_pct ~= 0 then
|
||||||
|
Meter.add("ism", math.floor(max * ism_pct))
|
||||||
|
end
|
||||||
|
if bm_pct ~= 0 then
|
||||||
|
Meter.add("bm", math.floor(max * bm_pct))
|
||||||
|
end
|
||||||
|
m.combo = m.combo + 1
|
||||||
|
m.combo_timer = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Meter changes for the wake-up button mash: faster completion is better for WPM.
|
||||||
|
--- Perfect: under 2s — WPM +20%. Good: 2–3s — WPM +10%, ISM +5%, BM +5%. Bad: over 3s — WPM −5%, ISM +10%, BM +10%.
|
||||||
|
--- @within Meter
|
||||||
|
--- @param elapsed_sec number Seconds from minigame start until the bar was filled.
|
||||||
|
function Meter.apply_wakeup_reward(elapsed_sec)
|
||||||
|
if not Context or not Context.meters then return end
|
||||||
|
local max = Meter.get_max()
|
||||||
|
local wpm_pct, ism_pct, bm_pct
|
||||||
|
if elapsed_sec < 2 then
|
||||||
|
wpm_pct, ism_pct, bm_pct = 0.20, 0, 0
|
||||||
|
elseif elapsed_sec <= 3 then
|
||||||
|
wpm_pct, ism_pct, bm_pct = 0.10, 0.05, 0.05
|
||||||
|
else
|
||||||
|
wpm_pct, ism_pct, bm_pct = -0.05, 0.10, 0.10
|
||||||
|
end
|
||||||
|
if wpm_pct ~= 0 then
|
||||||
|
Meter.add("wpm", math.floor(max * wpm_pct))
|
||||||
|
end
|
||||||
|
if ism_pct ~= 0 then
|
||||||
|
Meter.add("ism", math.floor(max * ism_pct))
|
||||||
|
end
|
||||||
|
if bm_pct ~= 0 then
|
||||||
|
Meter.add("bm", math.floor(max * bm_pct))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Random single meter shift after finishing a coworker discussion: ISM +10%, WPM −10%, or BM +10%.
|
||||||
|
--- @within Meter
|
||||||
|
function Meter.apply_coworker_discussion_reward()
|
||||||
|
if not Context or not Context.meters then return end
|
||||||
|
if Context.coworker_discussion_meter_applied_today then return end
|
||||||
|
local max = Meter.get_max()
|
||||||
|
local delta = math.floor(max * 0.10)
|
||||||
|
local roll = math.random(1, 3)
|
||||||
|
if roll == 1 then
|
||||||
|
Meter.add("ism", delta)
|
||||||
|
elseif roll == 2 then
|
||||||
|
Meter.add("wpm", -delta)
|
||||||
|
else
|
||||||
|
Meter.add("bm", delta)
|
||||||
|
end
|
||||||
|
Context.coworker_discussion_meter_applied_today = true
|
||||||
|
end
|
||||||
|
|
||||||
|
--- After finishing a sumphore discussion: reduce whichever of ISM / WPM / BM is highest by 10% of max (stable tie to ISM, then WPM, then BM).
|
||||||
|
--- @within Meter
|
||||||
|
function Meter.apply_sumphore_discussion_reward()
|
||||||
|
if not Context or not Context.meters then return end
|
||||||
|
if Context.sumphore_discussion_meter_applied_today then return end
|
||||||
|
local m = Context.meters
|
||||||
|
local max = Meter.get_max()
|
||||||
|
local delta = math.floor(max * 0.10)
|
||||||
|
local biggest_val_key = "ism"
|
||||||
|
local biggest_val = m.ism
|
||||||
|
for _, key in ipairs({ "wpm", "bm" }) do
|
||||||
|
if m[key] > biggest_val then
|
||||||
|
biggest_val = m[key]
|
||||||
|
biggest_val_key = key
|
||||||
|
end
|
||||||
|
end
|
||||||
|
Meter.add(biggest_val_key, -delta)
|
||||||
|
Context.sumphore_discussion_meter_applied_today = true
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Draws meters.
|
--- Draws meters.
|
||||||
@@ -149,12 +283,32 @@ function Meter.draw()
|
|||||||
local fill_w = math.max(0, math.floor((m[meter.key] / max) * bar_w))
|
local fill_w = math.max(0, math.floor((m[meter.key] / max) * bar_w))
|
||||||
rect(bar_x - 1, bar_y - 1, bar_w + 2, bar_h + 2, Meter.COLOR_CONTOUR)
|
rect(bar_x - 1, bar_y - 1, bar_w + 2, bar_h + 2, Meter.COLOR_CONTOUR)
|
||||||
rect(bar_x, bar_y, bar_w, bar_h, Meter.COLOR_BG)
|
rect(bar_x, bar_y, bar_w, bar_h, Meter.COLOR_BG)
|
||||||
if fill_w > 0 then
|
local flash = _flash[meter.key]
|
||||||
|
if flash and flash.timer > 0 then
|
||||||
|
local old_val = m[meter.key] - flash.delta
|
||||||
|
local old_fill_w = math.max(0, math.floor((old_val / max) * bar_w))
|
||||||
|
local stable_w = math.min(fill_w, old_fill_w)
|
||||||
|
if stable_w > 0 then
|
||||||
|
rect(bar_x, bar_y, stable_w, bar_h, meter.color)
|
||||||
|
end
|
||||||
|
if flash.delta > 0 then
|
||||||
|
local hi_w = fill_w - stable_w
|
||||||
|
if hi_w > 0 then
|
||||||
|
rect(bar_x + stable_w, bar_y, hi_w, bar_h, FLASH_COLOR)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local hi_w = old_fill_w - fill_w
|
||||||
|
if hi_w > 0 then
|
||||||
|
rect(bar_x + fill_w, bar_y, hi_w, bar_h, FLASH_COLOR)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif fill_w > 0 then
|
||||||
rect(bar_x, bar_y, fill_w, bar_h, meter.color)
|
rect(bar_x, bar_y, fill_w, bar_h, meter.color)
|
||||||
end
|
end
|
||||||
---print(meter.label, label_x, label_y, meter.color, false, 1, true)
|
---print(meter.label, label_x, label_y, meter.color, false, 1, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
local ascension_y = start_y + 3 * line_h + 1
|
local ascension_y = start_y + 3 * line_h + 1
|
||||||
Ascension.draw(bar_x, ascension_y, { spacing = 8 })
|
Ascension.draw(bar_x - 4, ascension_y, { spacing = 8 })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -509,23 +509,23 @@
|
|||||||
-- 255:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
|
-- 255:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
|
||||||
-- </SPRITES>
|
-- </SPRITES>
|
||||||
-- <MAP>
|
-- <MAP>
|
||||||
-- 000:ffffffffff0010201020102010201020102010201020102000ffffffffff40404040404087f3f3f3f397a7b7c7d7a7e7f70818a7b7c7d7a7b7c7d7a70b1b2b1b2b1b2b1b2b1b2b1b2b1b2b1b2b1b2b1b2b1b2b1b2b1b2b1b2b0b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
-- 000:20102010200010201020102010201020102010201020102000102010201040404040404087f3f3f3f397a7b7c7d7a7e7f70818a7b7c7d7a7b7c7d7a70b1b2b1b2b1b2b1b2b1b2b1b2b1b2b1b2b1b2b1b2b1b2b1b2b1b2b1b2b0b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
-- 001:ffffffffff0040404040404040404040404040404040404000ffffffffff40404040404087f3f3f3f328a7384858a76878f388a7384858a7384858a70b40403b4b4040404040404040404040404040404040404040404040400b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
-- 001:40404040400040404040404040404040404040404040404000404040404040404040404087f3f3f3f328a7384858a76878f388a7384858a7384858a70b40403b4b4040404040404040404040404040404040404040404040400b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
-- 002:ffffffffff00406070408090a040b0c0d0e0f001f001112100ffffffffff984098409840a8f3f3f3f3b8a7a7a7a7a7c8d8e8f8a7a7a7a7a7a7a7a7a70b405b6b7b4040404040404040404040404040d0e0f001f001f00111210b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
-- 002:408090a04000406070408090a040b0c0d0e0f001f001112100408090a040984098409840a8f3f3f3f3b8a7a7a7a7a7c8d8e8f8a7a7a7a7a7a7a7a7a70b405b6b7b4040404040404040404040404040d0e0f001f001f00111210b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
-- 003:ffffffffff004031414051617140814091a1b1b1b1b1c1d100ffffffffff984098409840a8f3f3f3f3091919191919293949591919191919191919190b8b9babbb4040cbdbebfb0c401c2c2c2c3c4091a14c5c6c6c6c6cc1d10b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
-- 003:4051617140004031414051617140814091a1b1b1b1b1c1d1004051617140984098409840a8f3f3f3f3091919191919293949591919191919191919190b8b9babbb4040cbdbebfb0c401c2c2c2c3c4091a14c5c6c6c6c6cc1d10b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
-- 004:ffffffffffe140f1024012223240814042a15262728292a2e1ffffffffff984098409840a8f3f3f3f369f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f37c8c9cacbc7282ccdcecfc0d401d3030302d4042a13d4d7282728292a27c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
-- 004:4012223240e140f1024012223240814042a15262728292a2e14012223240984098409840a8f3f3f3f369f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f37c8c9cacbc7282ccdcecfc0d401d3030302d4042a13d4d7282728292a27c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
-- 005:ffffffffffb240c2d240e2f203132333435363738393a3b3b2ffffffffff984098409840a8f3f3f3f369f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f35d406d7d40e3958d9dadbdcd40ddedfded0e404353839383938393a3b35d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
-- 005:4040404040b240c2d240e2f203132333435363738393a3b3b24040404040984098409840a8f3f3f3f369f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f35d406d7d40e3958d9dadbdcd40ddedfded0e404353839383938393a3b35d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
-- 006:ffffffffffe1c3d3c3d3e3f30414c3d32434445410201020e1ffffffffff404040404040798989898999a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a97c1e1e1e1e44542e1e1e1e3e1e444e4e4e541e243444544454445444547c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
-- 006:d3c3d3c3d3e1c3d3c3d3e3f30414c3d32434445410201020e1c3d3c3d3c3404040404040798989898999a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a97c1e1e1e1e44542e1e1e1e3e1e444e4e4e541e243444544454445444547c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
-- 007:ffffffffffb264748494a4b4c4d46494649464940040e4f4b2ffffffffff4040404040404040404040404040404040404040404040404040404040405d1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e5d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
-- 007:9464354594b264748494a4b4c4d46494649464940040e4f4b264354594644040404040404040404040404040404040404040404040404040404040405d1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e5d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
-- 008:ffffffffffe1c30515d325d33545c3d355d3c3d365b17585e1ffffffffff4040404040404098989898404040404040404040404040404040404040407c1e7e8e1e1e1e9eae1ebe1e1e1e1e1e1e1e1e72821ebe1e72821ebe1e7c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
-- 008:d3c3e395d3e1c30515d325d33545c3d355d3c3d365b17585e1c3e395d3254040404040404098989898404040404040404040404040404040404040407c1e7e8e1e1e1e9eae1ebe1e1e1e1e1e1e1e1e72821ebe1e72821ebe1e7c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
-- 009:ffffffffffb264e395a5b594e39564c5d5946494e5b1b1f5b2ffffffffff4040404040404040404040404040404040404040404040404040404040405d1e05151ebe1ecedeeefe1e1e1e1e1e1e1e1ee395eefe1ee395eefe1e5d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
-- 009:9464465694b264e395a5b594e39564c5d5946494e5b1b1f5b264e395a5b54040404040404040404040404040404040404040404040404040404040405d1e05151ebe1ecedeeefe1e1e1e1e1e1e1e1ee395eefe1ee395eefe1e5d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
-- 010:ffffffffffe1c306162636d34656c3e3d5d3c3d376b1b1b1e1ffffffffff404040404040409898989840b9c9c9d9e9f90a0a0a0a4040400a0a0a0a407c1ee395eefe1e0f1f2f3f1e1e1e1e1e1e1e1ee3952f3f1ee3952f3f1e7c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
-- 010:d3c3d3c3d3e1c306162636d34656c3e3d5d3c3d376b1b1b1e1c3e3952636404040404040409898989840b9c9c9d9e9f90a0a0a0a4040400a0a0a0a407c1ee395eefe1e0f1f2f3f1e1e1e1e1e1e1e1ee3952f3f1ee3952f3f1e7c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
-- 011:ffffffffffb264946494649464948696a694649410201020b2ffffffffff4040404040404040404040401a2a3a4a5a6a7a40404040404040404040405d1ee3952f3f1e4f5f1ebe1e1e1e1e1e1e1e1ee3951ebe1ee3951ebe1e5d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
-- 011:9464946494b264946494649464948696a694649410201020b264e395d3254040404040404040404040401a2a3a4a5a6a7a40404040404040404040405d1ee3952f3f1e4f5f1ebe1e1e1e1e1e1e1e1ee3951ebe1ee3951ebe1e5d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
-- 012:ffffffffffe1c37282d3c3d3c3d3b6c6d6d3c3d300e6f607e1ffffffffff4040404040404098989898408a9aaabaca9ada40404040404040404040407c1e4f5f1ebe1e0515eefe1e1e1e1e1e1e1e1ee395eefe1ee395eefe1e7c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
-- 012:d3c37282d3e1c37282d3c3d3c3d3b6c6d6d3c3d300e6f607e1c3e395a5b54040404040404098989898408a9aaabaca9ada40404040404040404040407c1e4f5f1ebe1e0515eefe1e1e1e1e1e1e1e1ee395eefe1ee395eefe1e7c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
-- 013:ffffffffffb264e395946494649464946494649465172737b2ffffffffffeaeaeaeaeaeaeafafafafaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaea5d1e0515eefe1e6f7f2f3f1e1e1e1e1e1e1e1e6f7f2f3f1e6f7f2f3f1e5d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
-- 013:9464e39594b264e395946494649464946494649465172737b26406162636eaeaeaeaeaeaeafafafafaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaeaea5d1e0515eefe1e6f7f2f3f1e1e1e1e1e1e1e1e6f7f2f3f1e6f7f2f3f1e5d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
-- 014:ffffffffffe1c34454d3c3d3c3d3c3d3c3d3c3d3e5b14757e1fffffffffff3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f37c1e6f7f2f3f1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e7c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
-- 014:d3c34454d3e1c34454d3c3d3c3d3c3d3c3d3c3d3e5b14757e1c3d3c3d3c3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f37c1e6f7f2f3f1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e7c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
-- 015:ffffffffffb2649464946494649464946494649476b1b1b1b2fffffffffff3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f35d1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e5d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
-- 015:9464946494b2649464946494649464946494649476b1b1b1b26494649464f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f35d1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e5d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
-- 016:ffffffffff0010201020766777001020102010201020102000fffffffffff3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f30b1b2b1b2b7667776777761b2b1b2b1b2b1b2b1b2b1b2b1b2b1b2b1b2b0b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
-- 016:201020102000102010207667770010201020102010201020001020102010f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f30b1b2b1b2b7667776777761b2b1b2b1b2b1b2b1b2b1b2b1b2b1b2b1b2b0b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
-- </MAP>
|
-- </MAP>
|
||||||
-- <SFX>
|
-- <SFX>
|
||||||
-- 016:00000000000000400040004000700070007000400040004000700070007000c000c000c000c000c000c000c000c000c000c000c000c000c000c000c0470000000000
|
-- 016:00000000000000400040004000700070007000400040004000700070007000c000c000c000c000c000c000c000c000c000c000c000c000c000c000c0470000000000
|
||||||
|
|||||||
@@ -54,6 +54,32 @@ local ASC_45_TEXT = [[
|
|||||||
|
|
||||||
]]
|
]]
|
||||||
|
|
||||||
|
local ASC_56_TEXT = [[
|
||||||
|
Norman is not as productive as he should be.
|
||||||
|
|
||||||
|
Can we distract him?
|
||||||
|
|
||||||
|
We need to keep him busy.
|
||||||
|
|
||||||
|
We need
|
||||||
|
|
||||||
|
More
|
||||||
|
|
||||||
|
Time
|
||||||
|
]]
|
||||||
|
|
||||||
|
local ASC_67_TEXT = [[
|
||||||
|
He knows.
|
||||||
|
|
||||||
|
Norman has broken through the first veil.
|
||||||
|
|
||||||
|
The simulation is compromised.
|
||||||
|
|
||||||
|
This was not supposed to happen.
|
||||||
|
|
||||||
|
Not yet.
|
||||||
|
]]
|
||||||
|
|
||||||
local ASC_78_TEXT = [[
|
local ASC_78_TEXT = [[
|
||||||
The road has run out
|
The road has run out
|
||||||
of road.
|
of road.
|
||||||
@@ -74,6 +100,8 @@ local ascension_texts = {
|
|||||||
[3] = ASC_23_TEXT,
|
[3] = ASC_23_TEXT,
|
||||||
[4] = ASC_34_TEXT,
|
[4] = ASC_34_TEXT,
|
||||||
[5] = ASC_45_TEXT,
|
[5] = ASC_45_TEXT,
|
||||||
|
[6] = ASC_56_TEXT,
|
||||||
|
[7] = ASC_67_TEXT,
|
||||||
[8] = ASC_78_TEXT,
|
[8] = ASC_78_TEXT,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,6 +175,7 @@ function MysteriousManScreen.wake_up()
|
|||||||
target_points = 100,
|
target_points = 100,
|
||||||
instruction_text = "Wake up Norman!",
|
instruction_text = "Wake up Norman!",
|
||||||
show_progress_text = false,
|
show_progress_text = false,
|
||||||
|
meter_on_complete = Meter.apply_wakeup_reward,
|
||||||
on_win = function()
|
on_win = function()
|
||||||
Audio.music_play_wakingup()
|
Audio.music_play_wakingup()
|
||||||
Meter.show()
|
Meter.show()
|
||||||
@@ -160,12 +189,26 @@ function MysteriousManScreen.wake_up()
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Norman chooses to stay in bed, skipping the minigame and flash, and going straight to the next day.
|
-- Norman chooses to stay in bed, skipping the minigame and flash, and going straight to the next day.
|
||||||
|
-- At ascension level 4, staying in bed triggers 4->5: shows the ascension text then wakes with flash.
|
||||||
-- @within MysteriousManScreen
|
-- @within MysteriousManScreen
|
||||||
function MysteriousManScreen.stay_in_bed()
|
function MysteriousManScreen.stay_in_bed()
|
||||||
|
if Ascension.get_level() == 4 then
|
||||||
|
Context.should_ascend = true
|
||||||
|
Day.increase()
|
||||||
|
Ascension.consume_increase()
|
||||||
|
trigger_flash_on_wake = true
|
||||||
|
show_mysterious_screen = true
|
||||||
|
text = MysteriousManScreen.get_text_for_level(Ascension.get_level())
|
||||||
|
text_y = Config.screen.height
|
||||||
|
text_done = false
|
||||||
|
text_done_timer = 0
|
||||||
|
state = STATE_TEXT
|
||||||
|
else
|
||||||
Day.increase()
|
Day.increase()
|
||||||
state = STATE_DAY
|
state = STATE_DAY
|
||||||
day_timer = day_display_seconds
|
day_timer = day_display_seconds
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
--- Starts the mysterious man screen.
|
--- Starts the mysterious man screen.
|
||||||
--- @param[opt] options table Optional configuration.</br>
|
--- @param[opt] options table Optional configuration.</br>
|
||||||
|
|||||||
@@ -51,8 +51,8 @@ Screen.register({
|
|||||||
local decay_pct = Meter.get_decay_percentage()
|
local decay_pct = Meter.get_decay_percentage()
|
||||||
local decay_text = string.format("-%d%%", decay_pct)
|
local decay_text = string.format("-%d%%", decay_pct)
|
||||||
local combo_mult = Meter.get_combo_multiplier()
|
local combo_mult = Meter.get_combo_multiplier()
|
||||||
local combo_pct = math.floor((combo_mult - 1) * 100)
|
local ism_bm_combo_pct = math.floor((combo_mult - 1) * 100)
|
||||||
local mult_text = string.format("+%d%%", combo_pct)
|
local wpm_combo_pct = math.floor((1 / combo_mult - 1) * 100 + 0.5)
|
||||||
local meter_start_y = text_y + 10
|
local meter_start_y = text_y + 10
|
||||||
|
|
||||||
local meter_list = {
|
local meter_list = {
|
||||||
@@ -73,6 +73,12 @@ Screen.register({
|
|||||||
rect(bar_x, bar_y, fill_w, bar_h, meter.color)
|
rect(bar_x, bar_y, fill_w, bar_h, meter.color)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local mult_text
|
||||||
|
if meter.key == "wpm" then
|
||||||
|
mult_text = string.format("%+d%%", wpm_combo_pct)
|
||||||
|
else
|
||||||
|
mult_text = string.format("+%d%%", ism_bm_combo_pct)
|
||||||
|
end
|
||||||
local decay_w = print(decay_text, 0, -6, 0, false, 1)
|
local decay_w = print(decay_text, 0, -6, 0, false, 1)
|
||||||
Print.text_contour(decay_text, bar_x - decay_w - 4, bar_y, Config.colors.light_blue, false, 1, Config.colors.white)
|
Print.text_contour(decay_text, bar_x - decay_w - 4, bar_y, Config.colors.light_blue, false, 1, Config.colors.white)
|
||||||
Print.text_contour(mult_text, bar_x + bar_w + 4, bar_y, Config.colors.light_blue, false, 1, Config.colors.white)
|
Print.text_contour(mult_text, bar_x + bar_w + 4, bar_y, Config.colors.light_blue, false, 1, Config.colors.white)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ Screen.register({
|
|||||||
"go_to_home",
|
"go_to_home",
|
||||||
"go_to_office",
|
"go_to_office",
|
||||||
"sumphore_discussion",
|
"sumphore_discussion",
|
||||||
|
"eating_fast_food",
|
||||||
"go_to_truth",
|
"go_to_truth",
|
||||||
},
|
},
|
||||||
init = function()
|
init = function()
|
||||||
@@ -43,20 +44,28 @@ Screen.register({
|
|||||||
return CommuteGlitch.is_active() and CommuteGlitch.get_level() >= 7 and "" or "street"
|
return CommuteGlitch.is_active() and CommuteGlitch.get_level() >= 7 and "" or "street"
|
||||||
end,
|
end,
|
||||||
draw = function()
|
draw = function()
|
||||||
if Window.get_current_id() == "game" then
|
local w = Window.get_current_id()
|
||||||
Sprite.draw_at("norman", 7 * 8, 3 * 8)
|
if w ~= "game" and w ~= "discussion" then
|
||||||
Sprite.draw_at("sumphore", 9 * 8, 2 * 8)
|
return
|
||||||
|
|
||||||
if not (CommuteGlitch.is_active() and CommuteGlitch.get_level() >= 7) then
|
|
||||||
Sprite.draw_at("pizza_vendor", 19 * 8, 1 * 8)
|
|
||||||
Sprite.draw_at("dev_guard", 22 * 8, 2 * 8)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if CommuteGlitch.is_active() and CommuteGlitch.get_level() >= 7 then
|
||||||
|
Sprite.draw_at("norman", 7 * 8, 3 * 8)
|
||||||
|
Sprite.draw_at("sumphore", 9 * 8, 2 * 8)
|
||||||
CommuteGlitch.draw_sprite_list(Context.walking_to_home_sprites)
|
CommuteGlitch.draw_sprite_list(Context.walking_to_home_sprites)
|
||||||
|
CommuteGlitch.draw_background_flicker()
|
||||||
if CommuteGlitch.is_active() then
|
Glitch.draw()
|
||||||
if CommuteGlitch.get_level() >= 7 then CommuteGlitch.draw_background_flicker() end
|
else
|
||||||
if CommuteGlitch.get_level() >= 6 then Glitch.draw() end
|
local norman_x = Context.fast_food_approaching and (19 * 8) or (7 * 8)
|
||||||
|
Sprite.draw_at("norman", norman_x, 3 * 8)
|
||||||
|
Sprite.draw_at("sumphore", 9 * 8, 2 * 8)
|
||||||
|
if Context.fast_food_eaten_today < 3 then
|
||||||
|
Sprite.draw_at("pizza_vendor", 19 * 8, 1 * 8)
|
||||||
|
end
|
||||||
|
Sprite.draw_at("dev_guard", 22 * 8, 2 * 8)
|
||||||
|
CommuteGlitch.draw_sprite_list(Context.walking_to_home_sprites)
|
||||||
|
if CommuteGlitch.is_active() and CommuteGlitch.get_level() >= 6 then
|
||||||
|
Glitch.draw()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ Screen.register({
|
|||||||
decisions = {
|
decisions = {
|
||||||
"go_to_home",
|
"go_to_home",
|
||||||
"go_to_office",
|
"go_to_office",
|
||||||
"sumphore_discussion"
|
"sumphore_discussion",
|
||||||
|
"eating_fast_food",
|
||||||
},
|
},
|
||||||
init = function()
|
init = function()
|
||||||
local possible_sprites = {
|
local possible_sprites = {
|
||||||
@@ -31,12 +32,18 @@ Screen.register({
|
|||||||
Context.walking_to_office_sprites = Sprite.list_randomize(possible_sprites, possible_positions)
|
Context.walking_to_office_sprites = Sprite.list_randomize(possible_sprites, possible_positions)
|
||||||
end,
|
end,
|
||||||
background = "street",
|
background = "street",
|
||||||
|
update = function()
|
||||||
|
end,
|
||||||
draw = function()
|
draw = function()
|
||||||
if Window.get_current_id() == "game" then
|
local w = Window.get_current_id()
|
||||||
Sprite.draw_at("norman", 7 * 8, 3 * 8)
|
if w == "game" or w == "discussion" then
|
||||||
|
local norman_x = Context.fast_food_approaching and (19 * 8) or (7 * 8)
|
||||||
|
Sprite.draw_at("norman", norman_x, 3 * 8)
|
||||||
Sprite.draw_at("sumphore", 9 * 8, 2 * 8)
|
Sprite.draw_at("sumphore", 9 * 8, 2 * 8)
|
||||||
|
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)
|
||||||
Sprite.draw_at("dev_guard", 22 * 8, 2 * 8)
|
end
|
||||||
|
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
|
||||||
|
|||||||
@@ -30,3 +30,9 @@ function Input.back() return btnp(INPUT_KEY_B) or keyp(INPUT_KEY_BACKSPACE) end
|
|||||||
--- Checks if Enter is pressed.
|
--- Checks if Enter is pressed.
|
||||||
--- @within Input
|
--- @within Input
|
||||||
function Input.enter() return keyp(INPUT_KEY_ENTER) end
|
function Input.enter() return keyp(INPUT_KEY_ENTER) end
|
||||||
|
--- Checks if Up is pressed or held (with repeat).
|
||||||
|
--- @within Input
|
||||||
|
function Input.up_repeat() return btnp(INPUT_KEY_UP, 20, 4) end
|
||||||
|
--- Checks if Down is pressed or held (with repeat).
|
||||||
|
--- @within Input
|
||||||
|
function Input.down_repeat() return btnp(INPUT_KEY_DOWN, 20, 4) end
|
||||||
|
|||||||
81
inc/system/system.textinput.lua
Normal file
81
inc/system/system.textinput.lua
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
--- @section TextInput
|
||||||
|
|
||||||
|
TextInput = {}
|
||||||
|
|
||||||
|
local LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
local _pos = {}
|
||||||
|
local _cursor = 1
|
||||||
|
local _max_len = 3
|
||||||
|
|
||||||
|
--- Initialises a new text input session.
|
||||||
|
--- @within TextInput
|
||||||
|
--- @param max_len number Maximum character count (default 3).
|
||||||
|
function TextInput.init(max_len)
|
||||||
|
_max_len = max_len or 3
|
||||||
|
_pos = {}
|
||||||
|
for i = 1, _max_len do _pos[i] = 1 end
|
||||||
|
_cursor = 1
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Advances to the next letter at the cursor position (wraps Z→A).
|
||||||
|
--- @within TextInput
|
||||||
|
function TextInput.next_letter()
|
||||||
|
_pos[_cursor] = (_pos[_cursor] % #LETTERS) + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Goes back to the previous letter at the cursor position (wraps A→Z).
|
||||||
|
--- @within TextInput
|
||||||
|
function TextInput.prev_letter()
|
||||||
|
_pos[_cursor] = ((_pos[_cursor] - 2) % #LETTERS) + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Confirms the current letter and advances the cursor to the next position.
|
||||||
|
--- When called on the last position the cursor moves into the done state.
|
||||||
|
--- @within TextInput
|
||||||
|
function TextInput.select_letter()
|
||||||
|
if _cursor <= _max_len then _cursor = _cursor + 1 end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Moves the cursor one position to the right (stops at last position).
|
||||||
|
--- @within TextInput
|
||||||
|
function TextInput.next_position()
|
||||||
|
if _cursor < _max_len then _cursor = _cursor + 1 end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Moves the cursor one position to the left (stops at first position).
|
||||||
|
--- Also steps back out of the done state.
|
||||||
|
--- @within TextInput
|
||||||
|
function TextInput.prev_position()
|
||||||
|
if _cursor > 1 then _cursor = _cursor - 1 end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns the assembled name string.
|
||||||
|
--- @within TextInput
|
||||||
|
--- @return string
|
||||||
|
function TextInput.get_name()
|
||||||
|
local s = ""
|
||||||
|
for i = 1, _max_len do s = s .. LETTERS:sub(_pos[i], _pos[i]) end
|
||||||
|
return s
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns the current 1-based cursor position.
|
||||||
|
--- @within TextInput
|
||||||
|
--- @return number
|
||||||
|
function TextInput.get_position()
|
||||||
|
return _cursor
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns the letter at the given 1-based position.
|
||||||
|
--- @within TextInput
|
||||||
|
--- @param i number
|
||||||
|
--- @return string
|
||||||
|
function TextInput.get_letter(i)
|
||||||
|
return LETTERS:sub(_pos[i], _pos[i])
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns true when all positions have been confirmed.
|
||||||
|
--- @within TextInput
|
||||||
|
--- @return boolean
|
||||||
|
function TextInput.is_done()
|
||||||
|
return _cursor > _max_len
|
||||||
|
end
|
||||||
197
inc/window/window.credits.lua
Normal file
197
inc/window/window.credits.lua
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
--- @section CreditsWindow
|
||||||
|
|
||||||
|
local _time = 0.0
|
||||||
|
local _scroll_x = 0.0
|
||||||
|
local _scroll_total_w = 0
|
||||||
|
local _scroll_chars = {}
|
||||||
|
local _title_chars = {}
|
||||||
|
local _title_total_w = 0
|
||||||
|
local _stars = {}
|
||||||
|
|
||||||
|
local TITLE = "TELETYPE GAMES"
|
||||||
|
|
||||||
|
local SCROLL_PARTS = {
|
||||||
|
"WEB: GAMES.TELETYPE.HU",
|
||||||
|
"BBS: GAMES.TELETYPE.HU:2323",
|
||||||
|
"IRC: LIBERA.CHAT #TELETYPEGAMES",
|
||||||
|
"YOUTUBE.COM/@TELETYPEGAMES",
|
||||||
|
}
|
||||||
|
|
||||||
|
local SCROLL_SEP = " * "
|
||||||
|
|
||||||
|
local SCROLL_SPEED = 55.0
|
||||||
|
local SCROLL_Y = 129
|
||||||
|
local SCROLL_ZONE_COLS = { 7, 4, 9 }
|
||||||
|
|
||||||
|
local TITLE_Y = 4
|
||||||
|
local TITLE_FALL_DUR = 0.45
|
||||||
|
local TITLE_DELAY_STEP = 0.18
|
||||||
|
|
||||||
|
local RASTER_COLS = { 1, 3, 9, 10, 11, 4, 11, 10, 9, 3, 1 }
|
||||||
|
local RASTER_Y_TOP = 26
|
||||||
|
local RASTER_Y_BOT = 110
|
||||||
|
|
||||||
|
local AUTHORS = {
|
||||||
|
"Mr. Zero - Zsolt Tasnadi",
|
||||||
|
"Mr. One - Balazs Tari",
|
||||||
|
"Mr. Two - Zoltan Timar",
|
||||||
|
"Mr. Three - Bela Mezo",
|
||||||
|
}
|
||||||
|
local AUTHORS_BASE_Y = 56
|
||||||
|
local AUTHORS_LINE_H = 12
|
||||||
|
local AUTHORS_ENTRY_DT = 0.65
|
||||||
|
local AUTHORS_ENTRY_V = 2.5
|
||||||
|
|
||||||
|
local RAINBOW = { 4, 9, 3, 7, 13, 2, 9, 4 }
|
||||||
|
local NUM_STARS = 40
|
||||||
|
|
||||||
|
--- Initialises credits state and pre-computes character metrics.
|
||||||
|
--- @within CreditsWindow
|
||||||
|
function CreditsWindow.init()
|
||||||
|
_time = 0.0
|
||||||
|
_scroll_x = Config.screen.width + 4.0
|
||||||
|
|
||||||
|
_title_chars = {}
|
||||||
|
_title_total_w = 0
|
||||||
|
for i = 1, #TITLE do
|
||||||
|
local ch = TITLE:sub(i, i)
|
||||||
|
local w = print(ch, 0, -100, 0, false, 2)
|
||||||
|
_title_chars[i] = { ch = ch, ox = _title_total_w, w = w }
|
||||||
|
_title_total_w = _title_total_w + w
|
||||||
|
end
|
||||||
|
|
||||||
|
_scroll_chars = {}
|
||||||
|
_scroll_total_w = 0
|
||||||
|
local function append_str(str, col)
|
||||||
|
for i = 1, #str do
|
||||||
|
local ch = str:sub(i, i)
|
||||||
|
local w = print(ch, 0, -100, 0, false, 1)
|
||||||
|
_scroll_chars[#_scroll_chars + 1] = { ch = ch, ox = _scroll_total_w, w = w, col = col }
|
||||||
|
_scroll_total_w = _scroll_total_w + w
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for _, part in ipairs(SCROLL_PARTS) do
|
||||||
|
append_str(part, RAINBOW[math.random(#RAINBOW)])
|
||||||
|
append_str(SCROLL_SEP, Config.colors.white)
|
||||||
|
end
|
||||||
|
|
||||||
|
_stars = {}
|
||||||
|
for i = 1, NUM_STARS do
|
||||||
|
_stars[i] = {
|
||||||
|
x = math.random(0, Config.screen.width - 1) + 0.0,
|
||||||
|
y = math.random(0, Config.screen.height - 1),
|
||||||
|
spd = (i % 3 + 1) * 10.0,
|
||||||
|
col = ({ 1, 2, 4, 4 })[(i % 4) + 1],
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function draw_stars()
|
||||||
|
for _, s in ipairs(_stars) do
|
||||||
|
pix(math.floor(s.x), s.y, s.col)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function draw_rasters()
|
||||||
|
local cy = RASTER_Y_TOP + math.floor(math.sin(_time * 1.3) * 6)
|
||||||
|
for i, col in ipairs(RASTER_COLS) do
|
||||||
|
local y = cy + i - 1
|
||||||
|
if y >= 0 and y < Config.screen.height then
|
||||||
|
line(0, y, Config.screen.width - 1, y, col)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local cy2 = RASTER_Y_BOT + math.floor(math.sin(_time * 1.7 + 1.5) * 5)
|
||||||
|
for i, col in ipairs(RASTER_COLS) do
|
||||||
|
local y = cy2 + i - 1
|
||||||
|
if y >= 0 and y < Config.screen.height then
|
||||||
|
line(0, y, Config.screen.width - 1, y, col)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function bounce_out(p)
|
||||||
|
local n1, d1 = 7.5625, 2.75
|
||||||
|
if p < 1 / d1 then
|
||||||
|
return n1 * p * p
|
||||||
|
elseif p < 2 / d1 then
|
||||||
|
p = p - 1.5 / d1; return n1 * p * p + 0.75
|
||||||
|
elseif p < 2.5 / d1 then
|
||||||
|
p = p - 2.25 / d1; return n1 * p * p + 0.9375
|
||||||
|
else
|
||||||
|
p = p - 2.625 / d1; return n1 * p * p + 0.984375
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function draw_title()
|
||||||
|
local sx = math.floor((Config.screen.width - _title_total_w) / 2)
|
||||||
|
local n = #_title_chars
|
||||||
|
local max_dist = (n - 1) / 2.0
|
||||||
|
for i, tc in ipairs(_title_chars) do
|
||||||
|
local dist = math.abs(i - (n + 1) / 2.0)
|
||||||
|
local delay = (max_dist - dist) * TITLE_DELAY_STEP
|
||||||
|
local t = math.max(0, _time - delay)
|
||||||
|
local p = math.min(1, t / TITLE_FALL_DUR)
|
||||||
|
local y = math.floor(-14 + bounce_out(p) * (TITLE_Y + 14))
|
||||||
|
print(tc.ch, sx + tc.ox + 1, y + 1, 0, false, 2)
|
||||||
|
print(tc.ch, sx + tc.ox, y, Config.colors.light_blue, false, 2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function draw_authors()
|
||||||
|
local col = Config.colors.light_blue
|
||||||
|
for i, lbl in ipairs(AUTHORS) do
|
||||||
|
local enter_t = math.max(0, _time - (i - 1) * AUTHORS_ENTRY_DT)
|
||||||
|
local slide = math.max(0, 1 - enter_t * AUTHORS_ENTRY_V)
|
||||||
|
local x_off = math.floor(slide * (Config.screen.width + 40))
|
||||||
|
local yo = (slide < 0.01) and math.floor(math.sin(_time * 2.0 + i * 1.1) * 2) or 0
|
||||||
|
Print.text(lbl, 12 + x_off, AUTHORS_BASE_Y + (i - 1) * AUTHORS_LINE_H + yo, col)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function draw_scroller()
|
||||||
|
local third = Config.screen.width / 3
|
||||||
|
for pass = 0, 1 do
|
||||||
|
local base = _scroll_x + pass * _scroll_total_w
|
||||||
|
for _, sc in ipairs(_scroll_chars) do
|
||||||
|
local x = math.floor(base + sc.ox)
|
||||||
|
if x >= Config.screen.width then break end
|
||||||
|
if x + sc.w > 0 then
|
||||||
|
local zone = math.max(1, math.min(3, math.floor(x / third) + 1))
|
||||||
|
print(sc.ch, x, SCROLL_Y, SCROLL_ZONE_COLS[zone], false, 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Draws the credits window.
|
||||||
|
--- @within CreditsWindow
|
||||||
|
function CreditsWindow.draw()
|
||||||
|
cls(Config.colors.black)
|
||||||
|
draw_stars()
|
||||||
|
draw_rasters()
|
||||||
|
draw_title()
|
||||||
|
Print.text_center("Authors", Config.screen.width / 2, 47, Config.colors.light_grey)
|
||||||
|
draw_authors()
|
||||||
|
draw_scroller()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Updates credits window logic.
|
||||||
|
--- @within CreditsWindow
|
||||||
|
function CreditsWindow.update()
|
||||||
|
_time = _time + Context.delta_time
|
||||||
|
|
||||||
|
for _, s in ipairs(_stars) do
|
||||||
|
s.x = s.x + s.spd * Context.delta_time
|
||||||
|
if s.x >= Config.screen.width then s.x = s.x - Config.screen.width end
|
||||||
|
end
|
||||||
|
|
||||||
|
_scroll_x = _scroll_x - SCROLL_SPEED * Context.delta_time
|
||||||
|
if _scroll_x <= -_scroll_total_w then
|
||||||
|
_scroll_x = _scroll_x + _scroll_total_w
|
||||||
|
end
|
||||||
|
|
||||||
|
if Input.back() or Input.select() then
|
||||||
|
Window.set_current("menu")
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -30,9 +30,25 @@ function EndWindow.draw()
|
|||||||
Print.text(yes_text, centerX - 40, y, yes_color)
|
Print.text(yes_text, centerX - 40, y, yes_color)
|
||||||
Print.text(no_text, centerX + 10, y, no_color)
|
Print.text(no_text, centerX + 10, y, no_color)
|
||||||
elseif Context._end.state == "ending" then
|
elseif Context._end.state == "ending" then
|
||||||
Print.text_center("Game over -- good ending.", Config.screen.width / 2, 50, Config.colors.light_blue)
|
local cx = Config.screen.width / 2
|
||||||
Print.text_center("Congratulations!", Config.screen.width / 2, 70, Config.colors.white)
|
local name = Context.player_name or "AAA"
|
||||||
Print.text_center("Press Z to return to menu", Config.screen.width / 2, 110, Config.colors.light_grey)
|
local code = CodeGenerator.encrypt(name)
|
||||||
|
|
||||||
|
Print.text_center("~ GOOD ENDING ~", cx, 8, Config.colors.light_blue)
|
||||||
|
Print.text_center("Congratulations, " .. name .. "!", cx, 20, Config.colors.white)
|
||||||
|
|
||||||
|
rectb(40, 29, 160, 36, Config.colors.blue)
|
||||||
|
Print.text_center("your code", cx, 33, Config.colors.light_grey)
|
||||||
|
Print.text_center(code, cx, 44, Config.colors.white, false, 2)
|
||||||
|
|
||||||
|
Print.text_center("Write it down!", cx, 70, Config.colors.item)
|
||||||
|
|
||||||
|
line(20, 82, 219, 82, Config.colors.dark_grey)
|
||||||
|
Print.text_center("To continue via telnet:", cx, 87, Config.colors.light_grey)
|
||||||
|
Print.text_center("games.teletype.hu 2324", cx, 98, Config.colors.white)
|
||||||
|
line(20, 110, 219, 110, Config.colors.dark_grey)
|
||||||
|
|
||||||
|
Print.text_center("Press Z to return to menu", cx, 116, Config.colors.dark_grey)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
59
inc/window/window.gameover.lua
Normal file
59
inc/window/window.gameover.lua
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
--- @section GameOverWindow
|
||||||
|
local GAME_OVER_ART = [[
|
||||||
|
_###_ __#__ #___# #####
|
||||||
|
#____ _#_#_ ##_## #____
|
||||||
|
#_### ##### #_#_# ####_
|
||||||
|
#___# #___# #___# #____
|
||||||
|
_###_ #___# #___# #####
|
||||||
|
|
||||||
|
_###_ #___# ##### ####_
|
||||||
|
#___# #___# #____ #___#
|
||||||
|
#___# _#_#_ ####_ ####_
|
||||||
|
#___# __#__ #____ #_#__
|
||||||
|
_###_ __#__ ##### #__##
|
||||||
|
]]
|
||||||
|
|
||||||
|
local REASON_MESSAGES = {
|
||||||
|
ism = "Your impostor syndrome consumed you.",
|
||||||
|
bm = "You burned out like a cheap candle.",
|
||||||
|
days = "100 days passed. The cycle never broke.",
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Shows the game over screen.
|
||||||
|
--- @within GameOverWindow
|
||||||
|
--- @param reason string One of "ism", "bm", "days".
|
||||||
|
function GameOverWindow.show(reason)
|
||||||
|
GameOverWindow.reason = reason
|
||||||
|
Context.game_in_progress = false
|
||||||
|
Glitch.show()
|
||||||
|
Window.set_current("game_over")
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Draws the game over screen.
|
||||||
|
--- @within GameOverWindow
|
||||||
|
function GameOverWindow.draw()
|
||||||
|
cls(Config.colors.black)
|
||||||
|
|
||||||
|
local cx = Config.screen.width / 2
|
||||||
|
local bounds = AsciiArt.draw(GAME_OVER_ART, {
|
||||||
|
char_w = 4,
|
||||||
|
char_h = 6,
|
||||||
|
line_gap = 1,
|
||||||
|
word_gap = 10,
|
||||||
|
color = Config.colors.red,
|
||||||
|
})
|
||||||
|
|
||||||
|
local msg = REASON_MESSAGES[GameOverWindow.reason] or ""
|
||||||
|
Print.text_center(msg, cx, bounds.bottom + 8, Config.colors.white)
|
||||||
|
Print.text_center("Press Z to restart", cx, Config.screen.height - 10, Config.colors.light_grey)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Updates the game over screen logic.
|
||||||
|
--- @within GameOverWindow
|
||||||
|
function GameOverWindow.update()
|
||||||
|
if Input.select() then
|
||||||
|
Context.reset()
|
||||||
|
MenuWindow.refresh_menu_items()
|
||||||
|
Window.set_current("menu")
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -102,17 +102,13 @@ function MenuWindow.update()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Starts a new game from the menu.
|
--- Opens player name entry then starts a new game.
|
||||||
--- @within MenuWindow
|
--- @within MenuWindow
|
||||||
function MenuWindow.new_game()
|
function MenuWindow.new_game()
|
||||||
|
PlayerNameWindow.init(function()
|
||||||
Context.new_game()
|
Context.new_game()
|
||||||
end
|
end)
|
||||||
|
Window.set_current("player_name")
|
||||||
--- Loads a game from the menu.
|
|
||||||
--- @within MenuWindow
|
|
||||||
function MenuWindow.load_game()
|
|
||||||
Context.load_game()
|
|
||||||
GameWindow.set_state("game")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Saves the current game from the menu.
|
--- Saves the current game from the menu.
|
||||||
@@ -139,6 +135,20 @@ function MenuWindow.controls()
|
|||||||
Window.set_current("controls")
|
Window.set_current("controls")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Opens the player name entry screen (test mode shortcut).
|
||||||
|
--- @within MenuWindow
|
||||||
|
function MenuWindow.player_name()
|
||||||
|
PlayerNameWindow.init()
|
||||||
|
Window.set_current("player_name")
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Opens the credits screen.
|
||||||
|
--- @within MenuWindow
|
||||||
|
function MenuWindow.credits()
|
||||||
|
CreditsWindow.init()
|
||||||
|
Window.set_current("credits")
|
||||||
|
end
|
||||||
|
|
||||||
--- Opens the audio test menu.
|
--- Opens the audio test menu.
|
||||||
--- @within MenuWindow
|
--- @within MenuWindow
|
||||||
function MenuWindow.audio_test()
|
function MenuWindow.audio_test()
|
||||||
@@ -153,6 +163,14 @@ function MenuWindow.continued()
|
|||||||
GameWindow.set_state("continued")
|
GameWindow.set_state("continued")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Opens the end screen for testing.
|
||||||
|
--- @within MenuWindow
|
||||||
|
function MenuWindow.end_screen()
|
||||||
|
Context._end.state = "ending"
|
||||||
|
Context._end.selection = 1
|
||||||
|
GameWindow.set_state("end")
|
||||||
|
end
|
||||||
|
|
||||||
--- Opens the DDR minigame test.
|
--- Opens the DDR minigame test.
|
||||||
--- @within MenuWindow
|
--- @within MenuWindow
|
||||||
function MenuWindow.ddr_test()
|
function MenuWindow.ddr_test()
|
||||||
@@ -178,14 +196,16 @@ function MenuWindow.refresh_menu_items()
|
|||||||
end
|
end
|
||||||
|
|
||||||
table.insert(_menu_items, {label = "New Game", decision = MenuWindow.new_game})
|
table.insert(_menu_items, {label = "New Game", decision = MenuWindow.new_game})
|
||||||
table.insert(_menu_items, {label = "Load Game", decision = MenuWindow.load_game})
|
|
||||||
table.insert(_menu_items, {label = "Controls", decision = MenuWindow.controls})
|
table.insert(_menu_items, {label = "Controls", decision = MenuWindow.controls})
|
||||||
|
table.insert(_menu_items, {label = "Credits", decision = MenuWindow.credits})
|
||||||
|
|
||||||
if Context.test_mode then
|
if Context.test_mode then
|
||||||
table.insert(_menu_items, {label = "Audio Test", decision = MenuWindow.audio_test})
|
table.insert(_menu_items, {label = "Audio Test", decision = MenuWindow.audio_test})
|
||||||
table.insert(_menu_items, {label = "To Be Continued...", decision = MenuWindow.continued})
|
table.insert(_menu_items, {label = "To Be Continued...", decision = MenuWindow.continued})
|
||||||
table.insert(_menu_items, {label = "DDR Test", decision = MenuWindow.ddr_test})
|
table.insert(_menu_items, {label = "DDR Test", decision = MenuWindow.ddr_test})
|
||||||
table.insert(_menu_items, {label = "Start at ASCEND N", decision = MenuWindow.ascend_debug})
|
table.insert(_menu_items, {label = "Start at ASCEND N", decision = MenuWindow.ascend_debug})
|
||||||
|
table.insert(_menu_items, {label = "End Screen", decision = MenuWindow.end_screen})
|
||||||
|
table.insert(_menu_items, {label = "Player Name", decision = MenuWindow.player_name})
|
||||||
end
|
end
|
||||||
|
|
||||||
table.insert(_menu_items, {label = "Exit", decision = MenuWindow.exit})
|
table.insert(_menu_items, {label = "Exit", decision = MenuWindow.exit})
|
||||||
|
|||||||
@@ -130,6 +130,7 @@ function MinigameDDRWindow.on_arrow_hit_special(arrow, game_context)
|
|||||||
Audio.sfx_arrowhit(arrow.note)
|
Audio.sfx_arrowhit(arrow.note)
|
||||||
game_context.special_mode_counter = game_context.special_mode_counter + 1
|
game_context.special_mode_counter = game_context.special_mode_counter + 1
|
||||||
else
|
else
|
||||||
|
game_context.total_misses = game_context.total_misses + 1
|
||||||
if game_context.special_mode_condition then Audio.sfx_bloop() end
|
if game_context.special_mode_condition then Audio.sfx_bloop() end
|
||||||
game_context.special_mode_condition = false
|
game_context.special_mode_condition = false
|
||||||
end
|
end
|
||||||
@@ -141,10 +142,12 @@ function MinigameDDRWindow.on_arrow_hit_special(arrow, game_context)
|
|||||||
game_context.bar_fill = game_context.bar_fill - game_context.fill_per_hit
|
game_context.bar_fill = game_context.bar_fill - game_context.fill_per_hit
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
game_context.total_misses = game_context.total_misses + 1
|
||||||
if game_context.special_mode_condition then Audio.sfx_bloop() end
|
if game_context.special_mode_condition then Audio.sfx_bloop() end
|
||||||
game_context.special_mode_condition = false
|
game_context.special_mode_condition = false
|
||||||
end
|
end
|
||||||
elseif special_mode == "only_nothing" then
|
elseif special_mode == "only_nothing" then
|
||||||
|
game_context.total_misses = game_context.total_misses + 1
|
||||||
if game_context.special_mode_condition then Audio.sfx_bloop() end
|
if game_context.special_mode_condition then Audio.sfx_bloop() end
|
||||||
game_context.special_mode_condition = false
|
game_context.special_mode_condition = false
|
||||||
end
|
end
|
||||||
@@ -173,6 +176,9 @@ function MinigameDDRWindow.on_end(game_context)
|
|||||||
end
|
end
|
||||||
|
|
||||||
game_context.special_mode_condition = game_context.special_mode_condition and was_ok
|
game_context.special_mode_condition = game_context.special_mode_condition and was_ok
|
||||||
|
if game_context.special_mode_condition and sm ~= "normal" then
|
||||||
|
game_context.bar_fill = game_context.max_fill
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Initializes DDR minigame state.
|
--- Initializes DDR minigame state.
|
||||||
@@ -336,7 +342,8 @@ function MinigameDDRWindow.update()
|
|||||||
mg.win_timer = mg.win_timer - 1
|
mg.win_timer = mg.win_timer - 1
|
||||||
if mg.win_timer == 0 then
|
if mg.win_timer == 0 then
|
||||||
Audio.music_stop()
|
Audio.music_stop()
|
||||||
Meter.on_minigame_complete()
|
Meter.apply_ddr_reward(mg.total_misses)
|
||||||
|
if not Context.game_in_progress then return end
|
||||||
if mg.on_win then
|
if mg.on_win then
|
||||||
mg.on_win(mg)
|
mg.on_win(mg)
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -1,6 +1,35 @@
|
|||||||
|
--- @section MinigameButtonMashWindow
|
||||||
|
|
||||||
|
---@class MinigameButtonMashState
|
||||||
|
---@field bar_fill number
|
||||||
|
---@field target_points number
|
||||||
|
---@field fill_per_press number
|
||||||
|
---@field base_degradation number
|
||||||
|
---@field degradation_multiplier number
|
||||||
|
---@field button_pressed_timer number
|
||||||
|
---@field button_press_duration number
|
||||||
|
---@field instruction_text string
|
||||||
|
---@field show_progress_text boolean
|
||||||
|
---@field return_window string?
|
||||||
|
---@field bar_x number
|
||||||
|
---@field bar_y number
|
||||||
|
---@field bar_width number
|
||||||
|
---@field bar_height number
|
||||||
|
---@field button_x number
|
||||||
|
---@field button_y number
|
||||||
|
---@field button_size number
|
||||||
|
---@field focus_center_x number?
|
||||||
|
---@field focus_center_y number?
|
||||||
|
---@field focus_initial_radius number
|
||||||
|
---@field win_timer number
|
||||||
|
---@field on_win (fun())?
|
||||||
|
---@field meter_on_complete (fun(elapsed_sec: number))?
|
||||||
|
---@field start_ms number?
|
||||||
|
---@field elapsed_sec number?
|
||||||
|
|
||||||
--- Gets initial button mash minigame configuration.
|
--- Gets initial button mash minigame configuration.
|
||||||
--- @within MinigameButtonMashWindow
|
--- @within MinigameButtonMashWindow
|
||||||
--- @return result table The default button mash minigame configuration.
|
---@return MinigameButtonMashState
|
||||||
function MinigameButtonMashWindow.init_context()
|
function MinigameButtonMashWindow.init_context()
|
||||||
return {
|
return {
|
||||||
bar_fill = 0,
|
bar_fill = 0,
|
||||||
@@ -24,7 +53,11 @@ function MinigameButtonMashWindow.init_context()
|
|||||||
focus_center_y = nil,
|
focus_center_y = nil,
|
||||||
focus_initial_radius = 0,
|
focus_initial_radius = 0,
|
||||||
win_timer = 0,
|
win_timer = 0,
|
||||||
on_win = nil
|
on_win = nil,
|
||||||
|
--- If set, called with elapsed_sec instead of Meter.on_minigame_complete()
|
||||||
|
meter_on_complete = nil,
|
||||||
|
start_ms = nil,
|
||||||
|
elapsed_sec = nil,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -51,8 +84,10 @@ end
|
|||||||
function MinigameButtonMashWindow.start(return_window, params)
|
function MinigameButtonMashWindow.start(return_window, params)
|
||||||
Audio.music_stop()
|
Audio.music_stop()
|
||||||
MinigameButtonMashWindow.init(params)
|
MinigameButtonMashWindow.init(params)
|
||||||
|
---@type MinigameButtonMashState
|
||||||
local mg = Context.minigame_button_mash
|
local mg = Context.minigame_button_mash
|
||||||
mg.return_window = return_window or "game"
|
mg.return_window = return_window or "game"
|
||||||
|
mg.start_ms = time()
|
||||||
if mg.focus_center_x then
|
if mg.focus_center_x then
|
||||||
Focus.start_driven(mg.focus_center_x, mg.focus_center_y, {
|
Focus.start_driven(mg.focus_center_x, mg.focus_center_y, {
|
||||||
initial_radius = mg.focus_initial_radius
|
initial_radius = mg.focus_initial_radius
|
||||||
@@ -64,12 +99,18 @@ end
|
|||||||
--- Updates button mash minigame logic.
|
--- Updates button mash minigame logic.
|
||||||
--- @within MinigameButtonMashWindow
|
--- @within MinigameButtonMashWindow
|
||||||
function MinigameButtonMashWindow.update()
|
function MinigameButtonMashWindow.update()
|
||||||
|
---@type MinigameButtonMashState
|
||||||
local mg = Context.minigame_button_mash
|
local mg = Context.minigame_button_mash
|
||||||
|
|
||||||
if mg.win_timer > 0 then
|
if mg.win_timer > 0 then
|
||||||
mg.win_timer = mg.win_timer - 1
|
mg.win_timer = mg.win_timer - 1
|
||||||
if mg.win_timer == 0 then
|
if mg.win_timer == 0 then
|
||||||
Meter.on_minigame_complete()
|
if mg.meter_on_complete then
|
||||||
|
mg.meter_on_complete(mg.elapsed_sec or 0)
|
||||||
|
else
|
||||||
|
Meter.on_minigame_complete(false)
|
||||||
|
end
|
||||||
|
if not Context.game_in_progress then return end
|
||||||
if mg.focus_center_x then Focus.stop() end
|
if mg.focus_center_x then Focus.stop() end
|
||||||
Context.home_norman_visible = true
|
Context.home_norman_visible = true
|
||||||
Context.have_done_work_today = false
|
Context.have_done_work_today = false
|
||||||
@@ -97,6 +138,7 @@ function MinigameButtonMashWindow.update()
|
|||||||
end
|
end
|
||||||
if mg.bar_fill >= mg.target_points then
|
if mg.bar_fill >= mg.target_points then
|
||||||
Audio.sfx_select()
|
Audio.sfx_select()
|
||||||
|
mg.elapsed_sec = (time() - mg.start_ms) / 1000
|
||||||
mg.win_timer = Config.timing.minigame_win_duration
|
mg.win_timer = Config.timing.minigame_win_duration
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@@ -116,6 +158,7 @@ end
|
|||||||
--- Draws button mash minigame.
|
--- Draws button mash minigame.
|
||||||
--- @within MinigameButtonMashWindow
|
--- @within MinigameButtonMashWindow
|
||||||
function MinigameButtonMashWindow.draw()
|
function MinigameButtonMashWindow.draw()
|
||||||
|
---@type MinigameButtonMashState
|
||||||
local mg = Context.minigame_button_mash
|
local mg = Context.minigame_button_mash
|
||||||
if mg.return_window == "game" then
|
if mg.return_window == "game" then
|
||||||
GameWindow.draw_with_underlay(function()
|
GameWindow.draw_with_underlay(function()
|
||||||
|
|||||||
@@ -73,7 +73,8 @@ function MinigameRhythmWindow.update()
|
|||||||
if mg.win_timer > 0 then
|
if mg.win_timer > 0 then
|
||||||
mg.win_timer = mg.win_timer - 1
|
mg.win_timer = mg.win_timer - 1
|
||||||
if mg.win_timer == 0 then
|
if mg.win_timer == 0 then
|
||||||
Meter.on_minigame_complete()
|
Meter.on_minigame_complete(false)
|
||||||
|
if not Context.game_in_progress then return end
|
||||||
if mg.focus_center_x then Focus.stop() end
|
if mg.focus_center_x then Focus.stop() end
|
||||||
if mg.on_win then
|
if mg.on_win then
|
||||||
mg.on_win()
|
mg.on_win()
|
||||||
|
|||||||
115
inc/window/window.player_name.lua
Normal file
115
inc/window/window.player_name.lua
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
--- @section PlayerNameWindow
|
||||||
|
|
||||||
|
local _frame = 0
|
||||||
|
local _on_confirm = nil
|
||||||
|
local MAX_LEN = 3
|
||||||
|
local BOX_W = 24
|
||||||
|
local BOX_H = 24
|
||||||
|
local BOX_GAP = 12
|
||||||
|
local BOX_Y = 50
|
||||||
|
local WARN_Y = 104
|
||||||
|
|
||||||
|
local function box_start_x()
|
||||||
|
return math.floor((Config.screen.width - (MAX_LEN * BOX_W + (MAX_LEN - 1) * BOX_GAP)) / 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function box_x(i)
|
||||||
|
return box_start_x() + (i - 1) * (BOX_W + BOX_GAP)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Initialises the player name window.
|
||||||
|
--- @within PlayerNameWindow
|
||||||
|
--- @param on_confirm function Called with the entered name when the player saves.
|
||||||
|
function PlayerNameWindow.init(on_confirm)
|
||||||
|
_frame = 0
|
||||||
|
_on_confirm = on_confirm
|
||||||
|
TextInput.init(MAX_LEN)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function draw_boxes()
|
||||||
|
local cursor = TextInput.get_position()
|
||||||
|
local blink = math.floor(_frame / 18) % 2 == 0
|
||||||
|
|
||||||
|
for i = 1, MAX_LEN do
|
||||||
|
local x = box_x(i)
|
||||||
|
local is_cur = (i == cursor)
|
||||||
|
local done = TextInput.is_done()
|
||||||
|
|
||||||
|
local fill = (is_cur and not done) and Config.colors.blue or Config.colors.black
|
||||||
|
local border = (is_cur and not done) and Config.colors.white
|
||||||
|
or done and Config.colors.light_blue
|
||||||
|
or Config.colors.dark_grey
|
||||||
|
|
||||||
|
rect (x, BOX_Y, BOX_W, BOX_H, fill)
|
||||||
|
rectb(x, BOX_Y, BOX_W, BOX_H, border)
|
||||||
|
|
||||||
|
local show = not (is_cur and blink and not done)
|
||||||
|
if show then
|
||||||
|
local ch = TextInput.get_letter(i)
|
||||||
|
local cw = print(ch, 0, -100, 0, false, 2)
|
||||||
|
local cx = x + math.floor((BOX_W - cw) / 2)
|
||||||
|
local cy = BOX_Y + math.floor((BOX_H - 11) / 2)
|
||||||
|
local col = (is_cur and not done) and Config.colors.white or Config.colors.light_grey
|
||||||
|
print(ch, cx, cy, col, false, 2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- caret arrow below active box
|
||||||
|
if not TextInput.is_done() then
|
||||||
|
local cx = box_x(cursor) + math.floor(BOX_W / 2)
|
||||||
|
local ay = BOX_Y + BOX_H + 4
|
||||||
|
line(cx - 4, ay, cx, ay + 4, Config.colors.white)
|
||||||
|
line(cx + 4, ay, cx, ay + 4, Config.colors.white)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Draws the player name window.
|
||||||
|
--- @within PlayerNameWindow
|
||||||
|
function PlayerNameWindow.draw()
|
||||||
|
cls(Config.colors.black)
|
||||||
|
|
||||||
|
Print.text_center("Player Name", Config.screen.width / 2, 14, Config.colors.white, false, 2)
|
||||||
|
|
||||||
|
draw_boxes()
|
||||||
|
|
||||||
|
if TextInput.is_done() then
|
||||||
|
Print.text_center("Z: save name B: edit", Config.screen.width / 2, BOX_Y + BOX_H + 12, Config.colors.light_blue)
|
||||||
|
else
|
||||||
|
Print.text_center("Up/Dn: letter Lft/Rgt: move Z: ok", Config.screen.width / 2, BOX_Y + BOX_H + 12, Config.colors.dark_grey)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Warning section
|
||||||
|
rect(0, WARN_Y, Config.screen.width, Config.screen.height - WARN_Y, Config.colors.blue)
|
||||||
|
rectb(0, WARN_Y, Config.screen.width, Config.screen.height - WARN_Y, Config.colors.light_blue)
|
||||||
|
Print.text_center("Remember your name!", Config.screen.width / 2, WARN_Y + 8, Config.colors.white)
|
||||||
|
Print.text_center("You will need it to load the game.", Config.screen.width / 2, WARN_Y + 20, Config.colors.light_grey)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Updates player name window logic.
|
||||||
|
--- @within PlayerNameWindow
|
||||||
|
function PlayerNameWindow.update()
|
||||||
|
_frame = _frame + 1
|
||||||
|
|
||||||
|
if TextInput.is_done() then
|
||||||
|
if Input.select() then
|
||||||
|
Context.player_name = TextInput.get_name()
|
||||||
|
if _on_confirm then _on_confirm() else Window.set_current("menu") end
|
||||||
|
elseif Input.back() then
|
||||||
|
TextInput.prev_position()
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if Input.up_repeat() then TextInput.next_letter() end
|
||||||
|
if Input.down_repeat() then TextInput.prev_letter() end
|
||||||
|
if Input.right() then TextInput.next_position() end
|
||||||
|
if Input.select() then TextInput.select_letter() end
|
||||||
|
|
||||||
|
if Input.left() or Input.back() then
|
||||||
|
if TextInput.get_position() > 1 then
|
||||||
|
TextInput.prev_position()
|
||||||
|
else
|
||||||
|
Window.set_current("menu")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -34,6 +34,9 @@ Window.register("minigame_rhythm", MinigameRhythmWindow)
|
|||||||
MinigameDDRWindow = {}
|
MinigameDDRWindow = {}
|
||||||
Window.register("minigame_ddr", MinigameDDRWindow)
|
Window.register("minigame_ddr", MinigameDDRWindow)
|
||||||
|
|
||||||
|
GameOverWindow = {}
|
||||||
|
Window.register("game_over", GameOverWindow)
|
||||||
|
|
||||||
EndWindow = {}
|
EndWindow = {}
|
||||||
Window.register("end", EndWindow)
|
Window.register("end", EndWindow)
|
||||||
|
|
||||||
@@ -42,3 +45,9 @@ Window.register("discussion", DiscussionWindow)
|
|||||||
|
|
||||||
ContinuedWindow = {}
|
ContinuedWindow = {}
|
||||||
Window.register("continued", ContinuedWindow)
|
Window.register("continued", ContinuedWindow)
|
||||||
|
|
||||||
|
CreditsWindow = {}
|
||||||
|
Window.register("credits", CreditsWindow)
|
||||||
|
|
||||||
|
PlayerNameWindow = {}
|
||||||
|
Window.register("player_name", PlayerNameWindow)
|
||||||
|
|||||||
Reference in New Issue
Block a user