Goner Setup: Cook 3 - Add "Outro"

One last guaranteed visit to the setup, to get a sendoff before the game truly begins.
(The "survey program" joke is now themed softlock prevention.)
This commit is contained in:
toaster 2023-12-07 23:36:02 +00:00
parent 8a2445820e
commit 11fcb0b9ae
6 changed files with 115 additions and 36 deletions

View file

@ -1144,11 +1144,29 @@ void M_DrawKartGamemodeMenu(void)
void M_DrawHorizontalMenu(void)
{
INT32 x = BASEVIDWIDTH/2, y = currentMenu->y, i;
INT32 x, y, i, final = currentMenu->extra2-1, showflags;
const INT32 width = 80;
y = currentMenu->y;
x = (BASEVIDWIDTH - 8*final)/2;
for (i = 0; i < currentMenu->extra2; i++, x += 8)
{
if (i == itemOn)
{
V_DrawFill(x-2, y + 16, 4, 4, 0);
}
else
{
V_DrawFill(x-1, y + 17, 2, 2,
(i >= currentMenu->numitems) ? 20 : 10
);
}
}
i = itemOn;
x = BASEVIDWIDTH/2;
do
{
@ -1161,9 +1179,21 @@ void M_DrawHorizontalMenu(void)
while (x < BASEVIDWIDTH + (width/2))
{
showflags = 0;
if (i == final)
{
showflags |= V_STRINGDANCE;
if (itemOn == i)
showflags |= V_YELLOWMAP;
}
else if (i == itemOn)
{
showflags |= highlightflags;
}
V_DrawCenteredThinString(
x, y,
(i == itemOn) ? highlightflags : 0,
showflags,
currentMenu->menuitems[i].text
);
@ -1172,30 +1202,13 @@ void M_DrawHorizontalMenu(void)
x += width;
}
y++; // thin string means better to bottom-align these
if (itemOn != 0)
V_DrawCharacter((BASEVIDWIDTH - width)/2 + 3 - (skullAnimCounter/5), y,
V_DrawCharacter((BASEVIDWIDTH - width)/2 + 3 - (skullAnimCounter/5), y + 1,
'\x1C' | highlightflags, false); // left arrow
if (itemOn != currentMenu->numitems-1)
V_DrawCharacter((BASEVIDWIDTH + width)/2 - 10 + (skullAnimCounter/5), y,
V_DrawCharacter((BASEVIDWIDTH + width)/2 - 10 + (skullAnimCounter/5), y + 1,
'\x1D' | highlightflags, false); // right arrow
x = (BASEVIDWIDTH - 8*(currentMenu->extra2-1))/2;
for (i = 0; i < currentMenu->extra2; i++, x += 8)
{
if (i == itemOn)
{
V_DrawFill(x-2, y + 15, 4, 4, 0);
}
else
{
V_DrawFill(x-1, y + 16, 2, 2,
(i >= currentMenu->numitems) ? 20 : 10
);
}
}
}
#define MAXMSGLINELEN 256

View file

@ -563,6 +563,20 @@ void M_StartControlPanel(void)
Music_Stop("title");
if (gamedata != NULL
&& gamedata->gonerlevel < GDGONER_OUTRO
&& gamestartchallenge < MAXUNLOCKABLES)
{
// See M_GameTrulyStarted
if (
gamedata->unlockpending[gamestartchallenge]
|| gamedata->unlocked[gamestartchallenge]
)
{
gamedata->gonerlevel = GDGONER_OUTRO;
}
}
if (M_GameTrulyStarted() == false)
{
// Are you ready for the First Boot Experience?
@ -600,7 +614,7 @@ void M_StartControlPanel(void)
}
else
{
if (restoreMenu == NULL)
if (restoreMenu == NULL || restoreMenu == &MAIN_GonerDef)
restoreMenu = &MainDef;
currentMenu = M_SpecificMenuRestore(M_InterruptMenuWithChallenges(restoreMenu));
restoreMenu = NULL;

View file

@ -3220,10 +3220,13 @@ boolean M_GameTrulyStarted(void)
return true;
// Okay, we can check to see if this challenge has been achieved.
return (
/*return (
gamedata->unlockpending[gamestartchallenge]
|| gamedata->unlocked[gamestartchallenge]
);
);*/
// Actually, on second thought, let's let the Goner Setup play one last time
// The above is used in M_StartControlPanel instead
return (gamedata->gonerlevel == GDGONER_DONE);
}
boolean M_CheckNetUnlockByID(UINT16 unlockid)

View file

@ -296,6 +296,7 @@ typedef enum {
GDGONER_SOUND,
GDGONER_PROFILE,
GDGONER_TUTORIAL,
GDGONER_OUTRO,
GDGONER_DONE,
} gdgoner_t;

View file

@ -12,6 +12,9 @@
#include <forward_list>
static void M_GonerDrawer(void);
static void M_GonerConclude(INT32 choice);
menuitem_t MAIN_Goner[] =
{
{IT_STRING | IT_CALL, NULL, NULL, NULL, {.routine = M_QuitSRB2}, 0, 0}, // will be replaced
@ -31,9 +34,11 @@ menuitem_t MAIN_Goner[] =
{IT_STRING | IT_CALL, "BEGIN TUTORIAL",
"PREPARE FOR INTEGRATION.", NULL,
{.routine = M_GonerTutorial}, 0, 0},
};
static void M_GonerDrawer(void);
{IT_STRING | IT_CALL, "START GAME",
"I WILL SUCCEED.", NULL,
{.routine = M_GonerConclude}, 0, 0},
};
menu_t MAIN_GonerDef = {
1, // Intentionally not the sizeof calc
@ -305,7 +310,6 @@ void M_AddGonerLines(void)
break;
}
case GDGONER_TUTORIAL:
case GDGONER_DONE: // maybe we could do something different for this eventually
{
if (!leftoff)
{
@ -329,6 +333,36 @@ void M_AddGonerLines(void)
break;
}
case GDGONER_OUTRO:
{
if (!leftoff)
{
LinesToDigest.emplace_front(GONERSPEAKER_EGGMAN, TICRATE/3,
"And... the training data is completed.");
}
LinesToDigest.emplace_front(GONERSPEAKER_TAILS, TICRATE/2,
"It's kind of funny, actually.");
LinesToDigest.emplace_front(GONERSPEAKER_EGGMAN, TICRATE/3,
"Oh? Care to elucidate, Prower?");
LinesToDigest.emplace_front(GONERSPEAKER_TAILS, TICRATE/2,
"No matter how much time we took getting here, a machine like Metal can play it back in minutes.");
LinesToDigest.emplace_front(GONERSPEAKER_TAILS, TICRATE/2,
"It could have been five days or five years of development on our ""\x82""Ring Racers""\x80"", and that barely matters.");
LinesToDigest.emplace_front(GONERSPEAKER_EGGMAN, TICRATE/4,
"Ha! As if. I'd like to think our partnership hasn't felt that long.");
LinesToDigest.emplace_front(GONERSPEAKER_EGGMAN, TICRATE/2,
"But yes. Perhaps now you have a better appreciation of what we're building here, Metal.");
LinesToDigest.emplace_front(GONERSPEAKER_EGGMAN, TICRATE/2,
"Now, I'm willing to let bygones be bygones.");
LinesToDigest.emplace_front(GONERSPEAKER_EGGMAN, TICRATE/2,
"As long as you keep your violence to the track, I'll be giving you your autonomy back in a moment.");
LinesToDigest.emplace_front(GONERSPEAKER_TAILS, 0,
"We've kept the keys from you long enough!");
break;
}
case GDGONER_DONE:
break;
default:
LinesToDigest.emplace_front(GONERSPEAKER_TAILS, 0,
"I am error");
@ -624,6 +658,15 @@ void M_GonerProfile(INT32 choice)
M_GonerResetLooking(GDGONER_PROFILE);
}
static boolean M_GonerSurveyResponse(INT32 ch)
{
if (ch != CH_YES)
return;
if (gamedata->gonerlevel < GDGONER_OUTRO)
gamedata->gonerlevel = GDGONER_OUTRO;
}
void M_GonerTutorial(INT32 choice)
{
(void)choice;
@ -646,15 +689,23 @@ void M_GonerTutorial(INT32 choice)
cupgrid.grandprix = false;
levellist.levelsearch.timeattack = false;
if (!M_LevelListFromGametype(GT_TUTORIAL))
if (!M_LevelListFromGametype(GT_TUTORIAL) && gamedata->gonerlevel < GDGONER_OUTRO)
{
// The game is incapable of progression, but I can't bring myself to put an I_Error here.
M_StartMessage("SURVEY_PROGRAM",
M_StartMessage("Agreement",
"YOU ACCEPT EVERYTHING THAT WILL HAPPEN FROM NOW ON.",
&M_QuitResponse, MM_YESNO, "I agree", "Cancel");
&M_GonerSurveyResponse, MM_YESNO, "I agree", "Cancel");
}
}
goner_levelworking = gamedata->gonerlevel = GDGONER_DONE;
static void M_GonerConclude(INT32 choice)
{
(void)choice;
gamedata->gonerlevel = GDGONER_DONE;
M_ClearMenus(true);
M_GonerResetText();
}
void M_GonerGDQ(boolean opinion)

View file

@ -744,11 +744,8 @@ void M_LevelSelected(INT16 add)
D_MapChange(levellist.choosemap+1, levellist.newgametype, (cv_kartencore.value == 1), 1, 1, false, false);
if (M_GameTrulyStarted() == false)
{
// No restoreMenu set.
}
else if (levellist.levelsearch.tutorial)
if (!M_GameTrulyStarted() ||
levellist.levelsearch.tutorial)
{
restoreMenu = currentMenu;
}