From e91115a8fae93f4fe92a967f2562c23f41dc3984 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 3 Dec 2023 22:31:45 +0000 Subject: [PATCH] Goner Setup: Cook 2 - More dialogue - Restrict access to your choices based on your progress through the Goner Setup. - Save progress through the setup to gamedata - Resets to beginning when Challenges is cleared - Passwords - Only permit the password entry in like the first two seconds - Preemptively disarms potentially annoying people in stream chats - Make wrongwarp also quit the game on exit instead of returning to the title screen - Add GDQ cheats - `savetheanimals` - `savetheframes` - Both do practically the same thing, with slightly modified dialogue. - Skips all of the normal dialogue. - Performing a social experiment on anyone who might stream this game at a charity event. :) --- src/g_game.c | 6 +- src/k_menu.h | 3 + src/k_menudraw.c | 8 +- src/k_menufunc.c | 4 +- src/m_cheat.c | 26 +++ src/m_cond.c | 2 + src/m_cond.h | 12 ++ src/menus/main-goner.cpp | 434 ++++++++++++++++++++++++++++++++------- src/menus/options-1.c | 4 + 9 files changed, 423 insertions(+), 76 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index c22bd031e..36b7a56e6 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4553,6 +4553,8 @@ typedef enum GDEVER_KEYMAJORSKIP = 1<<5, GDEVER_TUTORIALSKIP = 1<<6, GDEVER_ENTERTUTSKIP = 1<<7, + // --- Free up to 1<<23 --- // + GDEVER_GONERSHIFT = 24, // nothing above this } gdeverdone_t; static const char *G_GameDataFolder(void) @@ -4694,6 +4696,8 @@ void G_LoadGameData(void) gamedata->majorkeyskipattempted = !!(everflags & GDEVER_KEYMAJORSKIP); gamedata->finishedtutorialchallenge = !!(everflags & GDEVER_TUTORIALSKIP); gamedata->enteredtutorialchallenge = !!(everflags & GDEVER_ENTERTUTSKIP); + + gamedata->gonerlevel = everflags>>GDEVER_GONERSHIFT; } else { @@ -5371,7 +5375,7 @@ void G_SaveGameData(void) WRITEUINT16(save.p, gamedata->chaokeys); // 2 { - UINT32 everflags = 0; + UINT32 everflags = (gamedata->gonerlevel<everloadedaddon) everflags |= GDEVER_ADDON; diff --git a/src/k_menu.h b/src/k_menu.h index f5e414930..09fc6807f 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -206,6 +206,9 @@ extern menu_t MAIN_GonerDef; void M_GonerTick(void); void M_GonerProfile(INT32 choice); void M_GonerTutorial(INT32 choice); +void M_GonerResetLooking(int type); +void M_GonerCheckLooking(void); +void M_GonerGDQ(boolean opinion); extern menuitem_t PLAY_CharSelect[]; extern menu_t PLAY_CharSelectDef; diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 558e016c3..95c3a0b3c 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -1156,8 +1156,8 @@ void M_DrawHorizontalMenu(void) V_DrawCharacter((BASEVIDWIDTH + width)/2 - 10 + (skullAnimCounter/5), y, '\x1D' | highlightflags, false); // right arrow - x = (BASEVIDWIDTH - 8*(currentMenu->numitems-1))/2; - for (i = 0; i < currentMenu->numitems; i++, x += 8) + x = (BASEVIDWIDTH - 8*(currentMenu->extra2-1))/2; + for (i = 0; i < currentMenu->extra2; i++, x += 8) { if (i == itemOn) { @@ -1165,7 +1165,9 @@ void M_DrawHorizontalMenu(void) } else { - V_DrawFill(x-1, y + 16, 2, 2, 16); + V_DrawFill(x-1, y + 16, 2, 2, + (i >= currentMenu->numitems) ? 20 : 10 + ); } } } diff --git a/src/k_menufunc.c b/src/k_menufunc.c index ef6863594..c6ebeb401 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -741,8 +741,10 @@ void M_GoBack(INT32 choice) M_SetupNextMenu(currentMenu->prevMenu, false); } - else + else if (M_GameTrulyStarted()) M_ClearMenus(true); + else // No returning to the title screen. + M_QuitSRB2(-1); S_StartSound(NULL, sfx_s3k5b); } diff --git a/src/m_cheat.c b/src/m_cheat.c index 39ccfd16b..175acc7e5 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -134,6 +134,20 @@ static UINT8 cheatf_wrongwarp(void) return 1; } +static UINT8 cheatf_savetheanimals(void) +{ + M_GonerGDQ(true); + + return 1; +} + +static UINT8 cheatf_savetheframes(void) +{ + M_GonerGDQ(false); + + return 1; +} + #ifdef DEVELOP static UINT8 cheatf_devmode(void) { @@ -179,6 +193,16 @@ static cheatseq_t cheat_wrongwarp = { (UINT8[]){ SCRAMBLE('b'), SCRAMBLE('a'), SCRAMBLE('n'), SCRAMBLE('a'), SCRAMBLE('n'), SCRAMBLE('a'), 0xff } }; +static cheatseq_t cheat_savetheanimals = { + NULL, cheatf_savetheanimals, + (UINT8[]){ SCRAMBLE('s'), SCRAMBLE('a'), SCRAMBLE('v'), SCRAMBLE('e'), SCRAMBLE('t'), SCRAMBLE('h'), SCRAMBLE('e'), SCRAMBLE('a'), SCRAMBLE('n'), SCRAMBLE('i'), SCRAMBLE('m'), SCRAMBLE('a'), SCRAMBLE('l'), SCRAMBLE('s'), 0xff } +}; + +static cheatseq_t cheat_savetheframes = { + NULL, cheatf_savetheframes, + (UINT8[]){ SCRAMBLE('s'), SCRAMBLE('a'), SCRAMBLE('v'), SCRAMBLE('e'), SCRAMBLE('t'), SCRAMBLE('h'), SCRAMBLE('e'), SCRAMBLE('f'), SCRAMBLE('r'), SCRAMBLE('a'), SCRAMBLE('m'), SCRAMBLE('e'), SCRAMBLE('s'), 0xff } +}; + #ifdef DEVELOP static cheatseq_t cheat_devmode = { NULL, cheatf_devmode, @@ -190,6 +214,8 @@ cheatseq_t *cheatseqlist[] = { &cheat_warp, &cheat_wrongwarp, + &cheat_savetheanimals, + &cheat_savetheframes, #ifdef DEVELOP &cheat_devmode, #endif diff --git a/src/m_cond.c b/src/m_cond.c index b4f5a0ba6..353f19bc0 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -730,6 +730,8 @@ void M_ClearSecrets(void) gamedata->chaokeys = GDINIT_CHAOKEYS; gamedata->prisoneggstothispickup = GDINIT_PRISONSTOPRIZE; + + gamedata->gonerlevel = GDGONER_INIT; } // For lack of a better idea on where to put this diff --git a/src/m_cond.h b/src/m_cond.h index 87c38060e..4bccce9b1 100644 --- a/src/m_cond.h +++ b/src/m_cond.h @@ -289,6 +289,16 @@ typedef enum { #define GDINIT_CHAOKEYS 3 // Start with 3 Chao Keys !! #define GDINIT_PRISONSTOPRIZE 30 // 30 Prison Eggs to your [Wild Prize] !! +typedef enum { + GDGONER_INIT = 0, + GDGONER_INTRO, + GDGONER_VIDEO, + GDGONER_SOUND, + GDGONER_PROFILE, + GDGONER_TUTORIAL, + GDGONER_DONE, +} gdgoner_t; + typedef enum { GDGT_RACE, GDGT_BATTLE, @@ -370,6 +380,8 @@ struct gamedata_t boolean finishedtutorialchallenge; gdmusic_t musicstate; + UINT8 gonerlevel; + // BACKWARDS COMPAT ASSIST boolean importprofilewins; }; diff --git a/src/menus/main-goner.cpp b/src/menus/main-goner.cpp index cd2c201ef..b0ab6a38a 100644 --- a/src/menus/main-goner.cpp +++ b/src/menus/main-goner.cpp @@ -2,7 +2,10 @@ /// \brief The Goner Setup. #include "../k_menu.h" +#include "../m_cond.h" #include "../r_skins.h" +#include "../s_sound.h" +#include "../p_local.h" // P_AutoPause #include "../st_stuff.h" // faceprefix #include "../v_draw.hpp" #include "../k_dialogue.hpp" @@ -11,41 +14,36 @@ menuitem_t MAIN_Goner[] = { - {IT_STRING | IT_CVAR | IT_CV_STRING, "Password", + {IT_STRING | IT_CVAR | IT_CV_STRING, ". . .", "ATTEMPT ADMINISTRATOR ACCESS.", NULL, {.cvar = &cv_dummyextraspassword}, 0, 0}, - {IT_STRING | IT_CALL, "Quit", - "CONCLUDE OBSERVATIONS NOW.", NULL, - {.routine = M_QuitSRB2}, 0, 0}, - - {IT_STRING | IT_CALL, "Video Options", + {IT_STRING | IT_CALL, "VIDEO OPTIONS", "CONFIGURE OCULAR PATHWAYS.", NULL, {.routine = M_VideoOptions}, 0, 0}, - {IT_STRING | IT_CALL, "Sound Options", + {IT_STRING | IT_CALL, "SOUND OPTIONS", "CALIBRATE AURAL DATASTREAM.", NULL, {.routine = M_SoundOptions}, 0, 0}, - {IT_STRING | IT_CALL, "Profile Setup", + {IT_STRING | IT_CALL, "PROFILE SETUP", "ASSIGN VEHICLE INPUTS.", NULL, {.routine = M_GonerProfile}, 0, 0}, - {IT_STRING | IT_CALL, "Begin Tutorial", + {IT_STRING | IT_CALL, "BEGIN TUTORIAL", "PREPARE FOR INTEGRATION.", NULL, {.routine = M_GonerTutorial}, 0, 0}, }; -static boolean M_GonerInputs(INT32 ch); static void M_GonerDrawer(void); menu_t MAIN_GonerDef = { - sizeof (MAIN_Goner) / sizeof (menuitem_t), + 1, // Intentionally not the sizeof calc NULL, 0, MAIN_Goner, - 32, 160, - 0, 0, + 26, 160, + 0, sizeof (MAIN_Goner) / sizeof (menuitem_t), // extra2 is final width MBF_UD_LR_FLIPPED, "_GONER", 0, 0, @@ -53,7 +51,7 @@ menu_t MAIN_GonerDef = { M_GonerTick, NULL, NULL, - M_GonerInputs, + NULL, }; namespace @@ -154,63 +152,310 @@ public: std::forward_list LinesToDigest; std::forward_list LinesOutput; +int goner_levelworking = GDGONER_INIT; +bool goner_nicetry = false; +bool goner_gdq = false; + +void M_AddGonerLines(void) +{ + SRB2_ASSERT(LinesToDigest.empty()); + + auto _ = srb2::finally([]() { LinesToDigest.reverse(); }); + + static bool leftoff = false; + + goner_delay = TICRATE; + + // This one always plays, so it checks the levelworking instead of gamedata. + if (goner_levelworking == GDGONER_INTRO) + { + if (!goner_nicetry) + { + LinesToDigest.emplace_front(GONERSPEAKER_EGGMAN, 0, + "Metal Sonic. Are you online?"); + } + + leftoff = (goner_levelworking < gamedata->gonerlevel-1); + + if (leftoff) + { + LinesToDigest.emplace_front(GONERSPEAKER_TAILS, 0, + "It must have run into some sort of error..."); + LinesToDigest.emplace_front(GONERSPEAKER_EGGMAN, 0, + "Don't worry, your settings so far are saved. "\ + "Let's pick up where we left off."); + + // the -1 guarantees that one will be (re)played + goner_levelworking = gamedata->gonerlevel-1; + } + + return; + } + + switch (gamedata->gonerlevel) + { + case GDGONER_VIDEO: + { + LinesToDigest.emplace_front(GONERSPEAKER_EGGMAN, TICRATE/2, + "Take a close look, Miles. Moments ago he was at my throat! "\ + "Now he's docile as can be on that operating table."); + + LinesToDigest.emplace_front(GONERSPEAKER_TAILS, 0, + "I don't feel very safe!"); + LinesToDigest.emplace_front(GONERSPEAKER_TAILS, TICRATE/4, + "But its programming is definitely locked down..."); + + LinesToDigest.emplace_front(GONERSPEAKER_EGGMAN, 0, + "You've given me quite the headache, Metal. "\ + "Thankfully, Tails caught you in the act."); + + LinesToDigest.emplace_front(GONERSPEAKER_TAILS, TICRATE/5, + "Wait, I'm getting weird readings over the network."); + LinesToDigest.emplace_front(GONERSPEAKER_TAILS, 0, + "Metal Sonic is the unit labeled \"MS-1\", right?"); + LinesToDigest.emplace_front(GONERSPEAKER_TAILS, TICRATE, + "The ""\x87""viewport""\x80"" and ""\x87""audio""\x80"" "\ + "config looks like it got messed up."); + + LinesToDigest.emplace_front(GONERSPEAKER_EGGMAN, 0, + "So you're right. I wonder if it has anything to do with that outburst."); + LinesToDigest.emplace_front(GONERSPEAKER_EGGMAN, 0, + "Alright, Metal! I don't remember your specifications offhand. "\ + "First things first, go ahead and set up your "\ + "\x87""Video Options""\x80"" yourself."); + break; + } + case GDGONER_SOUND: + { + if (!leftoff) + { + LinesToDigest.emplace_front(GONERSPEAKER_EGGMAN, 0, + "Ah, you can see us now. Good."); + } + LinesToDigest.emplace_front(GONERSPEAKER_EGGMAN, 0, + "Now, calibrate your ""\x87""Sound Options""\x80""."); + + LinesToDigest.emplace_front(GONERSPEAKER_TAILS, 0, + "You always make your stuff so loud by default, Eggman. It might need a moment."); + + LinesToDigest.emplace_front(GONERSPEAKER_EGGMAN, 0, + "Not Metal! He always needed to be stealthy. But go on, set your sliders."); + break; + } + case GDGONER_PROFILE: + { + if (!leftoff) + { + LinesToDigest.emplace_front(GONERSPEAKER_TAILS, TICRATE/2, + "Oh! Let's tell Metal about our project!"); + + LinesToDigest.emplace_front(GONERSPEAKER_EGGMAN, 0, + "Of course. I and my lab assista-"); + + LinesToDigest.emplace_front(GONERSPEAKER_TAILS, 0, + "Lab PARTNER."); + + LinesToDigest.emplace_front(GONERSPEAKER_EGGMAN, 0, + "Irrelevant!"); + } + LinesToDigest.emplace_front(GONERSPEAKER_EGGMAN, TICRATE/4, + "We made a machine together, Tails and I. "\ + "It's called a \"""\x82""Ring Racer""\x80""\"."); + LinesToDigest.emplace_front(GONERSPEAKER_EGGMAN, TICRATE/2, + "At its core, it is designed to utilise the boundless potential "\ + "of the ""\x83""High Voltage Ring""\x80""."); + + LinesToDigest.emplace_front(GONERSPEAKER_TAILS, TICRATE, + "We made this special Ring by combining the power of tens of "\ + "thousands of ordinary ""\x82""Rings""\x80""."); + LinesToDigest.emplace_front(GONERSPEAKER_TAILS, TICRATE/2, + "We recorded some of our testing for you, MS-1. Maybe your neural "\ + "network could train on some less violent data for once."); + + LinesToDigest.emplace_front(GONERSPEAKER_EGGMAN, TICRATE/4, + "While that's uploading, why don't you set up your ""\x87""Profile Card""\x80""?"); + + LinesToDigest.emplace_front(GONERSPEAKER_TAILS, 0, + "Yes! That's one of my contributions."); + + LinesToDigest.emplace_front(GONERSPEAKER_EGGMAN, 0, + "(I'm too used to my systems being designed for me alone...)"); + + LinesToDigest.emplace_front(GONERSPEAKER_TAILS, 0, + "Every racer carries one, to contain their personal settings."); + LinesToDigest.emplace_front(GONERSPEAKER_TAILS, 0, + "It helps get your ""\x87""controls""\x80"" set up nice and quickly, "\ + "when starting your vehicle."); + LinesToDigest.emplace_front(GONERSPEAKER_TAILS, 0, + "And it helps track your wins, too."); + + LinesToDigest.emplace_front(GONERSPEAKER_EGGMAN, TICRATE/5, + "Bragging rights. My idea!"); + + LinesToDigest.emplace_front(GONERSPEAKER_TAILS, TICRATE/2, + "You can make the name on there anything you want."); + LinesToDigest.emplace_front(GONERSPEAKER_TAILS, TICRATE/2, + "Mine says \"Nine Tails\". That's the name of my original character! "\ + "He's like me if I never met my ""\x84""brother""\x80"". He'd have to become stronger "\ + "with robotics, and kind of mean and cool to protect himself..."); + + LinesToDigest.emplace_front(GONERSPEAKER_EGGMAN, TICRATE/5, + "Mine says \"Robotnik\". You can't beat a classic."); + + LinesToDigest.emplace_front(GONERSPEAKER_TAILS, 0, + "Go on, do your ""\x87""Profile Setup""\x80""!"); + break; + } + case GDGONER_TUTORIAL: + case GDGONER_DONE: // maybe we could do something different for this eventually + { + if (!leftoff) + { + LinesToDigest.emplace_front(GONERSPEAKER_EGGMAN, TICRATE/5, + "...right, now that that's sorted. How's the upload going?"); + + LinesToDigest.emplace_front(GONERSPEAKER_TAILS, 0, + "Just finished."); + + LinesToDigest.emplace_front(GONERSPEAKER_EGGMAN, 0, + "Perfect."); + } + + LinesToDigest.emplace_front(GONERSPEAKER_EGGMAN, 0, + "Now, Metal... it's important you pay attention."); + LinesToDigest.emplace_front(GONERSPEAKER_EGGMAN, TICRATE/5, + "It's time to ""\x87""begin your Tutorial""\x80""!"); + + LinesToDigest.emplace_front(GONERSPEAKER_TAILS, 0, + "That's a lot to get through. Good luck, MS-1!"); + + break; + } + default: + LinesToDigest.emplace_front(GONERSPEAKER_TAILS, 0, + "I am error"); + } + + leftoff = false; +} + +gdgoner_t goner_lasttypelooking = GDGONER_INIT; +tic_t goner_youactuallylooked = 0; + +void M_GonerRailroad(bool set) +{ + INT16 destsize = std::min( + static_cast( + (set ? 2 : 1) // Quit + options + maybe 1 for extra access + + std::max(0, gamedata->gonerlevel - GDGONER_VIDEO) + ), + currentMenu->extra2); + currentMenu->numitems = destsize; + + if (!set) + return; + + itemOn = destsize-1; + S_StartSound(NULL, sfx_s3k5b); +} + +void M_GonerHidePassword(void) +{ + if (currentMenu->menuitems[0].mvar2) + return; + + currentMenu->menuitems[0] = + {IT_STRING | IT_CALL, "EXIT PROGRAM", + "CONCLUDE OBSERVATIONS NOW.", NULL, + {.routine = M_QuitSRB2}, 0, 1}; +} + }; // namespace +void M_GonerResetLooking(int type) +{ + if (goner_youactuallylooked > 2*TICRATE + && goner_lasttypelooking == gamedata->gonerlevel) + { + if (goner_levelworking > gamedata->gonerlevel) + goner_levelworking--; + gamedata->gonerlevel++; + LinesToDigest.clear(); + } + + goner_lasttypelooking = static_cast(type); + goner_youactuallylooked = 0; +} + +void M_GonerCheckLooking(void) +{ + if (goner_lasttypelooking != gamedata->gonerlevel) + return; + goner_youactuallylooked++; +} + void M_GonerTick(void) { - static bool speakersinit = false; - if (!speakersinit) - { - goner_delay = TICRATE; + static bool first = true; + if (goner_levelworking == GDGONER_INIT) + { + first = true; + + // Init. goner_speakers[GONERSPEAKER_EGGMAN] = GonerSpeaker("eggman", 0); goner_speakers[GONERSPEAKER_TAILS] = GonerSpeaker("tails", 12); + } + else if (gamedata->gonerlevel == GDGONER_INIT) + { + first = true; // a lie, but only slightly... - LinesToDigest.emplace_front(GONERSPEAKER_EGGMAN, TICRATE, - "Metal Sonic. Are you online?"); - LinesToDigest.emplace_front(GONERSPEAKER_EGGMAN, TICRATE/2, - "Take a close look, Miles. Moments ago he was at my throat!\ - Now he's docile as can be on that operating table."); + // Handle rewinding if you clear your gamedata. + goner_typewriter.ClearText(); + LinesToDigest.clear(); + LinesOutput.clear(); - LinesToDigest.emplace_front(GONERSPEAKER_TAILS, 0, - "I don't feel very safe!"); - LinesToDigest.emplace_front(GONERSPEAKER_TAILS, TICRATE/4, - "But its programming is definitely locked down..."); - - LinesToDigest.emplace_front(GONERSPEAKER_EGGMAN, 0, - "You've given me quite the headache, Metal.\ - Thankfully, Tails caught you in the act."); - - LinesToDigest.emplace_front(GONERSPEAKER_TAILS, TICRATE/5, - "Wait, I'm getting weird readings over the network."); - LinesToDigest.emplace_front(GONERSPEAKER_TAILS, 0, - "Metal Sonic is the unit labeled \"MS1\", right?"); - LinesToDigest.emplace_front(GONERSPEAKER_TAILS, TICRATE, - "The ""\x87""viewport""\x80"" and ""\x87""audio""\x80"" config looks like it got messed up."); - - LinesToDigest.emplace_front(GONERSPEAKER_EGGMAN, 0, - "So you're right. I wonder if it has anything to do with that outburst."); - LinesToDigest.emplace_front(GONERSPEAKER_EGGMAN, 0, - "Alright, Metal! I don't remember your specifications offhand. First things first, go ahead and set up your ""\x87""Video Options""\x80"" yourself."); - - LinesToDigest.reverse(); - - speakersinit = true; + goner_levelworking = GDGONER_INIT; } - if (menutyping.active == false && cv_dummyextraspassword.string[0] != '\0') - { - // Challenges are not interpreted at this stage. - // See M_ExtraTick for the full behaviour. + M_GonerResetLooking(GDGONER_INIT); - cht_Interpret(cv_dummyextraspassword.string); - CV_StealthSet(&cv_dummyextraspassword, ""); + if (first) + { + first = false; + + if (gamedata->gonerlevel < GDGONER_INTRO) + gamedata->gonerlevel = GDGONER_INTRO; + + M_GonerRailroad(false); } goner_typewriter.WriteText(); + if (menutyping.active || menumessage.active || P_AutoPause()) + return; + + if (cv_dummyextraspassword.string[0] != '\0') + { + // Challenges are not interpreted at this stage. + // See M_ExtraTick for the full behaviour. + + if (!cht_Interpret(cv_dummyextraspassword.string)) + { + goner_delay = 0; + LinesToDigest.emplace_front(GONERSPEAKER_EGGMAN, TICRATE, + "Aha! Nice try. You're tricky enough WITHOUT admin access, thank you."); + M_GonerHidePassword(); + goner_nicetry = true; + } + + CV_StealthSet(&cv_dummyextraspassword, ""); + } + if (goner_typewriter.textDone) { + if (!LinesOutput.empty()) + M_GonerHidePassword(); if (goner_delay > 0) goner_delay--; else if (!LinesToDigest.empty()) @@ -223,6 +468,21 @@ void M_GonerTick(void) LinesOutput.push_front(line); LinesToDigest.pop_front(); } + else if (goner_levelworking <= gamedata->gonerlevel) + { + if (goner_levelworking == GDGONER_INTRO && gamedata->gonerlevel < GDGONER_VIDEO) + gamedata->gonerlevel = GDGONER_VIDEO; + + if (++goner_levelworking > gamedata->gonerlevel) + { + // We've reached the end of the goner text for now. + M_GonerRailroad(true); + } + else if (!goner_gdq) + { + M_AddGonerLines(); + } + } } } @@ -240,10 +500,15 @@ static void M_GonerDrawer(void) float newy = BASEVIDHEIGHT/2 + (3*12); boolean first = true; + int lastspeaker = MAXGONERSPEAKERS; + for (auto & element : LinesOutput) { INT32 flags = V_TRANSLUCENT; std::string text; + + if (newy < 0) break; + if (first) { text = goner_typewriter.text; @@ -255,9 +520,12 @@ static void M_GonerDrawer(void) { text = element.dialogue; newy -= element.value*12; + + if (lastspeaker != element.speaker) + newy -= 2; } - if (newy < 0) break; + lastspeaker = element.speaker; //if (newy > BASEVIDHEIGHT) continue; -- not needed yet @@ -267,18 +535,21 @@ static void M_GonerDrawer(void) .xy(speaker.offset, newy) .flags(flags); - int skinID = speaker.GetSkinID(); - if (skinID != -1) - { - line - .xy(-16, -2) - .colormap(skinID, static_cast(skins[skinID].prefcolor)) - .patch(faceprefix[skinID][FACE_MINIMAP]); - } - line .font(srb2::Draw::Font::kThin) .text( text.c_str() ); + + int skinID = speaker.GetSkinID(); + if (skinID != -1) + { + line = line + .xy(-16, -2) + .colormap(skinID, static_cast(skins[skinID].prefcolor)); + if (gamedata->gonerlevel > GDGONER_VIDEO) + line.patch(faceprefix[skinID][FACE_MINIMAP]); + else + line.patch("HUHMAP"); + } } M_DrawHorizontalMenu(); @@ -307,6 +578,8 @@ void M_GonerProfile(INT32 choice) // This will create a new profile if necessary. M_StartEditProfile(MA_YES); PR_ApplyProfilePretend(optionsmenu.profilen, 0); + + M_GonerResetLooking(GDGONER_PROFILE); } void M_GonerTutorial(INT32 choice) @@ -338,19 +611,38 @@ void M_GonerTutorial(INT32 choice) "YOU ACCEPT EVERYTHING THAT WILL HAPPEN FROM NOW ON.", &M_QuitResponse, MM_YESNO, "I agree", "Cancel"); } + + gamedata->gonerlevel = GDGONER_DONE; } -static boolean M_GonerInputs(INT32 ch) +void M_GonerGDQ(boolean opinion) { - const UINT8 pid = 0; - (void)ch; + if (currentMenu != &MAIN_GonerDef) + return; - if (M_MenuBackPressed(pid)) + LinesToDigest.clear(); + goner_delay = TICRATE/2; + goner_gdq = true; + + // The mapping of true/false to each opinion is completely + // arbitrary, and is not a comment on the nature of the Metroid run. + + if (opinion) // Save The Animals { - // No returning to the title screen. - M_QuitSRB2(-1); - return true; + LinesToDigest.emplace_front(GONERSPEAKER_EGGMAN, TICRATE/2, + "Why wouldn't you save the frames..?"); + LinesToDigest.emplace_front(GONERSPEAKER_TAILS, 0, + "Don't mind him. Good luck on the run!"); } + else // Save The Frames + { + LinesToDigest.emplace_front(GONERSPEAKER_TAILS, TICRATE/2, + "But what about all the little animals..."); + LinesToDigest.emplace_front(GONERSPEAKER_EGGMAN, 0, + "It's just logical. I know you'll conquer this run."); + } + LinesToDigest.reverse(); - return false; + goner_levelworking = GDGONER_TUTORIAL; + gamedata->gonerlevel = GDGONER_DONE; } diff --git a/src/menus/options-1.c b/src/menus/options-1.c index 9f43cc6aa..faba2786f 100644 --- a/src/menus/options-1.c +++ b/src/menus/options-1.c @@ -197,6 +197,8 @@ void M_OptionsTick(void) optionsmenu.fade--; if (optionsmenu.currcolour != currentMenu->extra1) M_OptionsChangeBGColour(currentMenu->extra1); + + M_GonerCheckLooking(); } // And one last giggle... @@ -213,12 +215,14 @@ void M_VideoOptions(INT32 choice) { (void)choice; M_OptionsMenuGoto(&OPTIONS_VideoDef); + M_GonerResetLooking(GDGONER_VIDEO); } void M_SoundOptions(INT32 choice) { (void)choice; M_OptionsMenuGoto(&OPTIONS_SoundDef); + M_GonerResetLooking(GDGONER_SOUND); } boolean M_OptionsInputs(INT32 ch)