Merge branch 'tutorial-pass' into 'master'

Goner Setup + Tutorial first pass

Closes #697

See merge request KartKrew/Kart!1692
This commit is contained in:
toaster 2023-12-18 23:05:51 +00:00
commit fd7de3c604
76 changed files with 3060 additions and 678 deletions

View file

@ -667,6 +667,27 @@ bool CallFunc_CameraWait(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::
return true; // Execution interrupted
}
/*--------------------------------------------------
bool Dialogue_ValidCheck(ACSVM::Thread *thread)
Helper to check if the thread's dialogue
context is valid, initialising if not set.
--------------------------------------------------*/
static bool Dialogue_ValidCheck(ACSVM::Thread *thread)
{
// TODO when we move away from g_dialogue
if (netgame)
{
return false;
}
auto info = &static_cast<Thread *>(thread)->info;
if (!info->dialogue_era)
info->dialogue_era = g_dialogue.GetNewEra();
return g_dialogue.EraIsValid(info->dialogue_era);
}
/*--------------------------------------------------
bool CallFunc_DialogueWaitDismiss(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
@ -678,17 +699,18 @@ bool CallFunc_DialogueWaitDismiss(ACSVM::Thread *thread, const ACSVM::Word *argV
(void)argV;
(void)argC;
// TODO when we move away from g_dialogue
if (netgame)
if (Dialogue_ValidCheck(thread) == false)
{
return false;
}
g_dialogue.SetDismissable(true);
auto info = &static_cast<Thread *>(thread)->info;
thread->state = {
ACSVM::ThreadState::WaitTag,
0,
info->dialogue_era,
ACS_TAGTYPE_DIALOGUE
};
@ -706,17 +728,18 @@ bool CallFunc_DialogueWaitText(ACSVM::Thread *thread, const ACSVM::Word *argV, A
(void)argV;
(void)argC;
// TODO when we move away from g_dialogue
if (netgame)
if (Dialogue_ValidCheck(thread) == false)
{
return false;
}
g_dialogue.SetDismissable(false);
auto info = &static_cast<Thread *>(thread)->info;
thread->state = {
ACSVM::ThreadState::WaitTag,
1,
info->dialogue_era,
ACS_TAGTYPE_DIALOGUE
};
@ -1278,7 +1301,9 @@ bool CallFunc_PlayerRings(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM:
&& (info->mo != NULL && P_MobjWasRemoved(info->mo) == false)
&& (info->mo->player != NULL))
{
rings = info->mo->player->rings;
rings = (gametyperules & GTR_SPHERES)
? info->mo->player->spheres
: info->mo->player->rings;
}
thread->dataStk.push(rings);
@ -1748,6 +1773,20 @@ bool CallFunc_TimeAttack(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::
return false;
}
/*--------------------------------------------------
bool CallFunc_FreePlay(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
Returns if the map is in Free Play.
--------------------------------------------------*/
bool CallFunc_FreePlay(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
{
(void)argV;
(void)argC;
thread->dataStk.push((M_NotFreePlay() == false));
return false;
}
/*--------------------------------------------------
bool CallFunc_GrandPrix(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
@ -1762,6 +1801,20 @@ bool CallFunc_GrandPrix(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::W
return false;
}
/*--------------------------------------------------
bool CallFunc_PositionStart(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
Returns if the map is in POSITION!!
--------------------------------------------------*/
bool CallFunc_PositionStart(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
{
(void)argV;
(void)argC;
thread->dataStk.push((starttime != 0 && leveltime < starttime));
return false;
}
/*--------------------------------------------------
bool CallFunc_GetGrabbedSprayCan(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
@ -1799,6 +1852,45 @@ bool CallFunc_GetGrabbedSprayCan(ACSVM::Thread *thread, const ACSVM::Word *argV,
return false;
}
/*--------------------------------------------------
bool CallFunc_CheckTutorialChallenge(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
Returns the Tutorial Challenge status, if possible.
--------------------------------------------------*/
bool CallFunc_CheckTutorialChallenge(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
{
Environment *env = &ACSEnv;
(void)argV;
(void)argC;
if (netgame == false) // behaviour is not particularly sync-friendly
{
if (tutorialchallenge == TUTORIALSKIP_INPROGRESS)
{
thread->dataStk.push(~env->getString( "Active" )->idx);
return false;
}
if (tutorialchallenge == TUTORIALSKIP_FAILED)
{
thread->dataStk.push(~env->getString( "Failed" )->idx);
return false;
}
if (gamedata != nullptr
&& gamedata->enteredtutorialchallenge == true
&& M_GameTrulyStarted() == false)
{
thread->dataStk.push(~env->getString( "Locked" )->idx);
return false;
}
}
thread->dataStk.push(0);
return false;
}
/*--------------------------------------------------
bool CallFunc_PodiumPosition(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
@ -2025,8 +2117,7 @@ bool CallFunc_DialogueSetSpeaker(ACSVM::Thread *thread, const ACSVM::Word *argV,
(void)argC;
// TODO when we move away from g_dialogue
if (netgame)
if (Dialogue_ValidCheck(thread) == false)
{
return false;
}
@ -2069,8 +2160,7 @@ bool CallFunc_DialogueSetCustomSpeaker(ACSVM::Thread *thread, const ACSVM::Word
(void)argC;
// TODO when we move away from g_dialogue
if (netgame)
if (Dialogue_ValidCheck(thread) == false)
{
return false;
}
@ -2082,13 +2172,18 @@ bool CallFunc_DialogueSetCustomSpeaker(ACSVM::Thread *thread, const ACSVM::Word
patchStr = map->getString(argV[1]);
patchName = patchStr->str;
patch = static_cast<patch_t *>( W_CachePatchName(patchName, PU_CACHE) );
colorStr = map->getString(argV[2]);
colorName = colorStr->str;
if (ACS_GetColorFromString(colorName, &colorID) == true)
if (patchName && patchName[0])
{
colormap = R_GetTranslationColormap(TC_DEFAULT, colorID, GTC_CACHE);
patch = static_cast<patch_t *>( W_CachePatchName(patchName, PU_CACHE) );
if (ACS_GetColorFromString(colorName, &colorID) == true)
{
colormap = R_GetTranslationColormap(TC_DEFAULT, colorID, GTC_CACHE);
}
}
voiceStr = map->getString(argV[3]);
@ -2156,8 +2251,7 @@ bool CallFunc_DialogueNewText(ACSVM::Thread *thread, const ACSVM::Word *argV, AC
(void)argC;
// TODO when we move away from g_dialogue
if (netgame)
if (Dialogue_ValidCheck(thread) == false)
{
return false;
}
@ -2171,6 +2265,25 @@ bool CallFunc_DialogueNewText(ACSVM::Thread *thread, const ACSVM::Word *argV, AC
return false;
}
/*--------------------------------------------------
bool CallFunc_DialogueAutoDismiss(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
Dismiss the current dialogue text.
--------------------------------------------------*/
bool CallFunc_DialogueAutoDismiss(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
{
(void)argV;
(void)argC;
if (Dialogue_ValidCheck(thread) == false)
{
return false;
}
g_dialogue.Dismiss();
return false;
}
/*--------------------------------------------------
bool CallFunc_MusicPlay(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)

View file

@ -83,8 +83,11 @@ bool CallFunc_LowestLap(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::W
bool CallFunc_EncoreMode(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_PrisonBreak(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_TimeAttack(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_FreePlay(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_GrandPrix(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_PositionStart(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_GetGrabbedSprayCan(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_CheckTutorialChallenge(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_PodiumPosition(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_PodiumFinish(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
@ -102,6 +105,7 @@ bool CallFunc_MusicRemap(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::
bool CallFunc_DialogueSetSpeaker(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_DialogueSetCustomSpeaker(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_DialogueNewText(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_DialogueAutoDismiss(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_Freeze(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);

View file

@ -169,6 +169,9 @@ Environment::Environment()
addFuncDataACS0( 313, addCallFunc(CallFunc_GrandPrix));
addFuncDataACS0( 314, addCallFunc(CallFunc_GetGrabbedSprayCan));
addFuncDataACS0( 315, addCallFunc(CallFunc_PlayerBot));
addFuncDataACS0( 316, addCallFunc(CallFunc_PositionStart));
addFuncDataACS0( 317, addCallFunc(CallFunc_FreePlay));
addFuncDataACS0( 318, addCallFunc(CallFunc_CheckTutorialChallenge));
addFuncDataACS0( 500, addCallFunc(CallFunc_CameraWait));
addFuncDataACS0( 501, addCallFunc(CallFunc_PodiumPosition));
@ -188,6 +191,7 @@ Environment::Environment()
addFuncDataACS0( 602, addCallFunc(CallFunc_DialogueNewText));
addFuncDataACS0( 603, addCallFunc(CallFunc_DialogueWaitDismiss));
addFuncDataACS0( 604, addCallFunc(CallFunc_DialogueWaitText));
addFuncDataACS0( 605, addCallFunc(CallFunc_DialogueAutoDismiss));
}
ACSVM::Thread *Environment::allocThread()
@ -312,12 +316,13 @@ bool Environment::checkTag(ACSVM::Word type, ACSVM::Word tag)
case ACS_TAGTYPE_DIALOGUE:
{
// TODO when we move away from g_dialogue
if (netgame)
// See also call-funcs.cpp Dialogue_ValidCheck
if (netgame || !g_dialogue.EraIsValid(tag)) // cheeky reuse
{
return true;
}
if (tag == 0) // cheeky reuse
if (g_dialogue.Dismissable())
{
// wait for dismissal
return (!g_dialogue.Active());

View file

@ -66,6 +66,7 @@ public:
sector_t *sector; // Sector that activated this thread.
polyobj_t *po; // Polyobject that activated this thread.
bool fromLineSpecial; // Called from P_ProcessLineSpecial.
UINT32 dialogue_era; // Prevents overlapping dialogue scripts.
ThreadInfo() :
thread_era { thinker_era },
@ -74,7 +75,8 @@ public:
side{ 0 },
sector{ nullptr },
po{ nullptr },
fromLineSpecial{ false }
fromLineSpecial{ false },
dialogue_era { 0 }
{
}
@ -85,7 +87,8 @@ public:
side{ info.side },
sector{ info.sector },
po{ info.po },
fromLineSpecial{ info.fromLineSpecial }
fromLineSpecial{ info.fromLineSpecial },
dialogue_era { info.dialogue_era }
{
P_SetTarget(&mo, info.mo);
}
@ -97,7 +100,8 @@ public:
side{ activator->side },
sector{ activator->sector },
po{ activator->po },
fromLineSpecial{ static_cast<bool>(activator->fromLineSpecial) }
fromLineSpecial{ static_cast<bool>(activator->fromLineSpecial) },
dialogue_era { 0 }
{
P_SetTarget(&mo, activator->mo);
}
@ -118,6 +122,7 @@ public:
side = info.side;
sector = info.sector;
po = info.po;
dialogue_era = info.dialogue_era;
return *this;
}

View file

@ -1751,10 +1751,7 @@ static boolean CL_FinishedFileList(void)
}
else if (i == 3) // too many files
{
D_QuitNetGame();
CL_Reset();
D_ClearState();
M_StartControlPanel();
Command_ExitGame_f();
M_StartMessage("Server Connection Failure",
M_GetText(
"You have too many WAD files loaded\n"
@ -1765,10 +1762,7 @@ static boolean CL_FinishedFileList(void)
}
else if (i == 2) // cannot join for some reason
{
D_QuitNetGame();
CL_Reset();
D_ClearState();
M_StartControlPanel();
Command_ExitGame_f();
M_StartMessage("Server Connection Failure",
M_GetText(
"You have the wrong addons loaded.\n\n"
@ -1804,10 +1798,7 @@ static boolean CL_FinishedFileList(void)
{
if (!CL_CheckDownloadable()) // nope!
{
D_QuitNetGame();
CL_Reset();
D_ClearState();
M_StartControlPanel();
Command_ExitGame_f();
M_StartMessage("Server Connection Failure",
M_GetText(
"An error occured when trying to\n"
@ -1931,10 +1922,7 @@ static boolean CL_ServerConnectionSearchTicker(tic_t *asksent)
serverlist[i].info.commit[n]);
}
D_QuitNetGame();
CL_Reset();
D_ClearState();
M_StartControlPanel();
Command_ExitGame_f();
M_StartMessage("Server Connection Failure",
va(
@ -2084,10 +2072,7 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
{
CONS_Printf(M_GetText("Legacy downloader request packet failed.\n"));
CONS_Printf(M_GetText("Network game synchronization aborted.\n"));
D_QuitNetGame();
CL_Reset();
D_ClearState();
M_StartControlPanel();
Command_ExitGame_f();
M_StartMessage("Server Connection Failure",
M_GetText(
"The direct download encountered an error.\n"
@ -2113,10 +2098,7 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
{
CONS_Printf(M_GetText("5 minute wait time exceeded.\n"));
CONS_Printf(M_GetText("Network game synchronization aborted.\n"));
D_QuitNetGame();
CL_Reset();
D_ClearState();
M_StartControlPanel();
Command_ExitGame_f();
M_StartMessage("Server Connection Failure",
M_GetText(
"5 minute wait time exceeded.\n"
@ -2226,10 +2208,7 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
CONS_Printf(M_GetText("Network game synchronization aborted.\n"));
// M_StartMessage("Server Connection", M_GetText("Network game synchronization aborted.\n"), NULL, MM_NOTHING, NULL, "Back to Menu");
D_QuitNetGame();
CL_Reset();
D_ClearState();
M_StartControlPanel();
Command_ExitGame_f();
return false;
}
@ -3125,10 +3104,7 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
#endif
LUA_HookBool(false, HOOK(GameQuit)); //Lua hooks handled differently now
D_QuitNetGame();
CL_Reset();
D_ClearState();
M_StartControlPanel();
Command_ExitGame_f();
if (msg == KICK_MSG_CON_FAIL)
M_StartMessage("Server Disconnected", M_GetText("Server closed connection\n(Synch failure)\n"), NULL, MM_NOTHING, NULL, "Back to Menu");
@ -4326,10 +4302,7 @@ static void HandleShutdown(SINT8 node)
{
(void)node;
LUA_HookBool(false, HOOK(GameQuit));
D_QuitNetGame();
CL_Reset();
D_ClearState();
M_StartControlPanel();
Command_ExitGame_f();
M_StartMessage("Server Disconnected", M_GetText("Server has shutdown\n"), NULL, MM_NOTHING, NULL, "Back to Menu");
}
@ -4342,10 +4315,7 @@ static void HandleTimeout(SINT8 node)
{
(void)node;
LUA_HookBool(false, HOOK(GameQuit));
D_QuitNetGame();
CL_Reset();
D_ClearState();
M_StartControlPanel();
Command_ExitGame_f();
M_StartMessage("Server Disconnected", M_GetText("Server Timeout\n"), NULL, MM_NOTHING, NULL, "Back to Menu");
}
@ -4359,10 +4329,7 @@ void HandleSigfail(const char *string)
}
LUA_HookBool(false, HOOK(GameQuit));
D_QuitNetGame();
CL_Reset();
D_ClearState();
M_StartControlPanel();
Command_ExitGame_f();
M_StartMessage("Server Disconnected", va(M_GetText("Signature check failed.\n(%s)\n"), string), NULL, MM_NOTHING, NULL, "Back to Menu");
}
@ -4561,10 +4528,7 @@ static void HandlePacketFromAwayNode(SINT8 node)
break;
}
D_QuitNetGame();
CL_Reset();
D_ClearState();
M_StartControlPanel();
Command_ExitGame_f();
if (reason[1] == '|')
{

View file

@ -396,13 +396,16 @@ static bool D_Display(void)
// save the current screen if about to wipe
wipe = (gamestate != wipegamestate);
if (wipe && wipetypepre != INT16_MAX)
if (wipe)
{
// set for all later
// MUST be set for all later
wipedefindex = gamestate; // wipe_xxx_toblack
if (gamestate == GS_TITLESCREEN && wipegamestate != GS_INTRO)
wipedefindex = wipe_titlescreen_toblack;
}
if (wipe && wipetypepre != INT16_MAX)
{
if (wipetypepre < 0 || !F_WipeExists(wipetypepre))
wipetypepre = wipedefs[wipedefindex];
@ -1113,7 +1116,7 @@ void D_StartTitle(void)
void D_SetDeferredStartTitle(boolean deferred)
{
g_deferredtitle = true;
g_deferredtitle = deferred;
}
boolean D_IsDeferredStartTitle(void)

View file

@ -4795,9 +4795,6 @@ static void Command_Playintro_f(void)
if (netgame)
return;
if (dirmenu)
closefilemenu(true);
F_StartIntro();
}

View file

@ -3541,6 +3541,14 @@ void readmaincfg(MYFILE *f, boolean mainfile)
Z_Free(tutorialchallengemap);
tutorialchallengemap = Z_StrDup(word2);
}
else if (fastcmp(word, "GAMESTARTCHALLENGE"))
{
INT32 val = get_number(word2) - 1;
if (val < 0 || val >= MAXUNLOCKABLES)
gamestartchallenge = MAXUNLOCKABLES;
else
gamestartchallenge = (UINT16)val;
}
else if (fastcmp(word, "HIDETITLEPICS") || fastcmp(word, "TITLEPICSHIDE"))
{
hidetitlepics = (boolean)(value != 0 || word2[0] == 'T' || word2[0] == 'Y');

View file

@ -284,7 +284,8 @@ static void F_TitleBGScroll(INT32 scrollspeed)
// =============
// INTRO SCENE
// =============
#define NUMINTROSCENES 1
#define NUMINTROSCENES 5
#define INTROSCENE_KREW 2 // first scene with Kart Krew Dev
INT32 intro_scenenum = 0;
INT32 intro_curtime = 0;
@ -292,12 +293,18 @@ const char *introtext[NUMINTROSCENES];
static tic_t introscenetime[NUMINTROSCENES] =
{
4*TICRATE, // KART KR(eW
2*TICRATE, // OUR SRB2 ASSOCIATES
TICRATE, // Listen to Funtown USA by tv room
(3*TICRATE)/2, // KKD
(2*TICRATE)/3, // S&K
TICRATE + (TICRATE/3), // Get ready !!
};
// custom intros
void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean resetplayer);
static boolean skippableallowed = true;
void F_StartIntro(void)
{
if (gamestate)
@ -306,9 +313,20 @@ void F_StartIntro(void)
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
F_WipeEndScreen();
F_RunWipe(wipe_intro_toblack, wipedefs[wipe_intro_toblack], false, "FADEMAP0", false, false);
D_ClearState();
}
skippableallowed = (
gamestartchallenge >= MAXUNLOCKABLES
|| (gamedata && gamedata->unlocked[gamestartchallenge])
);
M_ClearMenus(false);
D_SetDeferredStartTitle(false);
Music_StopAll();
Music_Stop("title");
S_StopSounds();
if (introtoplay)
@ -323,16 +341,15 @@ void F_StartIntro(void)
introtext[0] = " #";
G_SetGamestate(GS_INTRO);
wipegamestate = gamestate;
gameaction = ga_nothing;
paused = false;
CON_ToggleOff();
F_NewCutscene(introtext[0]);
//F_NewCutscene(introtext[0]);
intro_scenenum = 0;
finalecount = animtimer = skullAnimCounter = stoptimer = 0;
timetonext = introscenetime[intro_scenenum];
Music_StopAll();
}
//
@ -340,31 +357,80 @@ void F_StartIntro(void)
//
static void F_IntroDrawScene(void)
{
boolean highres = true;
INT32 cx = 8, cy = 128;
patch_t *background = NULL;
INT32 cx = 68*FRACUNIT, cy = 20*FRACUNIT;
INT32 jitterx = 0, jittery = 0;
INT32 bgxoffs = 0;
patch_t *logoparts[5];
UINT8 bgcol = 31;
// DRAW A FULL PIC INSTEAD OF FLAT!
if (intro_scenenum == 0)
if (intro_scenenum < INTROSCENE_KREW)
{
background = W_CachePatchName("KARTKREW", PU_CACHE);
highres = true;
logoparts[0] = NULL;
}
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 0);
if (background)
else if (intro_scenenum == INTROSCENE_KREW)
{
if (highres)
V_DrawSmallScaledPatch(bgxoffs, 0, 0, background);
logoparts[0] = W_CachePatchName("KKLOGO_C", PU_CACHE);
logoparts[1] = W_CachePatchName("KKTEXT_C", PU_CACHE);
logoparts[2] = NULL;
bgcol = 0;
}
else
{
logoparts[0] = W_CachePatchName("KKLOGO_A", PU_CACHE);
logoparts[1] = W_CachePatchName("KKLOGO_B", PU_CACHE);
logoparts[2] = W_CachePatchName("KKTEXT_A", PU_CACHE);
logoparts[3] = W_CachePatchName("KKTEXT_B", PU_CACHE);
logoparts[4] = NULL;
if (intro_scenenum == INTROSCENE_KREW+1)
{
bgxoffs = 1 + P_RandomKey(PR_INTERPHUDRANDOM, 8);
bgcol -= (timetonext * 31) / introscenetime[intro_scenenum];
const angle_t fa = (FixedAngle(intro_curtime*FRACUNIT) >> ANGLETOFINESHIFT) & FINEMASK;
jitterx = FINECOSINE(fa);
jittery = FINESINE(fa);
if (finalecount & 1)
{
jitterx = -jitterx;
jittery = -jittery;
bgxoffs = -bgxoffs;
}
}
else
V_DrawScaledPatch(bgxoffs, 0, 0, background);
{
bgxoffs = (1 + 8) + ((1 + intro_curtime) * 24);
}
}
W_UnlockCachedPatch(background);
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, bgcol);
V_DrawString(cx, cy, 0, cutscene_disptext);
UINT8 i;
for (i = 0; logoparts[i]; i++)
{
V_DrawFixedPatch(
cx + jitterx + (bgxoffs * FRACUNIT),
cy + jittery,
FRACUNIT,
0,
logoparts[i],
NULL
);
bgxoffs = -bgxoffs;
if (i == 1)
{
jitterx = -jitterx;
jittery = -jittery;
}
}
//V_DrawString(cx, cy, 0, cutscene_disptext);
}
//
@ -372,7 +438,21 @@ static void F_IntroDrawScene(void)
//
void F_IntroDrawer(void)
{
// Used to be this whole thing, but now...
if (intro_scenenum == 0)
{
if (intro_curtime <= 5)
{
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 157);
return;
}
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
V_DrawScaledPatch(0, 0, 0,
W_CachePatchName("STARTUP", PU_CACHE));
return;
}
F_IntroDrawScene();
}
@ -386,72 +466,37 @@ void F_IntroTicker(void)
timetonext--;
if (D_IsDeferredStartTitle())
if (skippableallowed && D_IsDeferredStartTitle())
{
D_StartTitle();
return;
}
if (intro_scenenum == 0)
if (timetonext <= 0)
{
if (timetonext <= 0)
intro_scenenum++;
if (intro_scenenum == (M_GameTrulyStarted()
? NUMINTROSCENES
: INTROSCENE_KREW)
)
{
#if 0 // The necessary apparatus for constructing more elaborate intros...
intro_scenenum++;
F_NewCutscene(introtext[intro_scenenum]);
timetonext = introscenetime[intro_scenenum];
wipegamestate = -1;
animtimer = stoptimer = 0;
#endif
if (rendermode != render_none)
{
F_WipeStartScreen();
F_WipeColorFill(31);
F_WipeEndScreen();
F_RunWipe(wipe_intro_toblack, 99, true, "FADEMAP0", false, false);
}
// Stay on black for a bit. =)
{
tic_t nowtime, quittime, lasttime;
nowtime = lasttime = I_GetTime();
quittime = nowtime + NEWTICRATE*2; // Shortened the quit time, used to be 2 seconds
while (quittime > nowtime)
{
while (!((nowtime = I_GetTime()) - lasttime))
{
I_Sleep(cv_sleep.value);
I_UpdateTime(cv_timescale.value);
}
lasttime = nowtime;
I_OsPolling();
I_UpdateNoBlit();
#ifdef HAVE_THREADS
I_lock_mutex(&k_menu_mutex);
#endif
M_Drawer(); // menu is drawn even on top of wipes
#ifdef HAVE_THREADS
I_unlock_mutex(k_menu_mutex);
#endif
I_FinishUpdate(); // Update the screen with the image Tails 06-19-2001
#ifdef HWRENDER
if (moviemode && rendermode == render_opengl) // make sure we save frames for the white hold too
M_LegacySaveFrame();
else
#endif
if (moviemode && rendermode != render_none)
I_CaptureVideoFrame();
}
}
D_StartTitle();
// Custom built fade to skip the to-black
//wipetypepre = INT16_MAX; -- however, this breaks the title screen cacheing and I don't know why and I'm tired of fighting it.
return;
}
if (finalecount == 8)
//F_NewCutscene(introtext[intro_scenenum]);
timetonext = introscenetime[intro_scenenum];
animtimer = stoptimer = 0;
if (intro_scenenum == INTROSCENE_KREW)
wipegamestate = -1;
}
if (intro_scenenum == INTROSCENE_KREW)
{
if (timetonext == 5)
S_StartSound(NULL, sfx_vroom);
else if (finalecount == 47)
else if (timetonext == 24)
{
// Need to use M_Random otherwise it always uses the same sound
UINT32 rskin = R_GetLocalRandomSkin();
@ -1470,6 +1515,8 @@ static void F_CacheTitleScreen(void)
}
}
static boolean cache_gametrulystarted = false;
void F_StartTitleScreen(void)
{
INT32 titleMapNum;
@ -1486,7 +1533,10 @@ void F_StartTitleScreen(void)
else
wipegamestate = GS_TITLESCREEN;
if (titlemap
cache_gametrulystarted = M_GameTrulyStarted();
if (cache_gametrulystarted == true
&& titlemap
&& ((titleMapNum = G_MapNumber(titlemap)) < nummapheaders)
&& mapheaderinfo[titleMapNum]
&& mapheaderinfo[titleMapNum]->lumpnum != LUMPERROR)
@ -1550,6 +1600,9 @@ void F_StartTitleScreen(void)
F_InitMenuPresValues();
F_CacheTitleScreen();
if (menumessage.active && !menumessage.closing)
menumessage.fadetimer = 1;
}
void F_VersionDrawer(void)
@ -1600,16 +1653,19 @@ void F_TitleScreenDrawer(void)
{
boolean hidepics = false;
#if 0
if (modeattacking)
return; // We likely came here from retrying. Don't do a damn thing.
#endif
// Draw that sky!
if (curbgcolor >= 0)
if (cache_gametrulystarted == false)
{
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
}
else if (curbgcolor >= 0)
{
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, curbgcolor);
}
else if (!curbghide || !titlemapinaction || gamestate == GS_WAITINGPLAYERS)
{
F_SkyScroll(curbgxspeed, curbgyspeed, curbgname);
}
// Don't draw outside of the title screen, or if the patch isn't there.
if (gamestate != GS_TITLESCREEN && gamestate != GS_WAITINGPLAYERS)
@ -1631,35 +1687,42 @@ void F_TitleScreenDrawer(void)
case TTMODE_RINGRACERS:
{
const char *eggName = "eggman";
INT32 eggSkin = R_SkinAvailable(eggName);
skincolornum_t eggColor = SKINCOLOR_RED;
UINT8 *eggColormap = NULL;
const char *tailsName = "tails";
INT32 tailsSkin = R_SkinAvailable(tailsName);
skincolornum_t tailsColor = SKINCOLOR_ORANGE;
UINT8 *tailsColormap = NULL;
if (eggSkin != -1)
if (cache_gametrulystarted == true)
{
eggColor = skins[eggSkin].prefcolor;
}
eggColormap = R_GetTranslationColormap(TC_DEFAULT, eggColor, GTC_MENUCACHE);
const char *eggName = "eggman";
INT32 eggSkin = R_SkinAvailable(eggName);
skincolornum_t eggColor = SKINCOLOR_RED;
UINT8 *eggColormap = NULL;
if (tailsSkin != -1)
const char *tailsName = "tails";
INT32 tailsSkin = R_SkinAvailable(tailsName);
skincolornum_t tailsColor = SKINCOLOR_ORANGE;
UINT8 *tailsColormap = NULL;
if (eggSkin != -1)
{
eggColor = skins[eggSkin].prefcolor;
}
eggColormap = R_GetTranslationColormap(TC_DEFAULT, eggColor, GTC_MENUCACHE);
if (tailsSkin != -1)
{
tailsColor = skins[tailsSkin].prefcolor;
}
tailsColormap = R_GetTranslationColormap(TC_DEFAULT, tailsColor, GTC_MENUCACHE);
V_DrawFixedPatch(0, 0, FRACUNIT, 0, kts_tails_tails, tailsColormap);
V_DrawFixedPatch(0, 0, FRACUNIT, V_ADD, kts_electricity[finalecount % 6], NULL);
V_DrawFixedPatch(0, 0, FRACUNIT, 0, kts_eggman, eggColormap);
V_DrawFixedPatch(0, 0, FRACUNIT, 0, kts_tails, tailsColormap);
V_DrawFixedPatch(0, 0, FRACUNIT, 0, kts_bumper, NULL);
}
else
{
tailsColor = skins[tailsSkin].prefcolor;
V_DrawCenteredString(BASEVIDWIDTH/2, (BASEVIDHEIGHT/2) - 4, 0, "Press any button/key to continue");
}
tailsColormap = R_GetTranslationColormap(TC_DEFAULT, tailsColor, GTC_MENUCACHE);
V_DrawFixedPatch(0, 0, FRACUNIT, 0, kts_tails_tails, tailsColormap);
V_DrawFixedPatch(0, 0, FRACUNIT, V_ADD, kts_electricity[finalecount % 6], NULL);
V_DrawFixedPatch(0, 0, FRACUNIT, 0, kts_eggman, eggColormap);
V_DrawFixedPatch(0, 0, FRACUNIT, 0, kts_tails, tailsColormap);
V_DrawFixedPatch(0, 0, FRACUNIT, 0, kts_bumper, NULL);
V_DrawFixedPatch(0, 0, FRACUNIT, 0, kts_copyright, NULL);
break;
@ -1719,7 +1782,7 @@ void F_TitleScreenTicker(boolean run)
{
if (finalecount == 0)
{
if (!Music_Playing("title"))
if (cache_gametrulystarted && !Music_Playing("title"))
{
// Now start the music
Music_Loop("title", looptitle);
@ -1798,7 +1861,7 @@ void F_TitleScreenTicker(boolean run)
}
// no demos to play? or, are they disabled?
if (!cv_rollingdemos.value)
if (!cv_rollingdemos.value || cache_gametrulystarted == false)
return;
#if defined (TESTERS)

View file

@ -3000,10 +3000,7 @@ void G_FinishExitLevel(void)
{
// Back to the menu with you.
G_HandleSaveLevel(true);
D_QuitNetGame();
CL_Reset();
D_ClearState();
M_StartControlPanel();
Command_ExitGame_f();
return;
}
}
@ -4331,7 +4328,11 @@ void G_NextLevel(void)
if (
gametype == GT_TUTORIAL
&& nextmap == NEXTMAP_TUTORIALCHALLENGE
&& !(gamedata && gamedata->enteredtutorialchallenge)
&& (
!gamedata
|| gamedata->enteredtutorialchallenge == false
|| M_GameTrulyStarted() == true
)
)
{
nextmap = G_MapNumber(tutorialchallengemap);
@ -4507,8 +4508,7 @@ void G_EndGame(void)
}
// Time to return to the menu.
D_ClearState();
M_StartControlPanel();
Command_ExitGame_f();
}
//
@ -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<<GDEVER_GONERSHIFT);
if (gamedata->everloadedaddon)
everflags |= GDEVER_ADDON;

View file

@ -27,6 +27,7 @@
#include "s_sound.h"
#include "z_zone.h"
#include "k_hud.h"
#include "p_tick.h" // P_LevelIsFrozen
#include "v_draw.hpp"
@ -34,10 +35,114 @@
using srb2::Dialogue;
// Dialogue::Typewriter
void Dialogue::Typewriter::ClearText(void)
{
text.clear();
textDest.clear();
}
void Dialogue::Typewriter::NewText(std::string newText)
{
text.clear();
textDest = newText;
std::reverse(textDest.begin(), textDest.end());
textTimer = kTextPunctPause;
textSpeed = kTextSpeedDefault;
textDone = false;
textLines = 1;
syllable = true;
}
void Dialogue::Typewriter::WriteText(void)
{
if (textDone)
return;
bool voicePlayed = false;
bool empty = textDest.empty();
textTimer -= textSpeed;
while (textTimer <= 0 && !empty)
{
char c = textDest.back(), nextc = '\n';
text.push_back(c);
textDest.pop_back();
empty = textDest.empty();
if (c & 0x80)
{
// Color code support
continue;
}
if (c == '\n')
textLines++;
if (!empty)
nextc = textDest.back();
if (voicePlayed == false
&& std::isprint(c)
&& c != ' ')
{
if (syllable)
{
S_StopSoundByNum(voiceSfx);
S_StartSound(nullptr, voiceSfx);
}
syllable = !syllable;
voicePlayed = true;
}
if (c == '-' && empty)
{
textTimer += textSpeed;
}
else if (std::ispunct(c)
&& std::isspace(nextc))
{
// slow down for punctuation
textTimer += kTextPunctPause;
}
else
{
textTimer += FRACUNIT;
}
}
textDone = (textTimer <= 0 && empty);
}
void Dialogue::Typewriter::CompleteText(void)
{
while (!textDest.empty())
{
char c = textDest.back();
if (c == '\n')
textLines++;
text.push_back( c );
textDest.pop_back();
}
textTimer = 0;
textDone = true;
}
// Dialogue
void Dialogue::Init(void)
{
active = true;
syllable = true;
}
void Dialogue::SetSpeaker(void)
@ -48,7 +153,7 @@ void Dialogue::SetSpeaker(void)
portrait = nullptr;
portraitColormap = nullptr;
voiceSfx = sfx_ktalk;
typewriter.voiceSfx = sfx_ktalk;
}
void Dialogue::SetSpeaker(std::string skinName, int portraitID)
@ -70,16 +175,21 @@ void Dialogue::SetSpeaker(std::string skinName, int portraitID)
if (sprdef->numframes > 0)
{
portraitID %= sprdef->numframes;
}
const spriteframe_t *sprframe = &sprdef->spriteframes[portraitID];
const spriteframe_t *sprframe = &sprdef->spriteframes[portraitID];
portrait = static_cast<patch_t *>( W_CachePatchNum(sprframe->lumppat[0], PU_CACHE) );
portraitColormap = R_GetTranslationColormap(skinID, static_cast<skincolornum_t>(skin->prefcolor), GTC_CACHE);
}
else
{
portrait = nullptr;
portraitColormap = nullptr;
}
speaker = skin->realname;
portrait = static_cast<patch_t *>( W_CachePatchNum(sprframe->lumppat[0], PU_CACHE) );
portraitColormap = R_GetTranslationColormap(skinID, static_cast<skincolornum_t>(skin->prefcolor), GTC_CACHE);
voiceSfx = skin->soundsid[ S_sfx[sfx_ktalk].skinsound ];
typewriter.voiceSfx = skin->soundsid[ S_sfx[sfx_ktalk].skinsound ];
}
else
{
@ -98,14 +208,14 @@ void Dialogue::SetSpeaker(std::string name, patch_t *patch, UINT8 *colormap, sfx
{
portrait = nullptr;
portraitColormap = nullptr;
voiceSfx = sfx_ktalk;
typewriter.voiceSfx = sfx_ktalk;
return;
}
portrait = patch;
portraitColormap = colormap;
voiceSfx = voice;
typewriter.voiceSfx = voice;
}
void Dialogue::NewText(std::string newText)
@ -119,14 +229,7 @@ void Dialogue::NewText(std::string newText)
newText.c_str()
);
text.clear();
textDest = newText;
std::reverse(textDest.begin(), textDest.end());
textTimer = kTextPunctPause;
textSpeed = kTextSpeedDefault;
textDone = false;
typewriter.NewText(newText);
}
bool Dialogue::Active(void)
@ -136,7 +239,7 @@ bool Dialogue::Active(void)
bool Dialogue::TextDone(void)
{
return textDone;
return typewriter.textDone;
}
bool Dialogue::Dismissable(void)
@ -149,57 +252,6 @@ void Dialogue::SetDismissable(bool value)
dismissable = value;
}
void Dialogue::WriteText(void)
{
bool voicePlayed = false;
textTimer -= textSpeed;
while (textTimer <= 0 && !textDest.empty())
{
char c = textDest.back(), nextc = '\n';
text.push_back(c);
textDest.pop_back();
if (c & 0x80)
{
// Color code support
continue;
}
if (!textDest.empty())
nextc = textDest.back();
if (voicePlayed == false
&& std::isprint(c)
&& c != ' ')
{
if (syllable)
{
S_StopSoundByNum(voiceSfx);
S_StartSound(nullptr, voiceSfx);
}
syllable = !syllable;
voicePlayed = true;
}
if (std::ispunct(c)
&& std::isspace(nextc))
{
// slow down for punctuation
textTimer += kTextPunctPause;
}
else
{
textTimer += FRACUNIT;
}
}
textDone = (textTimer <= 0 && textDest.empty());
}
bool Dialogue::Held(void)
{
return ((players[serverplayer].cmd.buttons & BT_VOTE) == BT_VOTE);
@ -213,18 +265,6 @@ bool Dialogue::Pressed(void)
);
}
void Dialogue::CompleteText(void)
{
while (!textDest.empty())
{
text.push_back( textDest.back() );
textDest.pop_back();
}
textTimer = 0;
textDone = true;
}
void Dialogue::Tick(void)
{
if (Active())
@ -254,7 +294,7 @@ void Dialogue::Tick(void)
return;
}
WriteText();
typewriter.WriteText();
if (Dismissable() == true)
{
@ -266,12 +306,21 @@ void Dialogue::Tick(void)
}
else
{
CompleteText();
typewriter.CompleteText();
}
}
}
}
INT32 Dialogue::SlideAmount(fixed_t multiplier)
{
if (slide == 0)
return 0;
if (slide == FRACUNIT)
return multiplier;
return Easing_OutCubic(slide, 0, multiplier);
}
void Dialogue::Draw(void)
{
if (slide == 0)
@ -279,60 +328,172 @@ void Dialogue::Draw(void)
return;
}
const UINT8 bgcol = 1, darkcol = 235;
const fixed_t height = 78 * FRACUNIT;
INT32 speakernameedge = -6;
srb2::Draw drawer =
srb2::Draw(
0, FixedToFloat(Easing_OutCubic(slide, -78 * FRACUNIT, 0))
).flags(V_SNAPTOTOP);
BASEVIDWIDTH, BASEVIDHEIGHT - FixedToFloat(SlideAmount(height) - height)
).flags(V_SNAPTOBOTTOM);
drawer.patch("TUTDIAG1");
// TODO -- hack, change when dialogue is made per-player/netsynced
UINT32 speakerbgflags = (players[consoleplayer].nocontrol == 0 && P_LevelIsFrozen() == false)
? (V_ADD|V_30TRANS)
: 0;
drawer
.flags(speakerbgflags|V_VFLIP|V_FLIP)
.patch("TUTDIAGA");
drawer
.flags(V_VFLIP|V_FLIP)
.patch("TUTDIAGB");
if (portrait != nullptr)
{
drawer
.xy(10, 41)
.flags(V_VFLIP|V_FLIP)
.patch("TUTDIAGC");
drawer
.xy(-10-32, -41-32)
.colormap(portraitColormap)
.patch(portrait);
speakernameedge -= 39; // -45
}
const char *speakername = speaker.c_str();
const INT32 arrowstep = 8; // width of TUTDIAGD
if (speakername && speaker[0])
{
INT32 speakernamewidth = V_StringWidth(speakername, 0);
INT32 existingborder = (portrait == nullptr ? -4 : 3);
INT32 speakernamewidthoffset = (speakernamewidth + (arrowstep - existingborder) - 1) % arrowstep;
if (speakernamewidthoffset)
{
speakernamewidthoffset = (arrowstep - speakernamewidthoffset);
speakernamewidth += speakernamewidthoffset;
}
if (portrait == nullptr)
{
speakernameedge -= 3;
speakernamewidth += 3;
existingborder += 2;
drawer
.xy(speakernameedge, -36)
.width(2)
.height(3+11)
.fill(bgcol);
}
if (speakernamewidth > existingborder)
{
drawer
.x(speakernameedge - speakernamewidth)
.width(speakernamewidth - existingborder)
.y(-36-3)
.height(3)
.fill(bgcol);
drawer
.x(speakernameedge - speakernamewidth)
.width(speakernamewidth - existingborder)
.y(-38-11)
.height(11)
.fill(darkcol);
}
speakernameedge -= speakernamewidth;
drawer
.xy(speakernamewidthoffset + speakernameedge, -39-9)
.font(srb2::Draw::Font::kConsole)
.text(speakername);
speakernameedge -= 5;
drawer
.xy(speakernameedge, -36)
.flags(V_VFLIP|V_FLIP)
.patch("TUTDIAGD");
drawer
.xy(speakernameedge, -36-3-11)
.width(5)
.height(3+11)
.fill(bgcol);
drawer
.xy(speakernameedge + 5, -36)
.flags(V_VFLIP|V_FLIP)
.patch("TUTDIAGF");
}
while (speakernameedge > -142) // the left-most edge
{
speakernameedge -= arrowstep;
drawer
.xy(speakernameedge, -36)
.flags(V_VFLIP|V_FLIP)
.patch("TUTDIAGD");
}
drawer
.xy(45, 39)
.font(srb2::Draw::Font::kConsole)
.text( speaker.c_str() );
.xy(speakernameedge - arrowstep, -36)
.flags(V_VFLIP|V_FLIP)
.patch("TUTDIAGE");
drawer
.xy(10, 3)
.xy(10 - BASEVIDWIDTH, -3-32)
.font(srb2::Draw::Font::kConsole)
.text( text.c_str() );
.text( typewriter.text.c_str() );
if (Dismissable())
{
if (TextDone())
{
drawer
.xy(304, 7)
.xy(-14, -7-5)
.patch("TUTDIAG2");
}
K_drawButton(
FloatToFixed(drawer.x() + 303),
FloatToFixed(drawer.y() + 39),
V_SNAPTOTOP,
kp_button_z[0], Held()
);
drawer
.xy(17-14 - BASEVIDWIDTH, -39-16)
.button(srb2::Draw::Button::z, Held());
}
}
void Dialogue::Dismiss(void)
{
active = false;
text.clear();
textDest.clear();
typewriter.ClearText();
}
UINT32 Dialogue::GetNewEra(void)
{
return (++current_era);
}
bool Dialogue::EraIsValid(INT32 comparison)
{
return (current_era == comparison);
}
void Dialogue::Unset(void)
{
Dismiss();
SetSpeaker();
slide = 0;
current_era = 0;
}
/*
@ -358,3 +519,8 @@ void K_TickDialogue(void)
{
g_dialogue.Tick();
}
INT32 K_GetDialogueSlide(fixed_t multiplier)
{
return g_dialogue.SlideAmount(multiplier);
}

View file

@ -26,6 +26,7 @@ void K_DrawDialogue(void);
void K_TickDialogue(void);
boolean K_DialogueFreeze(void);
INT32 K_GetDialogueSlide(fixed_t multiplier);
#ifdef __cplusplus
} // extern "C"

View file

@ -27,41 +27,7 @@ namespace srb2
class Dialogue
{
private:
patch_t *bgPatch;
patch_t *confirmPatch;
std::string speaker;
patch_t *portrait;
UINT8 *portraitColormap;
sfxenum_t voiceSfx;
std::string text;
std::string textDest;
bool active;
fixed_t slide;
fixed_t textTimer;
fixed_t textSpeed;
bool textDone;
bool syllable;
bool dismissable;
bool freeze;
void Init(void);
//void Unset(void);
void WriteText(void);
void CompleteText(void);
bool Pressed(void);
bool Held(void);
public:
static constexpr fixed_t kTextSpeedDefault = FRACUNIT;
static constexpr fixed_t kTextPunctPause = (FRACUNIT * TICRATE * 2) / 5;
static constexpr fixed_t kSlideSpeed = FRACUNIT / (TICRATE / 5);
void SetSpeaker(void);
@ -78,8 +44,62 @@ public:
void Tick(void);
void Draw(void);
INT32 SlideAmount(fixed_t multiplier);
void Dismiss(void);
void Unset(void);
UINT32 GetNewEra(void);
bool EraIsValid(INT32 comparison);
class Typewriter
{
public:
static constexpr fixed_t kTextSpeedDefault = FRACUNIT;
static constexpr fixed_t kTextPunctPause = (FRACUNIT * TICRATE * 2) / 5;
std::string text;
std::string textDest;
fixed_t textTimer;
fixed_t textSpeed;
bool textDone;
int textLines;
sfxenum_t voiceSfx;
bool syllable;
void NewText(std::string newText);
void ClearText(void);
void WriteText(void);
void CompleteText(void);
};
private:
Typewriter typewriter;
INT32 current_era;
patch_t *bgPatch;
patch_t *confirmPatch;
std::string speaker;
patch_t *portrait;
UINT8 *portraitColormap;
bool active;
fixed_t slide;
bool dismissable;
bool freeze;
void Init(void);
//void Unset(void);
bool Pressed(void);
bool Held(void);
};
}; // namespace srb2

View file

@ -5462,6 +5462,10 @@ void K_drawKartHUD(void)
if (demo.title)
;
else if (gametype == GT_TUTORIAL)
{
islonesome = true;
}
else if (!r_splitscreen)
{
// Draw the timestamp

View file

@ -5060,7 +5060,7 @@ static mobj_t *K_SpawnKartMissile(mobj_t *source, mobjtype_t type, angle_t an, I
Obj_JawzThrown(th, finalspeed, dir);
break;
case MT_SPB:
th->movefactor = finalspeed;
Obj_SPBThrown(th, finalspeed);
break;
case MT_BUBBLESHIELDTRAP:
P_SetScale(th, ((5*th->destscale)>>2)*4);
@ -12864,14 +12864,12 @@ UINT8 K_GetOrbinautItemFrame(UINT8 count)
boolean K_IsSPBInGame(void)
{
UINT8 i;
thinker_t *think;
// is there an SPB chasing anyone?
if (spbplace != -1)
return true;
// do any players have an SPB in their item slot?
UINT8 i;
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator)
@ -12881,14 +12879,15 @@ boolean K_IsSPBInGame(void)
return true;
}
// spbplace is still -1 until a fired SPB finds a target, so look for an in-map SPB just in case
for (think = thlist[THINK_MOBJ].next; think != &thlist[THINK_MOBJ]; think = think->next)
mobj_t *mobj;
for (mobj = trackercap; mobj; mobj = mobj->itnext)
{
if (think->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
if (mobj->type != MT_SPB)
continue;
if (((mobj_t *)think)->type == MT_SPB)
return true;
return true;
}
return false;

View file

@ -136,6 +136,7 @@ typedef enum
MBF_UD_LR_FLIPPED = 1, // flip up-down and left-right axes
MBF_SOUNDLESS = 1<<1, // do not play base menu sounds
MBF_NOLOOPENTRIES = 1<<2, // do not loop M_NextOpt/M_PrevOpt
MBF_DRAWBGWHILEPLAYING = 1<<3, // run backroutine() outside of GS_MENU
} menubehaviourflags_t;
struct menuitem_t
@ -170,6 +171,7 @@ struct menu_t
INT16 transitionTics; // tics for transitions out
void (*drawroutine)(void); // draw routine
void (*bgroutine)(void); // draw routine, but, like, for the background
void (*tickroutine)(void); // ticker routine
void (*initroutine)(void); // called when starting a new menu
boolean (*quitroutine)(void); // called before quit a menu return true if we can
@ -200,6 +202,20 @@ typedef enum
quitkart
} main_e;
extern menuitem_t MAIN_Goner[];
extern menu_t MAIN_GonerDef;
void M_GonerTick(void);
void M_GonerBGTick(void);
void M_GonerBGImplyPassageOfTime(void);
void M_DrawGonerBack(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);
boolean M_GonerMusicPlayable(void);
extern menuitem_t PLAY_CharSelect[];
extern menu_t PLAY_CharSelectDef;
@ -247,6 +263,8 @@ typedef enum
ta_start,
} ta_e;
// If you add another Time Attach submenu, remember to catch level-select.c's music/bgroutine update
extern menuitem_t PLAY_TAReplay[];
extern menu_t PLAY_TAReplayDef;
@ -322,15 +340,17 @@ extern menu_t MAIN_ProfilesDef;
typedef enum
{
popt_profilename = 0,
popt_profilepname,
popt_char,
popt_controls,
popt_char,
popt_profilepname,
popt_confirm,
} popt_e;
extern menuitem_t OPTIONS_EditProfile[];
extern menu_t OPTIONS_EditProfileDef;
void M_StartEditProfile(INT32 c);
extern menuitem_t OPTIONS_ProfileControls[];
extern menu_t OPTIONS_ProfileControlsDef;
@ -629,6 +649,7 @@ boolean M_MenuExtraPressed(UINT8 pid);
boolean M_MenuExtraHeld(UINT8 pid);
void M_StartControlPanel(void);
void M_ValidateRestoreMenu(void);
menu_t *M_SpecificMenuRestore(menu_t *torestore);
void M_ClearMenus(boolean callexitmenufunc);
void M_SelectableClearMenus(INT32 choice);
@ -990,6 +1011,9 @@ boolean M_OptionsInputs(INT32 ch);
boolean M_OptionsQuit(void); // resets buttons when you quit the options.
void M_OptionsChangeBGColour(INT16 newcolour); // changes the background colour for options
void M_VideoOptions(INT32 choice);
void M_SoundOptions(INT32 choice);
void M_HandleItemToggles(INT32 choice); // For item toggling
void M_EraseData(INT32 choice); // For data erasing
void M_CheckProfileData(INT32 choice); // check if we have profiles.
@ -1156,6 +1180,7 @@ void M_DrawMenuForeground(void);
void M_Drawer(void);
void M_DrawGenericMenu(void);
void M_DrawKartGamemodeMenu(void);
void M_DrawHorizontalMenu(void);
void M_DrawTextBox(INT32 x, INT32 y, INT32 width, INT32 boxlines);
void M_DrawMessageMenu(void);
void M_DrawImageDef(void);
@ -1166,6 +1191,7 @@ boolean M_DrawCharacterSprite(INT16 x, INT16 y, INT16 skin, UINT8 spr2, UINT8 ro
void M_DrawCup(cupheader_t *cup, fixed_t x, fixed_t y, INT32 lockedTic, boolean isTrophy, UINT8 placement);
void M_DrawCupSelect(void);
void M_DrawLevelSelect(void);
void M_DrawSealedBack(void);
void M_DrawTimeAttack(void);
void M_DrawRaceDifficulty(void);
@ -1185,6 +1211,7 @@ void M_DrawKickHandler(void);
void M_DrawPlaybackMenu(void);
// Options menus:
void M_DrawOptionsCogs(void);
void M_DrawOptionsMovingButton(void); // for sick transitions...
void M_DrawOptions(void);
void M_DrawGenericOptions(void);
@ -1197,6 +1224,7 @@ void M_DrawProfileErase(void);
extern tic_t shitsfree;
// Extras menu:
void M_DrawExtrasBack(void);
void M_DrawExtrasMovingButton(void);
void M_DrawExtras(void);
@ -1375,6 +1403,7 @@ const char *M_GetDiscordName(discordRequest_t *r);
NULL,\
NULL,\
NULL,\
NULL,\
NULL\
}
@ -1394,6 +1423,7 @@ const char *M_GetDiscordName(discordRequest_t *r);
NULL,\
NULL,\
NULL,\
NULL,\
NULL\
}
@ -1412,6 +1442,7 @@ const char *M_GetDiscordName(discordRequest_t *r);
NULL,\
NULL,\
NULL,\
NULL,\
NULL\
}

View file

@ -231,6 +231,12 @@ void M_DrawMenuBackground(void)
}
}
void M_DrawExtrasBack(void)
{
patch_t *bg = W_CachePatchName("M_XTRABG", PU_CACHE);
V_DrawFixedPatch(0, 0, FRACUNIT, 0, bg, NULL);
}
UINT16 M_GetCvPlayerColor(UINT8 pnum)
{
if (pnum >= MAXSPLITSCREENPLAYERS)
@ -601,7 +607,7 @@ static void M_DrawMenuTyping(void)
#undef BUTTONHEIGHT
y = 175;
y = 187;
if (menutyping.menutypingfade < 9)
{
@ -611,15 +617,46 @@ static void M_DrawMenuTyping(void)
// Some contextual stuff
if (menutyping.keyboardtyping)
{
V_DrawThinString(returnx, y, V_GRAYMAP, "Type using your keyboard. Press Enter to confirm & exit.\nUse your controller or any directional input to use the Virtual Keyboard.\n");
V_DrawThinString(returnx, y, V_GRAYMAP,
"Type using your keyboard. Press Enter to confirm & exit."
//"\nPress any button on your controller to use the Virtual Keyboard."
);
}
else
{
V_DrawThinString(returnx, y, V_GRAYMAP, "Type using the Virtual Keyboard. Use the \'OK\' button to confirm & exit.\nPress any keyboard key not bound to a control to use it.");
V_DrawThinString(returnx, y, V_GRAYMAP,
"Type using the Virtual Keyboard. Use the \'OK\' button to confirm & exit."
//"\nPress any keyboard key to type normally."
);
}
}
static void M_DrawMediocreKeyboardKey(const char *text, INT32 *workx, INT32 worky, boolean push, boolean rightaligned)
{
INT32 buttonwidth = V_StringWidth(text, 0) + 2;
if (rightaligned)
{
(*workx) -= buttonwidth;
}
if (push)
{
worky += 2;
}
else
{
V_DrawFill((*workx)-1, worky+10, buttonwidth, 2, 24);
}
V_DrawFill((*workx)-1, worky, buttonwidth, 10, 16);
V_DrawString(
(*workx), worky + 1,
0, text
);
}
// Draw the message popup submenu
void M_DrawMenuMessage(void)
{
@ -646,6 +683,10 @@ void M_DrawMenuMessage(void)
INT32 workx = x + menumessage.x;
INT32 worky = y + menumessage.y;
boolean standardbuttons = (
cv_currprofile.value != -1 || G_GetNumAvailableGamepads()
);
boolean push;
if (menumessage.closing)
@ -666,19 +707,26 @@ void M_DrawMenuMessage(void)
workx -= 2;
workx -= SHORT(kp_button_x[1][0]->width);
K_drawButton(
workx * FRACUNIT, worky * FRACUNIT,
0, kp_button_x[1],
push
);
if (standardbuttons)
{
workx -= SHORT(kp_button_x[1][0]->width);
K_drawButton(
workx * FRACUNIT, worky * FRACUNIT,
0, kp_button_x[1],
push
);
workx -= SHORT(kp_button_b[1][0]->width);
K_drawButton(
workx * FRACUNIT, worky * FRACUNIT,
0, kp_button_b[1],
push
);
workx -= SHORT(kp_button_b[1][0]->width);
K_drawButton(
workx * FRACUNIT, worky * FRACUNIT,
0, kp_button_b[1],
push
);
}
else
{
M_DrawMediocreKeyboardKey("ESC", &workx, worky, push, true);
}
if (menumessage.confirmstr)
{
@ -698,12 +746,19 @@ void M_DrawMenuMessage(void)
workx -= 2;
}
workx -= SHORT(kp_button_a[1][0]->width);
K_drawButton(
workx * FRACUNIT, worky * FRACUNIT,
0, kp_button_a[1],
push
);
if (standardbuttons)
{
workx -= SHORT(kp_button_a[1][0]->width);
K_drawButton(
workx * FRACUNIT, worky * FRACUNIT,
0, kp_button_a[1],
push
);
}
else
{
M_DrawMediocreKeyboardKey("ENTER", &workx, worky, push, true);
}
}
x -= 4;
@ -778,14 +833,34 @@ void M_Drawer(void)
// background layer
if (menuactive)
{
if (gamestate == GS_MENU)
boolean drawbgroutine = false;
boolean trulystarted = M_GameTrulyStarted();
if (gamestate == GS_MENU && trulystarted)
{
M_DrawMenuBackground();
if (currentMenu->bgroutine)
drawbgroutine = true;
else
M_DrawMenuBackground();
}
else if (!WipeInAction && currentMenu != &PAUSE_PlaybackMenuDef)
else
{
V_DrawFadeScreen(122, 3);
if (currentMenu->bgroutine
&& (currentMenu->behaviourflags & MBF_DRAWBGWHILEPLAYING))
drawbgroutine = true;
if (!Playing() && !trulystarted)
{
M_DrawGonerBack();
}
else if (!WipeInAction && currentMenu != &PAUSE_PlaybackMenuDef)
{
V_DrawFadeScreen(122, 3);
}
}
if (drawbgroutine)
currentMenu->bgroutine();
}
// draw pause pic
@ -1116,6 +1191,81 @@ void M_DrawKartGamemodeMenu(void)
}
}
void M_DrawHorizontalMenu(void)
{
INT32 x, y, i, final = currentMenu->extra2-1, showflags;
const INT32 width = 80;
y = currentMenu->y;
V_DrawFadeFill(0, y-2, BASEVIDWIDTH, 24, 0, 31, 5);
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 if (i >= currentMenu->numitems)
{
V_DrawFill(x-1, y + 17, 2, 2, 20);
}
else
{
V_DrawFill(x-1, y + 17, 2, 2,
(i == final && skullAnimCounter/5) ? 73 : 10
);
}
}
i = itemOn;
x = BASEVIDWIDTH/2;
do
{
if (i == 0)
break;
i--;
x -= width;
}
while (x > -width/2);
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,
showflags,
currentMenu->menuitems[i].text
);
if (++i == currentMenu->numitems)
break;
x += width;
}
if (itemOn != 0)
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 + 1,
'\x1D' | highlightflags, false); // right arrow
}
#define MAXMSGLINELEN 256
//
@ -2095,7 +2245,7 @@ void M_DrawCharacterSelect(void)
UINT8 priority = 0;
INT16 quadx, quady;
INT16 skin;
INT32 basex = optionsmenu.profile != NULL ? 64 : 0;
INT32 basex = optionsmenu.profile ? (64 + (menutransition.tics*32)) : 0;
boolean forceskin = (Playing() && K_CanChangeRules(true) == true) && (cv_forceskin.value != -1);
if (setup_numplayers > 0)
@ -2104,13 +2254,16 @@ void M_DrawCharacterSelect(void)
}
{
const int kLeft = 80;
const int kLeft = 76;
const int kTop = 6;
const int kButtonWidth = 16;
INT32 x = basex + kLeft;
K_drawButton((x += 18) * FRACUNIT, (kTop - 3) * FRACUNIT, 0, kp_button_r, M_MenuButtonPressed(pid, MBT_R));
V_DrawThinString((x += kButtonWidth), kTop, 0, "Info");
if (!optionsmenu.profile) // Does nothing on this screen
{
K_drawButton((x += 22) * FRACUNIT, (kTop - 3) * FRACUNIT, 0, kp_button_r, M_MenuButtonPressed(pid, MBT_R));
V_DrawThinString((x += kButtonWidth), kTop, 0, "Info");
}
K_drawButton((x += 58) * FRACUNIT, (kTop - 1) * FRACUNIT, 0, kp_button_c[1], M_MenuButtonPressed(pid, MBT_C));
V_DrawThinString((x += kButtonWidth), kTop, 0, "Default");
@ -2969,12 +3122,6 @@ void M_DrawLevelSelect(void)
INT16 y = 80 - (12 * levellist.y);
boolean tatransition = ((menutransition.startmenu == &PLAY_TimeAttackDef || menutransition.endmenu == &PLAY_TimeAttackDef) && menutransition.tics);
if (levellist.levelsearch.tutorial)
{
patch_t *bg = W_CachePatchName("M_XTRABG", PU_CACHE);
V_DrawFixedPatch(0, 0, FRACUNIT, 0, bg, NULL);
}
if (tatransition)
{
t = -t;
@ -3007,6 +3154,49 @@ void M_DrawLevelSelect(void)
M_DrawCupTitle(tay, &levellist.levelsearch);
}
static boolean M_LevelSelectHasBG(menu_t *check)
{
if (check == NULL)
check = currentMenu;
return (check == &PLAY_LevelSelectDef
|| check == &PLAY_CupSelectDef);
}
static boolean M_LevelSelectToTimeAttackTransitionHelper(void)
{
if (menutransition.tics == 0)
return false;
return (M_LevelSelectHasBG(menutransition.startmenu))
!= M_LevelSelectHasBG(menutransition.endmenu);
}
void M_DrawSealedBack(void)
{
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
if (M_LevelSelectHasBG(currentMenu) == false)
return;
INT32 translucencylevel = 7;
if (M_LevelSelectToTimeAttackTransitionHelper())
{
translucencylevel += menutransition.tics/3;
if (translucencylevel >= 10)
return;
}
V_DrawFixedPatch(
0, 0,
FRACUNIT,
translucencylevel << V_ALPHASHIFT,
W_CachePatchName("MENUI008", PU_CACHE),
R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_BLACK, GTC_CACHE)
);
}
void M_DrawTimeAttack(void)
{
UINT16 map = levellist.choosemap;
@ -3015,27 +3205,95 @@ void M_DrawTimeAttack(void)
INT16 rightedge = 149+t+155;
INT16 opty = 140;
INT32 w;
patch_t *minimap = NULL;
UINT8 i;
M_DrawLevelSelectBlock(0, 2, map, true, false);
//V_DrawFill(24-t, 82, 100, 100, 36); // size test
V_DrawScaledPatch(149+t, 70, 0, W_CachePatchName("BESTTIME", PU_CACHE));
if (currentMenu == &PLAY_TimeAttackDef && mapheaderinfo[map])
if (!mapheaderinfo[map])
{
tic_t timerec = 0;
tic_t laprec = 0;
V_DrawRightAlignedString(rightedge-12, opty, 0, "No map!?");
return;
}
{
patch_t *minimap = NULL;
INT32 minimapx = 76, minimapy = 130;
if (M_LevelSelectToTimeAttackTransitionHelper())
minimapx -= t;
if (levellist.newgametype == GT_SPECIAL)
{
// Star Within The Seal
#define SEAL_PULSELEN ((6*TICRATE)/5) // The rate of O_SSTAR3
INT32 crossfade = (timeattackmenu.ticker % (2*SEAL_PULSELEN)) - SEAL_PULSELEN;
if (crossfade < 0)
crossfade = -crossfade;
crossfade = (crossfade * 10)/SEAL_PULSELEN;
#undef SEAL_PULSELEN
if (crossfade != 10)
{
minimap = W_CachePatchName(
"K_FINB05",
PU_CACHE
);
V_DrawScaledPatch(
minimapx, minimapy,
0, minimap
);
}
if (crossfade != 0)
{
minimap = W_CachePatchName(
"K_FINB04",
PU_CACHE
);
V_DrawScaledPatch(
minimapx, minimapy,
(10-crossfade)<<V_ALPHASHIFT,
minimap
);
}
}
else if (levellist.newgametype == GT_VERSUS)
{
const INT32 teaserh = 56;
minimapy -= 1; // tiny adjustment
V_DrawScaledPatch(
minimapx, minimapy - teaserh,
V_TRANSLUCENT, W_CachePatchName("K_TEASR2", PU_CACHE)
);
V_DrawScaledPatch(
minimapx, minimapy + teaserh,
V_TRANSLUCENT, W_CachePatchName("K_TEASR4", PU_CACHE)
);
V_DrawScaledPatch(
minimapx, minimapy,
0, W_CachePatchName("K_TEASR3", PU_CACHE)
);
}
else if ((minimap = mapheaderinfo[map]->minimapPic))
{
V_DrawScaledPatch(
minimapx - (SHORT(minimap->width)/2),
minimapy - (SHORT(minimap->height)/2),
0, minimap
);
}
}
if (currentMenu == &PLAY_TimeAttackDef)
{
tic_t timerec = mapheaderinfo[map]->records.time;
tic_t laprec = mapheaderinfo[map]->records.lap;
UINT32 timeheight = 82;
if ((minimap = mapheaderinfo[map]->minimapPic))
V_DrawScaledPatch(24-t, 82, 0, minimap);
timerec = mapheaderinfo[map]->records.time;
laprec = mapheaderinfo[map]->records.lap;
if ((gametypes[levellist.newgametype]->rules & GTR_CIRCUIT)
&& (mapheaderinfo[map]->numlaps != 1))
{
@ -3069,6 +3327,9 @@ void M_DrawTimeAttack(void)
else
opty = 80;
// Done after to overlay material
M_DrawLevelSelectBlock(0, 2, map, true, false);
for (i = 0; i < currentMenu->numitems; i++)
{
UINT32 f = (i == itemOn) ? highlightflags : 0;
@ -3233,7 +3494,6 @@ void M_DrawEggaChannel(void)
// Multiplayer mode option select
void M_DrawMPOptSelect(void)
{
M_DrawEggaChannel();
M_DrawMenuTooltips();
M_MPOptDrawer(&PLAY_MP_OptSelectDef, mpmenu.modewinextend);
M_DrawMasterServerReminder();
@ -3243,7 +3503,6 @@ void M_DrawMPOptSelect(void)
// A rehash of the generic menu drawer adapted to fit into that cramped space. ...A small sacrifice for utility
void M_DrawMPHost(void)
{
patch_t *gobutt = W_CachePatchName("M_BUTTGO", PU_CACHE); // I'm very mature
INT32 xp = 40, yp = 64, i = 0, w = 0; // Starting position for the text drawing.
@ -3348,7 +3607,6 @@ void M_DrawMPHost(void)
// (I don't like duplicating code but I rather this than some horrible all-in-one function with too many options...)
void M_DrawMPJoinIP(void)
{
//patch_t *minibutt = W_CachePatchName("M_SBUTT", PU_CACHE);
// There is no such things as mini butts, only thick thighs to rest your head on.
//patch_t *minigo = W_CachePatchName("M_SGO", PU_CACHE);
@ -3674,12 +3932,15 @@ void M_DrawMPServerBrowser(void)
// OPTIONS MENU
// Draws the cogs and also the options background!
static void M_DrawOptionsCogs(void)
void M_DrawOptionsCogs(void)
{
boolean trulystarted = M_GameTrulyStarted();
UINT32 tick = ((optionsmenu.ticker/10) % 3) + 1;
// the background isn't drawn outside of being in the main menu state.
if (gamestate == GS_MENU)
if (gamestate == GS_MENU && trulystarted)
{
patch_t *back[3] = {W_CachePatchName("OPT_BG1", PU_CACHE), W_CachePatchName("OPT_BG2", PU_CACHE), W_CachePatchName("OPT_BG3", PU_CACHE)};
patch_t *back = W_CachePatchName(va("OPT_BG%u", tick), PU_CACHE);
INT32 tflag = 0;
UINT8 *c;
UINT8 *c2; // colormap for the one we're changing
@ -3687,19 +3948,24 @@ static void M_DrawOptionsCogs(void)
if (optionsmenu.fade)
{
c2 = R_GetTranslationColormap(TC_DEFAULT, optionsmenu.lastcolour, GTC_CACHE);
V_DrawFixedPatch(0, 0, FRACUNIT, 0, back[(optionsmenu.ticker/10) %3], c2);
V_DrawFixedPatch(0, 0, FRACUNIT, 0, back, c2);
// prepare fade flag:
tflag = min(V_90TRANS, (optionsmenu.fade)<<V_ALPHASHIFT);
}
c = R_GetTranslationColormap(TC_DEFAULT, optionsmenu.currcolour, GTC_CACHE);
V_DrawFixedPatch(0, 0, FRACUNIT, tflag, back[(optionsmenu.ticker/10) %3], c);
V_DrawFixedPatch(0, 0, FRACUNIT, tflag, back, c);
}
else
{
patch_t *back_pause[3] = {W_CachePatchName("OPT_BAK1", PU_CACHE), W_CachePatchName("OPT_BAK2", PU_CACHE), W_CachePatchName("OPT_BAK3", PU_CACHE)};
V_DrawFixedPatch(0, 0, FRACUNIT, V_MODULATE, back_pause[(optionsmenu.ticker/10) %3], NULL);
patch_t *back_pause = W_CachePatchName(va("OPT_BAK%u", tick), PU_CACHE);
V_DrawFixedPatch(0, 0, FRACUNIT, V_MODULATE, back_pause, NULL);
if (!trulystarted)
{
V_DrawFixedPatch(0, 0, FRACUNIT, (V_ADD|V_70TRANS), back_pause, NULL);
}
}
}
@ -3721,8 +3987,6 @@ void M_DrawOptions(void)
UINT8 *c = NULL;
M_DrawOptionsCogs();
for (i=0; i < currentMenu->numitems; i++)
{
INT32 py = y - (itemOn*48);
@ -3758,7 +4022,6 @@ void M_DrawGenericOptions(void)
{
INT32 x = currentMenu->x - menutransition.tics*48, y = currentMenu->y, w, i, cursory = 0;
M_DrawOptionsCogs();
M_DrawMenuTooltips();
M_DrawOptionsMovingButton();
@ -3908,7 +4171,6 @@ void M_DrawProfileErase(void)
INT32 x = currentMenu->x - menutransition.tics*48, y = currentMenu->y-SMALLLINEHEIGHT, i, cursory = 0;
UINT8 np = PR_GetNumProfiles();
M_DrawOptionsCogs();
M_DrawMenuTooltips();
M_DrawOptionsMovingButton();
@ -3940,7 +4202,6 @@ void M_DrawProfileSelect(void)
INT32 x = 160 - optionsmenu.profilen*(128 + 128/8) + optionsmenu.offset;
INT32 y = 35 + menutransition.tics*32;
M_DrawOptionsCogs();
M_DrawMenuTooltips();
// This shouldn't be drawn when a profile is selected as optx/opty are used to move the card.
@ -3970,11 +4231,9 @@ void M_DrawEditProfile(void)
{
INT32 y = 34;
INT32 x = 145;
INT32 x = (145 + (menutransition.tics*32));
INT32 i;
M_DrawOptionsCogs();
// Tooltip
// The text is slightly shifted hence why we don't just use M_DrawMenuTooltips()
V_DrawFixedPatch(0, 0, FRACUNIT, 0, W_CachePatchName("MENUHINT", PU_CACHE), NULL);
@ -3990,33 +4249,34 @@ void M_DrawEditProfile(void)
UINT8 *colormap = NULL;
INT32 tflag = (currentMenu->menuitems[i].status & IT_TRANSTEXT) ? V_TRANSLUCENT : 0;
y = currentMenu->menuitems[i].mvar2;
// Background -- 169 is the plague colourization
V_DrawFill(0, y, 400 - (menutransition.tics*64), 10, itemOn == i ? 169 : 30);
if (i == itemOn)
{
colormap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_PLAGUE, GTC_CACHE);
// Background
V_DrawFill(0, y, 400 - (menutransition.tics*64), 24, itemOn == i ? 169 : 30); // 169 is the plague colourization
V_DrawCharacter(x - 10 - (skullAnimCounter/5), y+1,
'\x1C' | highlightflags, false); // left arrow
}
// Text
V_DrawGamemodeString(x + (menutransition.tics*32), y - 6, tflag, colormap, currentMenu->menuitems[i].text);
//V_DrawGamemodeString(x, y - 6, tflag, colormap, currentMenu->menuitems[i].text);
V_DrawStringScaled(
x * FRACUNIT,
(y - 3) * FRACUNIT,
FRACUNIT,
FRACUNIT,
FRACUNIT,
tflag,
colormap,
KART_FONT,
currentMenu->menuitems[i].text
);
// Cvar specific handling
/*switch (currentMenu->menuitems[i].status & IT_TYPE)
{
case IT_CVAR:
{
consvar_t *cv = currentMenu->menuitems[i].itemaction.cvar;
switch (currentMenu->menuitems[i].status & IT_CVARTYPE)
{
case IT_CV_STRING:
V_DrawFill(0, y+24, 400 - (menutransition.tics*64), 16, itemOn == i ? 169 : 30); // 169 is the plague colourization
V_DrawString(x + 8, y + 29, 0, cv->string);
if (skullAnimCounter < 4 && i == itemOn)
V_DrawCharacter(x + 8 + V_StringWidth(cv->string, 0), y + 29, '_', false);
y += 16;
}
}
}*/
y += 34;
//y += 32 + 2;
}
// Finally, draw the card ontop
@ -4072,8 +4332,6 @@ void M_DrawProfileControls(void)
INT32 i, j, k;
const UINT8 pid = 0;
M_DrawOptionsCogs();
V_DrawScaledPatch(BASEVIDWIDTH*2/3 - optionsmenu.contx, BASEVIDHEIGHT/2 -optionsmenu.conty, 0, W_CachePatchName("PR_CONT", PU_CACHE));
// Draw button presses...
@ -4302,7 +4560,6 @@ void M_DrawVideoModes(void)
{
INT32 i, j, row, col;
M_DrawOptionsCogs();
M_DrawMenuTooltips();
M_DrawOptionsMovingButton();
@ -4388,7 +4645,6 @@ void M_DrawItemToggles(void)
consvar_t *cv;
INT32 i, translucent, drawnum;
M_DrawOptionsCogs();
M_DrawMenuTooltips();
M_DrawOptionsMovingButton();
@ -4531,12 +4787,9 @@ void M_DrawExtras(void)
INT32 x = 140 - (48*itemOn) + extrasmenu.offset;
INT32 y = 70 + extrasmenu.offset;
patch_t *buttback = W_CachePatchName("OPT_BUTT", PU_CACHE);
patch_t *bg = W_CachePatchName("M_XTRABG", PU_CACHE);
UINT8 *c = NULL;
V_DrawFixedPatch(0, 0, FRACUNIT, 0, bg, NULL);
for (i=0; i < currentMenu->numitems; i++)
{
INT32 py = y - (itemOn*48);
@ -5051,14 +5304,6 @@ void M_DrawAddons(void)
M_CacheAddonPatches();
// hack: If we're calling this from GS_MENU, that means we're in the extras menu!
// so draw the apropriate background
if (gamestate == GS_MENU)
{
patch_t *bg = W_CachePatchName("M_XTRABG", PU_CACHE);
V_DrawFixedPatch(0, 0, FRACUNIT, 0, bg, NULL);
}
if (Playing())
V_DrawCenteredString(BASEVIDWIDTH/2, 4, warningflags, "Adding files mid-game may cause problems.");
else
@ -6875,11 +7120,6 @@ void M_DrawStatistics(void)
char beststr[256];
tic_t besttime = 0;
{
patch_t *bg = W_CachePatchName("M_XTRABG", PU_CACHE);
V_DrawFixedPatch(0, 0, FRACUNIT, 0, bg, NULL);
}
{
const char *pagename = NULL;
INT32 pagenamewidth = 0;
@ -6996,28 +7236,6 @@ void M_DrawStatistics(void)
V_DrawRightAlignedThinString(BASEVIDWIDTH-20, 50, 0, beststr);
}
static INT32 M_WrongWarpFallingHelper(INT32 y, INT32 falltime)
{
if (wrongwarp.ticker < falltime)
{
return y;
}
if (wrongwarp.ticker > falltime + 2*TICRATE)
{
return INT32_MAX;
}
if (wrongwarp.ticker < falltime + TICRATE)
{
y += + ((wrongwarp.ticker - falltime) & 1 ? 1 : -1);
return y;
}
y += floor(pow(1.5, (double)(wrongwarp.ticker - (falltime + TICRATE))));
return y;
}
static void M_DrawWrongPlayer(UINT8 i)
{
#define wrongpl wrongwarp.wrongplayers[i]
@ -7043,60 +7261,6 @@ void M_DrawWrongWarp(void)
INT32 titleoffset = 0, titlewidth, x, y;
const char *titletext = "WRONG GAME? WRONG GAME! ";
if (gamestate == GS_MENU)
{
patch_t *pat, *pat2;
INT32 animtimer, anim2 = 0;
pat = W_CachePatchName("TITLEBG1", PU_CACHE);
pat2 = W_CachePatchName("TITLEBG2", PU_CACHE);
animtimer = ((wrongwarp.ticker*5)/16) % SHORT(pat->width);
anim2 = SHORT(pat2->width) - (((wrongwarp.ticker*5)/16) % SHORT(pat2->width));
// SRB2Kart: F_DrawPatchCol is over-engineered; recoded to be less shitty and error-prone
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 0);
x = -((INT32)animtimer);
y = 0;
while (x < BASEVIDWIDTH)
{
V_DrawFixedPatch(x*FRACUNIT, y*FRACUNIT, FRACUNIT, 0, pat, NULL);
x += SHORT(pat->width);
}
x = -anim2;
y = BASEVIDHEIGHT - SHORT(pat2->height);
while (x < BASEVIDWIDTH)
{
V_DrawFixedPatch(x*FRACUNIT, y*FRACUNIT, FRACUNIT, 0, pat2, NULL);
x += SHORT(pat2->width);
}
}
{
patch_t *ttcheckers = W_CachePatchName("TTCHECK", PU_CACHE);
y = FixedMul(40<<FRACBITS, FixedDiv(wrongwarp.ticker%70, 70));
V_DrawSciencePatch(0, -y, 0, ttcheckers, FRACUNIT);
V_DrawSciencePatch(280<<FRACBITS, -(40<<FRACBITS) + y, 0, ttcheckers, FRACUNIT);
y = M_WrongWarpFallingHelper(36, 7*TICRATE/4);
if (y != INT32_MAX)
{
patch_t *ttbanner = W_CachePatchName("TTKBANNR", PU_CACHE);
V_DrawSmallScaledPatch(84, y, 0, ttbanner);
}
y = M_WrongWarpFallingHelper(87, 4*TICRATE/3);
if (y != INT32_MAX)
{
patch_t *ttkart = W_CachePatchName("TTKART", PU_CACHE);
V_DrawSmallScaledPatch(84, y, 0, ttkart);
}
}
if (wrongwarp.ticker < 2*TICRATE/3)
return;
@ -7147,12 +7311,6 @@ void M_DrawSoundTest(void)
patch_t *btn = W_CachePatchName("STER_BTN", PU_CACHE);
if (gamestate == GS_MENU)
{
patch_t *bg = W_CachePatchName("M_XTRABG", PU_CACHE);
V_DrawFixedPatch(0, 0, FRACUNIT, 0, bg, NULL);
}
V_DrawFixedPatch(0, 0, FRACUNIT, 0, W_CachePatchName("STER_BG", PU_CACHE), NULL);
x = 24;

View file

@ -365,11 +365,37 @@ void M_PlayMenuJam(void)
return;
}
gdmusic_t override = musicstatepermitted ? gamedata->musicstate : 0;
if (Playing() || soundtest.playing)
if (soundtest.playing)
return;
const boolean trulystarted = M_GameTrulyStarted();
const boolean profilemode = (
trulystarted
&& optionsmenu.profilemenu
&& !optionsmenu.resetprofilemenu
);
if (!profilemode && Playing())
{
if (optionsmenu.resetprofilemenu)
Music_Stop("menu");
return;
}
if (!trulystarted)
{
if (M_GonerMusicPlayable() && NotCurrentlyPlaying("_GONER"))
{
Music_Remap("menu", "_GONER");
Music_Play("menu");
}
return;
}
gdmusic_t override = musicstatepermitted ? gamedata->musicstate : 0;
if (refMenu != NULL && refMenu->music != NULL)
{
if (refMenu->music[0] == '.' && refMenu->music[1] == '\0')
@ -408,7 +434,7 @@ void M_PlayMenuJam(void)
return;
}
if (cv_menujam_update.value)
if (!profilemode && cv_menujam_update.value)
{
CV_AddValue(&cv_menujam, 1);
CV_SetValue(&cv_menujam_update, 0);
@ -423,6 +449,12 @@ void M_PlayMenuJam(void)
#undef IsCurrentlyPlaying
void M_ValidateRestoreMenu(void)
{
if (restoreMenu == NULL || restoreMenu == &MAIN_GonerDef)
restoreMenu = &MainDef;
}
//
// M_SpecificMenuRestore
//
@ -558,7 +590,32 @@ void M_StartControlPanel(void)
Music_Stop("title");
if (cv_currprofile.value == -1) // Only ask once per session.
if (gamedata != NULL
&& gamedata->gonerlevel < GDGONER_OUTRO
&& gamestartchallenge < MAXUNLOCKABLES)
{
// See M_GameTrulyStarted
if (
gamedata->unlockpending[gamestartchallenge]
|| gamedata->unlocked[gamestartchallenge]
)
{
gamedata->gonerlevel = GDGONER_OUTRO;
M_GonerBGImplyPassageOfTime();
}
}
if (M_GameTrulyStarted() == false)
{
// Are you ready for the First Boot Experience?
M_ResetOptions();
currentMenu = &MAIN_GonerDef;
restoreMenu = NULL;
M_PlayMenuJam();
}
else if (cv_currprofile.value == -1) // Only ask once per session.
{
// Make sure the profile data is ready now since we need to select a profile.
M_ResetOptions();
@ -570,8 +627,9 @@ void M_StartControlPanel(void)
// options don't need initializing here.
// make sure we don't overstep that.
if (optionsmenu.profilen > PR_GetNumProfiles())
optionsmenu.profilen = PR_GetNumProfiles();
const INT32 maxp = PR_GetNumProfiles();
if (optionsmenu.profilen > maxp)
optionsmenu.profilen = maxp;
else if (optionsmenu.profilen < 0)
optionsmenu.profilen = 0;
@ -585,8 +643,7 @@ void M_StartControlPanel(void)
}
else
{
if (restoreMenu == NULL)
restoreMenu = &MainDef;
M_ValidateRestoreMenu();
currentMenu = M_SpecificMenuRestore(M_InterruptMenuWithChallenges(restoreMenu));
restoreMenu = NULL;
@ -726,8 +783,10 @@ void M_GoBack(INT32 choice)
M_SetupNextMenu(currentMenu->prevMenu, false);
}
else
else if (Playing() || M_GameTrulyStarted())
M_ClearMenus(true);
else // No returning to the title screen.
M_QuitSRB2(-1);
S_StartSound(NULL, sfx_s3k5b);
}
@ -1144,7 +1203,14 @@ void M_Ticker(void)
}
if (--skullAnimCounter <= 0)
{
skullAnimCounter = 8;
}
if (!Playing() && !M_GameTrulyStarted())
{
M_GonerBGTick();
}
#if 0
if (currentMenu == &PAUSE_PlaybackMenuDef)

View file

@ -41,9 +41,11 @@ void Obj_ItemDebrisThink(mobj_t *debris);
fixed_t Obj_ItemDebrisBounce(mobj_t *debris, fixed_t momz);
/* SPB */
void Obj_SPBThrown(mobj_t *spb, fixed_t finalspeed);
void Obj_SPBThink(mobj_t *spb);
void Obj_SPBExplode(mobj_t *spb);
void Obj_SPBTouch(mobj_t *spb, mobj_t *toucher);
void Obj_SPBEradicateCapsules(void);
/* SPB Juicebox Rings */
void Obj_MantaRingThink(mobj_t *manta);

View file

@ -1577,6 +1577,9 @@ static void K_KartGetItemResult(player_t *const player, kartitems_t getitem)
player->itemtype = K_ItemResultToType(getitem);
player->itemamount = K_ItemResultToAmount(getitem);
if (player->itemtype == KITEM_SPB)
Obj_SPBEradicateCapsules();
}
/*--------------------------------------------------

View file

@ -73,17 +73,31 @@ static UINT8 cheatf_warp(void)
{
if (!unlockables[i].conditionset)
continue;
if (!gamedata->unlocked[i])
{
gamedata->unlocked[i] = true;
success = true;
}
if (gamedata->unlocked[i])
continue;
gamedata->unlocked[i] = true;
success = true;
}
// Unlock all hidden levels.
#define GD_MV_SET (MV_VISITED|MV_BEATEN)
for (i = 0; i < nummapheaders; i++)
{
if ((mapheaderinfo[i]->records.mapvisited & GD_MV_SET) == GD_MV_SET)
continue;
mapheaderinfo[i]->records.mapvisited |= GD_MV_SET;
success = true;
}
#undef GD_MV_SET
// Goofy, but this call needs to be before M_ClearMenus because that path
// calls G_LoadLevel, which will trigger a gamedata save. Garbage factory
if (success)
{
gamedata->gonerlevel = GDGONER_DONE;
G_SetUsedCheats();
}
M_ClearMenus(true);
@ -134,6 +148,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)
{
@ -156,6 +184,10 @@ static UINT8 cheatf_devmode(void)
mapheaderinfo[i]->records.mapvisited = MV_MAX;
}
gamedata->gonerlevel = GDGONER_DONE;
M_ClearMenus(true);
// This is a developer feature, you know how to delete ringdata
// G_SetUsedCheats();
S_StartSound(0, sfx_kc42);
@ -179,6 +211,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 +232,8 @@ cheatseq_t *cheatseqlist[] =
{
&cheat_warp,
&cheat_wrongwarp,
&cheat_savetheanimals,
&cheat_savetheframes,
#ifdef DEVELOP
&cheat_devmode,
#endif

View file

@ -48,6 +48,9 @@ unlockable_t unlockables[MAXUNLOCKABLES];
// Number of emblems
INT32 numemblems = 0;
// The challenge that will truly let the games begin.
UINT16 gamestartchallenge = 600; // 601
// Create a new gamedata_t, for start-up
void M_NewGameDataStruct(void)
{
@ -727,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
@ -3200,6 +3205,30 @@ UINT16 M_CompletionEmblems(void) // Bah! Duplication sucks, but it's for a separ
// Quick unlock checks
// -------------------
boolean M_GameTrulyStarted(void)
{
// Fail safe
if (gamedata == NULL)
return false;
// Not set
if (gamestartchallenge >= MAXUNLOCKABLES)
return true;
// An unfortunate sidestep, but sync is important.
if (netgame)
return true;
// Okay, we can check to see if this challenge has been achieved.
/*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)
{
if (unlockid >= MAXUNLOCKABLES

View file

@ -289,6 +289,17 @@ 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_OUTRO,
GDGONER_DONE,
} gdgoner_t;
typedef enum {
GDGT_RACE,
GDGT_BATTLE,
@ -370,6 +381,8 @@ struct gamedata_t
boolean finishedtutorialchallenge;
gdmusic_t musicstate;
UINT8 gonerlevel;
// BACKWARDS COMPAT ASSIST
boolean importprofilewins;
};
@ -435,9 +448,12 @@ void M_UpdateNextPrisonEggPickup(void);
UINT16 M_CheckLevelEmblems(void);
UINT16 M_CompletionEmblems(void);
extern UINT16 gamestartchallenge;
// Checking unlockable status
boolean M_CheckNetUnlockByID(UINT16 unlockid);
boolean M_SecretUnlocked(INT32 type, boolean local);
boolean M_GameTrulyStarted(void);
boolean M_CupLocked(cupheader_t *cup);
boolean M_CupSecondRowLocked(void);
boolean M_MapLocked(UINT16 mapnum);

View file

@ -6,6 +6,7 @@ target_sources(SRB2SDL2 PRIVATE
extras-statistics.c
extras-wrong.c
main-1.c
main-goner.cpp
main-profile-select.c
options-1.c
options-data-1.c

View file

@ -58,6 +58,7 @@ menu_t EXTRAS_MainDef = {
"EXTRAS",
28, 5,
M_DrawExtras,
M_DrawExtrasBack,
M_ExtrasTick,
NULL,
NULL,

View file

@ -27,6 +27,7 @@ menu_t MISC_AddonsDef = {
"EXTRAS",
0, 0,
M_DrawAddons,
M_DrawExtrasBack,
M_AddonsRefresh,
NULL,
NULL,

View file

@ -27,6 +27,7 @@ menu_t MISC_ChallengesDef = {
"UNLOCK",
98, 0,
M_DrawChallenges,
NULL,
M_ChallengesTick,
NULL,
NULL,
@ -46,6 +47,7 @@ menu_t MISC_StatisticsDef = {
"EXTRAS",
98, 0,
M_DrawStatistics,
M_DrawExtrasBack,
NULL,
NULL,
NULL,
@ -291,7 +293,8 @@ menu_t *M_InterruptMenuWithChallenges(menu_t *desiredmenu)
{
UINT16 newunlock;
if (Playing())
if (Playing() == true
|| M_GameTrulyStarted() == false)
return desiredmenu;
M_UpdateUnlockablesAndExtraEmblems(false, true);
@ -376,9 +379,8 @@ boolean M_CanKeyHiliTile(void)
UINT16 i = (challengesmenu.hilix * CHALLENGEGRIDHEIGHT) + challengesmenu.hiliy;
// Not a hinted tile OR a fresh board.
if (!(challengesmenu.extradata[i].flags & CHE_HINT)
&& (challengesmenu.unlockcount[CMC_UNLOCKED] > 0))
// Not a hinted tile.
if (!(challengesmenu.extradata[i].flags & CHE_HINT))
return false;
// Marked as major?

View file

@ -112,6 +112,7 @@ menu_t EXTRAS_EggTVDef =
M_DrawEggTV,
NULL,
NULL,
NULL,
M_QuitEggTV,
M_HandleEggTV
};

View file

@ -6,6 +6,8 @@
#include "../m_random.h"
#include "../music.h"
#include "../r_skins.h"
#include "../v_video.h"
#include "../z_zone.h"
struct wrongwarp_s wrongwarp;
@ -137,6 +139,87 @@ static boolean M_WrongWarpInputs(INT32 ch)
return false;
}
static INT32 M_WrongWarpFallingHelper(INT32 y, INT32 falltime)
{
if (wrongwarp.ticker < falltime)
{
return y;
}
if (wrongwarp.ticker > falltime + 2*TICRATE)
{
return INT32_MAX;
}
if (wrongwarp.ticker < falltime + TICRATE)
{
y += + ((wrongwarp.ticker - falltime) & 1 ? 1 : -1);
return y;
}
y += floor(pow(1.5, (double)(wrongwarp.ticker - (falltime + TICRATE))));
return y;
}
static void M_DrawWrongWarpBack(void)
{
INT32 x, y;
if (gamestate == GS_MENU)
{
patch_t *pat, *pat2;
INT32 animtimer, anim2 = 0;
pat = W_CachePatchName("TITLEBG1", PU_CACHE);
pat2 = W_CachePatchName("TITLEBG2", PU_CACHE);
animtimer = ((wrongwarp.ticker*5)/16) % SHORT(pat->width);
anim2 = SHORT(pat2->width) - (((wrongwarp.ticker*5)/16) % SHORT(pat2->width));
// SRB2Kart: F_DrawPatchCol is over-engineered; recoded to be less shitty and error-prone
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 0);
x = -((INT32)animtimer);
y = 0;
while (x < BASEVIDWIDTH)
{
V_DrawFixedPatch(x*FRACUNIT, y*FRACUNIT, FRACUNIT, 0, pat, NULL);
x += SHORT(pat->width);
}
x = -anim2;
y = BASEVIDHEIGHT - SHORT(pat2->height);
while (x < BASEVIDWIDTH)
{
V_DrawFixedPatch(x*FRACUNIT, y*FRACUNIT, FRACUNIT, 0, pat2, NULL);
x += SHORT(pat2->width);
}
}
{
patch_t *ttcheckers = W_CachePatchName("TTCHECK", PU_CACHE);
y = FixedMul(40<<FRACBITS, FixedDiv(wrongwarp.ticker%70, 70));
V_DrawSciencePatch(0, -y, 0, ttcheckers, FRACUNIT);
V_DrawSciencePatch(280<<FRACBITS, -(40<<FRACBITS) + y, 0, ttcheckers, FRACUNIT);
y = M_WrongWarpFallingHelper(36, 7*TICRATE/4);
if (y != INT32_MAX)
{
patch_t *ttbanner = W_CachePatchName("TTKBANNR", PU_CACHE);
V_DrawSmallScaledPatch(84, y, 0, ttbanner);
}
y = M_WrongWarpFallingHelper(87, 4*TICRATE/3);
if (y != INT32_MAX)
{
patch_t *ttkart = W_CachePatchName("TTKART", PU_CACHE);
V_DrawSmallScaledPatch(84, y, 0, ttkart);
}
}
}
menu_t MISC_WrongWarpDef = {
sizeof (MISC_WrongWarpMenu)/sizeof (menuitem_t),
NULL,
@ -144,10 +227,11 @@ menu_t MISC_WrongWarpDef = {
MISC_WrongWarpMenu,
0, 0,
0, 0,
MBF_SOUNDLESS,
MBF_SOUNDLESS|MBF_DRAWBGWHILEPLAYING,
".",
98, 0,
M_DrawWrongWarp,
M_DrawWrongWarpBack,
M_WrongWarpTick,
NULL,
NULL,

View file

@ -18,6 +18,7 @@
#include "../z_zone.h"
#include "../i_video.h" // I_FinishUpdate
#include "../i_system.h" // I_Sleep
#include "../m_cond.h" // M_GameTrulyStarted
menuitem_t MainMenu[] =
{
@ -79,8 +80,37 @@ void M_QuitSRB2(INT32 choice)
{
// We pick index 0 which is language sensitive, or one at random,
// between 1 and maximum number.
// ------------------------------------------------------------//
// ...no we don't! We haven't for ages!
// But I'm leaving that comment in, unmodified, because it dates
// ALL the way back to the original 1993 Doom source publication.
// One act of kindness has far-reaching consequences for so many
// people. It's a week until christmas as I'm writing this --
// for those who read this, what act of kindness can you bring
// to others? ~toast 181223
(void)choice;
M_StartMessage("Quit Game", "Are you sure you want to quit playing?\n", &M_QuitResponse, MM_YESNO, "Leave the game", "No, I want to go back!");
if (M_GameTrulyStarted())
{
M_StartMessage(
"Quit Game",
"Are you sure you want to quit playing?\n",
&M_QuitResponse, MM_YESNO,
"Leave the game",
"No, I want to go back!"
);
return;
}
M_StartMessage(
"Exit Program",
"Are you sure you want to quit?\n",
&M_QuitResponse, MM_YESNO,
"Yes",
"Cancel"
);
}
void M_QuitResponse(INT32 ch)

1330
src/menus/main-goner.cpp Normal file

File diff suppressed because it is too large Load diff

View file

@ -15,10 +15,11 @@ menu_t MAIN_ProfilesDef = {
MAIN_Profiles,
32, 80,
SKINCOLOR_ULTRAMARINE, 0,
0,
MBF_DRAWBGWHILEPLAYING,
"FILE",
2, 5,
M_DrawProfileSelect,
M_DrawOptionsCogs,
M_OptionsTick,
NULL,
NULL,

View file

@ -13,11 +13,11 @@ menuitem_t OPTIONS_Main[] =
{IT_STRING | IT_CALL, "Profile Setup", "Remap keys & buttons to your likings.",
NULL, {.routine = M_ProfileSelectInit}, 0, 0},
{IT_STRING | IT_SUBMENU, "Video Options", "Change video settings such as the resolution.",
NULL, {.submenu = &OPTIONS_VideoDef}, 0, 0},
{IT_STRING | IT_CALL, "Video Options", "Change video settings such as the resolution.",
NULL, {.routine = M_VideoOptions}, 0, 0},
{IT_STRING | IT_SUBMENU, "Sound Options", "Adjust various sound settings such as the volume.",
NULL, {.submenu = &OPTIONS_SoundDef}, 0, 0},
{IT_STRING | IT_CALL, "Sound Options", "Adjust various sound settings such as the volume.",
NULL, {.routine = M_SoundOptions}, 0, 0},
{IT_STRING | IT_SUBMENU, "HUD Options", "Options related to the Heads-Up Display.",
NULL, {.submenu = &OPTIONS_HUDDef}, 0, 0},
@ -45,10 +45,11 @@ menu_t OPTIONS_MainDef = {
OPTIONS_Main,
0, 0,
SKINCOLOR_SLATE, 0,
0,
MBF_DRAWBGWHILEPLAYING,
NULL,
2, 5,
M_DrawOptions,
M_DrawOptionsCogs,
M_OptionsTick,
NULL,
NULL,
@ -135,16 +136,22 @@ boolean M_OptionsQuit(void)
void M_OptionsTick(void)
{
optionsmenu.offset /= 2;
boolean instanttransmission = optionsmenu.ticker == 0 && menuwipe;
optionsmenu.ticker++;
optionsmenu.optx += (optionsmenu.toptx - optionsmenu.optx)/2;
optionsmenu.opty += (optionsmenu.topty - optionsmenu.opty)/2;
if (abs(optionsmenu.optx - optionsmenu.opty) < 2)
if (!instanttransmission)
{
optionsmenu.optx = optionsmenu.toptx;
optionsmenu.opty = optionsmenu.topty; // Avoid awkward 1 px errors.
optionsmenu.offset /= 2;
optionsmenu.optx += (optionsmenu.toptx - optionsmenu.optx)/2;
optionsmenu.opty += (optionsmenu.topty - optionsmenu.opty)/2;
if (abs(optionsmenu.optx - optionsmenu.opty) < 2)
{
optionsmenu.optx = optionsmenu.toptx;
optionsmenu.opty = optionsmenu.topty; // Avoid awkward 1 px errors.
}
}
// Move the button for cool animations
@ -177,13 +184,47 @@ void M_OptionsTick(void)
optionsmenu.fade--;
// change the colour if we aren't matching the current menu colour
if (optionsmenu.currcolour != currentMenu->extra1)
M_OptionsChangeBGColour(currentMenu->extra1);
if (instanttransmission)
{
optionsmenu.currcolour = currentMenu->extra1;
optionsmenu.offset = optionsmenu.fade = 0;
optionsmenu.optx = optionsmenu.toptx;
optionsmenu.opty = optionsmenu.topty;
}
else
{
if (optionsmenu.fade)
optionsmenu.fade--;
if (optionsmenu.currcolour != currentMenu->extra1)
M_OptionsChangeBGColour(currentMenu->extra1);
M_GonerCheckLooking();
}
// And one last giggle...
if (shitsfree)
shitsfree--;
}
static void M_OptionsMenuGoto(menu_t *assignment)
{
assignment->prevMenu = currentMenu;
M_SetupNextMenu(assignment, false);
}
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)
{

View file

@ -36,10 +36,11 @@ menu_t OPTIONS_DataDef = {
OPTIONS_Data,
48, 80,
SKINCOLOR_BLUEBERRY, 0,
0,
MBF_DRAWBGWHILEPLAYING,
NULL,
2, 5,
M_DrawGenericOptions,
M_DrawOptionsCogs,
M_OptionsTick,
NULL,
NULL,

View file

@ -37,10 +37,11 @@ menu_t OPTIONS_DataAddonDef = {
OPTIONS_DataAddon,
48, 80,
SKINCOLOR_BLUEBERRY, 0,
0,
MBF_DRAWBGWHILEPLAYING,
NULL,
2, 5,
M_DrawGenericOptions,
M_DrawOptionsCogs,
M_OptionsTick,
NULL,
NULL,

View file

@ -33,10 +33,11 @@ menu_t OPTIONS_DataDiscordDef = {
OPTIONS_DataDiscord,
48, 80,
SKINCOLOR_BLUEBERRY, 0,
0,
MBF_DRAWBGWHILEPLAYING,
NULL,
2, 5,
M_DrawGenericOptions,
M_DrawOptionsCogs,
M_OptionsTick,
NULL,
NULL,

View file

@ -40,10 +40,11 @@ menu_t OPTIONS_DataEraseDef = {
OPTIONS_DataErase,
48, 80,
SKINCOLOR_BLACK, 0,
0,
MBF_DRAWBGWHILEPLAYING,
"SHWDN2", // Danger.
2, 5,
M_DrawGenericOptions,
M_DrawOptionsCogs,
M_OptionsTick,
NULL,
NULL,

View file

@ -17,10 +17,11 @@ menu_t OPTIONS_DataProfileEraseDef = {
OPTIONS_DataProfileErase,
48, 80,
SKINCOLOR_BLACK, 0,
0,
MBF_DRAWBGWHILEPLAYING,
"SHWDN2", // Danger.
2, 5,
M_DrawProfileErase,
M_DrawOptionsCogs,
M_OptionsTick,
NULL,
NULL,

View file

@ -19,10 +19,11 @@ menu_t OPTIONS_DataReplayDef = {
OPTIONS_DataReplay,
48, 80,
SKINCOLOR_BLUEBERRY, 0,
0,
MBF_DRAWBGWHILEPLAYING,
NULL,
2, 5,
M_DrawGenericOptions,
M_DrawOptionsCogs,
M_OptionsTick,
NULL,
NULL,

View file

@ -35,10 +35,11 @@ menu_t OPTIONS_DataScreenshotDef = {
OPTIONS_DataScreenshot,
48, 80,
SKINCOLOR_BLUEBERRY, 0,
0,
MBF_DRAWBGWHILEPLAYING,
NULL,
2, 5,
M_DrawGenericOptions,
M_DrawOptionsCogs,
M_OptionsTick,
NULL,
NULL,

View file

@ -51,10 +51,11 @@ menu_t OPTIONS_GameplayDef = {
OPTIONS_Gameplay,
48, 80,
SKINCOLOR_SCARLET, 0,
0,
MBF_DRAWBGWHILEPLAYING,
NULL,
2, 5,
M_DrawGenericOptions,
M_DrawOptionsCogs,
M_OptionsTick,
NULL,
NULL,

View file

@ -55,10 +55,11 @@ menu_t OPTIONS_GameplayItemsDef = {
OPTIONS_GameplayItems,
14, 40,
SKINCOLOR_SCARLET, 0,
0,
MBF_DRAWBGWHILEPLAYING,
NULL,
2, 5,
M_DrawItemToggles,
M_DrawOptionsCogs,
M_OptionsTick,
NULL,
NULL,

View file

@ -4,7 +4,6 @@
#include "../k_menu.h"
#include "../r_main.h" // cv_showhud
#include "../v_video.h" // cv_constextsize
#include "../console.h" // console cvars
menuitem_t OPTIONS_HUD[] =
{
@ -21,12 +20,15 @@ menuitem_t OPTIONS_HUD[] =
{IT_SPACE | IT_NOTHING, NULL, NULL,
NULL, {NULL}, 0, 0},
/* -- Nah, console isn't even bound by default, if you know how to use it you can change the size there
{IT_STRING | IT_CVAR, "Console Text Size", "Size of the text within the console.",
NULL, {.cvar = &cv_constextsize}, 0, 0},
NULL, {.cvar = &cv_constextsize}, 0, 0},*/
// we spell words properly here.
{IT_STRING | IT_CVAR, "Console Tint", "Change the background colour of the console.",
NULL, {.cvar = &cons_backcolor}, 0, 0},
{IT_STRING | IT_CVAR, "Show FPS", "Displays the game framerate at the lower right corner of the screen.",
NULL, {.cvar = &cv_ticrate}, 0, 0},
{IT_STRING | IT_CVAR, "Show Input Delay", "Displays your input delay at the lower right corner of the screen.",
NULL, {.cvar = &cv_showping}, 0, 0},
{IT_STRING | IT_CVAR, "Show \"FOCUS LOST\"", "Displays \"FOCUS LOST\" when the game window isn't the active window.",
NULL, {.cvar = &cv_showfocuslost}, 0, 0},
@ -34,7 +36,7 @@ menuitem_t OPTIONS_HUD[] =
{IT_SPACE | IT_NOTHING, NULL, NULL,
NULL, {NULL}, 0, 0},
{IT_STRING | IT_SUBMENU, "Online HUD Options...", "HUD options related to the online chat box and other features.",
{IT_STRING | IT_SUBMENU, "Online Chat Options...", "HUD options related to the online chat box.",
NULL, {.submenu = &OPTIONS_HUDOnlineDef}, 0, 0},
};
@ -45,10 +47,11 @@ menu_t OPTIONS_HUDDef = {
OPTIONS_HUD,
48, 80,
SKINCOLOR_SUNSLAM, 0,
0,
MBF_DRAWBGWHILEPLAYING,
NULL,
2, 5,
M_DrawGenericOptions,
M_DrawOptionsCogs,
M_OptionsTick,
NULL,
NULL,

View file

@ -2,6 +2,7 @@
/// \brief Online HUD Options
#include "../k_menu.h"
#include "../console.h" // console cvars
menuitem_t OPTIONS_HUDOnline[] =
{
@ -12,29 +13,23 @@ menuitem_t OPTIONS_HUDOnline[] =
{IT_SPACE | IT_NOTHING, NULL, NULL,
NULL, {NULL}, 0, 0},
{IT_STRING | IT_CVAR, "Chat Box Tint", "Changes the background colour of the chat box.",
NULL, {.cvar = &cv_chatbacktint}, 0, 0},
{IT_STRING | IT_CVAR, "Chat Box Tint", "Change the background color of the chat box.",
NULL, {.cvar = &cons_backcolor}, 0, 0},
{IT_STRING | IT_CVAR | IT_CV_SLIDER, "Chat Box Width", "Change the width of the Chat Box",
{IT_STRING | IT_CVAR | IT_CV_SLIDER, "Chat Box Width", "Change the width of the Chat Box.",
NULL, {.cvar = &cv_chatwidth}, 0, 0},
{IT_STRING | IT_CVAR | IT_CV_SLIDER, "Chat Box Height", "Change the height of the Chat Box",
{IT_STRING | IT_CVAR | IT_CV_SLIDER, "Chat Box Height", "Change the height of the Chat Box.",
NULL, {.cvar = &cv_chatheight}, 0, 0},
{IT_SPACE | IT_NOTHING, NULL, NULL,
NULL, {NULL}, 0, 0},
{IT_STRING | IT_CVAR, "Message Fadeout Time", "How long chat messages stay displayed with the chat closed.",
{IT_STRING | IT_CVAR, "Message Fadeout Time (s)", "How long chat messages stay displayed with the chat closed.",
NULL, {.cvar = &cv_chattime}, 0, 0},
{IT_STRING | IT_CVAR, "Spam Protection", "Prevents too many message from a single player from being displayed.",
NULL, {.cvar = &cv_chatspamprotection}, 0, 0},
{IT_SPACE | IT_NOTHING, NULL, NULL,
NULL, {NULL}, 0, 0},
{IT_STRING | IT_CVAR, "Local Ping Display", "In netgames, displays your ping at the lower right corner of the screen.",
NULL, {.cvar = &cv_showping}, 0, 0},
{IT_STRING | IT_CVAR, "Message Tint", "Shows the tint for new chat messages when the box is closed.",
NULL, {.cvar = &cv_chatbacktint}, 0, 0},
};
@ -45,10 +40,11 @@ menu_t OPTIONS_HUDOnlineDef = {
OPTIONS_HUDOnline,
48, 80,
SKINCOLOR_SUNSLAM, 0,
0,
MBF_DRAWBGWHILEPLAYING,
NULL,
2, 5,
M_DrawGenericOptions,
M_DrawOptionsCogs,
M_OptionsTick,
NULL,
NULL,

View file

@ -17,10 +17,11 @@ menu_t OPTIONS_ProfilesDef = {
OPTIONS_Profiles,
32, 80,
SKINCOLOR_ULTRAMARINE, 0,
0,
MBF_DRAWBGWHILEPLAYING,
"FILE",
2, 5,
M_DrawProfileSelect,
M_DrawOptionsCogs,
M_OptionsTick,
NULL,
NULL,
@ -46,8 +47,7 @@ void M_FirstPickProfile(INT32 c)
PR_ApplyProfile(optionsmenu.profilen, 0);
if (restoreMenu == NULL)
restoreMenu = &MainDef;
M_ValidateRestoreMenu();
M_SetupNextMenu(M_SpecificMenuRestore(M_InterruptMenuWithChallenges(restoreMenu)), false);
restoreMenu = NULL;
@ -61,7 +61,7 @@ void M_FirstPickProfile(INT32 c)
}
// Start menu edition. Call this with MA_YES if not used with a textbox.
static void M_StartEditProfile(INT32 c)
void M_StartEditProfile(INT32 c)
{
const INT32 maxp = PR_GetNumProfiles();
@ -114,6 +114,7 @@ static void M_StartEditProfile(INT32 c)
OPTIONS_EditProfile[popt_char].status |= IT_TRANSTEXT;
}
OPTIONS_EditProfileDef.prevMenu = currentMenu;
M_SetupNextMenu(&OPTIONS_EditProfileDef, false);
return;
}

View file

@ -3,22 +3,25 @@
#include "../k_menu.h"
#include "../s_sound.h"
#include "../m_cond.h"
// These are placed in descending order next to the things they modify, for clarity.
// Try to keep the mvar2 in order, if you add new profile info!!
menuitem_t OPTIONS_EditProfile[] = {
{IT_STRING | IT_CVAR | IT_CV_STRING, "Profile Name", "6-character long name to identify this Profile.",
NULL, {.cvar = &cv_dummyprofilename}, 0, 0},
{IT_STRING | IT_CVAR | IT_CV_STRING, "Player Name", "Name displayed online when using this Profile.",
NULL, {.cvar = &cv_dummyprofileplayername}, 0, 0},
{IT_STRING | IT_CALL, "Character", "Default character and color for this Profile.",
NULL, {.routine = M_CharacterSelect}, 0, 0},
{IT_STRING | IT_CVAR | IT_CV_STRING, "Profile ID", "6-character long name to identify this Profile.",
NULL, {.cvar = &cv_dummyprofilename}, 0, 41},
{IT_STRING | IT_CALL, "Controls", "Select the button mappings for this Profile.",
NULL, {.routine = M_ProfileDeviceSelect}, 0, 0},
NULL, {.routine = M_ProfileDeviceSelect}, 0, 81},
{IT_STRING | IT_CALL, "Character", "Default character and color for this Profile.",
NULL, {.routine = M_CharacterSelect}, 0, 101},
{IT_STRING | IT_CVAR | IT_CV_STRING, "Player Tag", "Name displayed online when using this Profile.",
NULL, {.cvar = &cv_dummyprofileplayername}, 0, 141},
{IT_STRING | IT_CALL, "Confirm", "Confirm changes.",
NULL, {.routine = M_ConfirmProfile}, 0, 0},
NULL, {.routine = M_ConfirmProfile}, 0, 171},
};
@ -29,10 +32,11 @@ menu_t OPTIONS_EditProfileDef = {
OPTIONS_EditProfile,
32, 80,
SKINCOLOR_ULTRAMARINE, 0,
0,
MBF_DRAWBGWHILEPLAYING,
"FILE",
2, 5,
M_DrawEditProfile,
M_DrawOptionsCogs,
M_HandleProfileEdit,
NULL,
NULL,
@ -76,9 +80,17 @@ static boolean M_ProfileEditEnd(const UINT8 pid)
static void M_ProfileEditExit(void)
{
optionsmenu.toptx = 160;
optionsmenu.topty = 35;
optionsmenu.resetprofile = true; // Reset profile after the transition is done.
if (M_GameTrulyStarted() == true)
{
optionsmenu.toptx = 160;
optionsmenu.topty = 35;
optionsmenu.resetprofile = true; // Reset profile after the transition is done.
}
else
{
M_ResetOptions(); // Reset all options variables otherwise things are gonna go reaaal bad lol.
optionsmenu.profile = NULL; // Make sure to get rid of that, too.
}
PR_SaveProfiles(); // save profiles after we do that.
}
@ -116,10 +128,10 @@ boolean M_ProfileEditInputs(INT32 ch)
void M_HandleProfileEdit(void)
{
// Always copy the profile name and player name in the profile.
if (optionsmenu.profile)
if (optionsmenu.profile && !menutyping.active)
{
// Copy the first 6 chars for profile name
if (strlen(cv_dummyprofilename.string))
if (cv_dummyprofilename.string[0])
{
char *s;
// convert dummyprofilename to uppercase
@ -132,8 +144,10 @@ void M_HandleProfileEdit(void)
}
}
if (strlen(cv_dummyprofileplayername.string))
if (cv_dummyprofileplayername.string[0])
{
strncpy(optionsmenu.profile->playername, cv_dummyprofileplayername.string, MAXPLAYERNAME);
}
}
M_OptionsTick(); // Has to be afterwards because this can unset optionsmenu.profile

View file

@ -114,10 +114,11 @@ menu_t OPTIONS_ProfileControlsDef = {
OPTIONS_ProfileControls,
32, 80,
SKINCOLOR_ULTRAMARINE, 0,
0,
MBF_DRAWBGWHILEPLAYING,
"FILE",
3, 5,
M_DrawProfileControls,
M_DrawOptionsCogs,
M_HandleProfileControls,
NULL,
NULL,

View file

@ -40,6 +40,9 @@ menuitem_t OPTIONS_Server[] =
{IT_STRING | IT_CVAR, "Mute Chat", "Prevents non-admins from sending chat messages.",
NULL, {.cvar = &cv_mute}, 0, 0},
{IT_STRING | IT_CVAR, "Chat Spam Protection", "Prevents too many message from a single player.",
NULL, {.cvar = &cv_chatspamprotection}, 0, 0},
{IT_SPACE | IT_NOTHING, NULL, NULL,
NULL, {NULL}, 0, 0},
@ -55,10 +58,11 @@ menu_t OPTIONS_ServerDef = {
OPTIONS_Server,
48, 70, // This menu here is slightly higher because there's a lot of options...
SKINCOLOR_VIOLET, 0,
0,
MBF_DRAWBGWHILEPLAYING,
NULL,
2, 5,
M_DrawGenericOptions,
M_DrawOptionsCogs,
M_OptionsTick,
NULL,
NULL,

View file

@ -53,10 +53,11 @@ menu_t OPTIONS_ServerAdvancedDef = {
OPTIONS_ServerAdvanced,
48, 70, // This menu here is slightly higher because there's a lot of options...
SKINCOLOR_VIOLET, 0,
0,
MBF_DRAWBGWHILEPLAYING,
NULL,
2, 5,
M_DrawGenericOptions,
M_DrawOptionsCogs,
M_OptionsTick,
NULL,
NULL,

View file

@ -57,10 +57,11 @@ menu_t OPTIONS_SoundDef = {
OPTIONS_Sound,
48, 80,
SKINCOLOR_THUNDER, 0,
0,
MBF_DRAWBGWHILEPLAYING,
NULL,
2, 5,
M_DrawGenericOptions,
M_DrawOptionsCogs,
M_OptionsTick,
NULL,
NULL,

View file

@ -13,27 +13,31 @@ menuitem_t OPTIONS_Video[] =
{IT_STRING | IT_CALL, "Set Resolution...", "Change the screen resolution for the game.",
NULL, {.routine = M_VideoModeMenu}, 0, 0},
// A check to see if you're not running on a fucking antique potato powered stone i guess???????
#if (defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL)
{IT_STRING | IT_CVAR, "Fullscreen", "Set whether you want to use fullscreen or windowed mode.",
NULL, {.cvar = &cv_fullscreen}, 0, 0},
#endif
{IT_STRING | IT_CVAR, "Vertical Sync", "Works with your screen to reduce image tearing and judder.",
NULL, {.cvar = &cv_vidwait}, 0, 0},
{IT_NOTHING|IT_SPACE, NULL, "Kanade best waifu! I promise!",
NULL, {NULL}, 0, 0},
// Everytime I see a screenshot at max gamma I die inside
{IT_STRING | IT_CVAR | IT_CV_SLIDER, "Gamma", "Adjusts the overall brightness of the game.",
NULL, {.cvar = &cv_globalgamma}, 0, 0},
{IT_STRING | IT_CVAR, "FPS Cap", "Handles the frame rate of the game (35 to match game logic)",
NULL, {.cvar = &cv_fpscap}, 0, 0},
{IT_STRING | IT_CVAR, "Enable Skyboxes", "Turning this off will improve performance at the detriment of visuals for many maps.",
NULL, {.cvar = &cv_skybox}, 0, 0},
{IT_NOTHING|IT_SPACE, NULL, NULL,
NULL, {NULL}, 0, 0},
{IT_STRING | IT_CVAR, "Screen Tilting", "The view rotatation on inclines can be disabled to reduce motion sickness.",
NULL, {.cvar = &cv_tilting}, 0, 0},
{IT_STRING | IT_CVAR, "Reduce Visual Effects", "If on, some less-important particle cues will be hidden.",
NULL, {.cvar = &cv_reducevfx}, 0, 0},
{IT_STRING | IT_CVAR | IT_CV_SLIDER, "Gamma", "Adjusts the overall brightness of the game.",
NULL, {.cvar = &cv_globalgamma}, 0, 0},
{IT_NOTHING|IT_SPACE, NULL, NULL,
NULL, {NULL}, 0, 0},
{IT_STRING | IT_CVAR, "Draw Distance", "How far objects can be drawn. A tradeoff between performance & visibility.",
NULL, {.cvar = &cv_drawdist}, 0, 0},
@ -41,13 +45,13 @@ menuitem_t OPTIONS_Video[] =
{IT_STRING | IT_CVAR, "Weather Draw Distance", "Affects how far weather visuals can be drawn. Lower values improve performance.",
NULL, {.cvar = &cv_drawdist_precip}, 0, 0},
{IT_STRING | IT_CVAR, "Show FPS", "Displays the game framerate at the lower right corner of the screen.",
NULL, {.cvar = &cv_ticrate}, 0, 0},
{IT_NOTHING|IT_SPACE, NULL, "Kanade best waifu! I promise!",
NULL, {NULL}, 0, 0},
{IT_STRING | IT_CVAR, "Enable Skyboxes", "Turning this off may improve performance, but reduces courses' background details.",
NULL, {.cvar = &cv_skybox}, 0, 0},
#ifdef HWRENDER
{IT_NOTHING|IT_SPACE, NULL, NULL,
NULL, {NULL}, 0, 0},
{IT_STRING | IT_SUBMENU, "Hardware Options...", "For usage and configuration of the OpenGL renderer.",
NULL, {.submenu = &OPTIONS_VideoOGLDef}, 0, 0},
#endif
@ -59,12 +63,13 @@ menu_t OPTIONS_VideoDef = {
&OPTIONS_MainDef,
0,
OPTIONS_Video,
32, 80,
32, 80-8,
SKINCOLOR_PLAGUE, 0,
0,
MBF_DRAWBGWHILEPLAYING,
NULL,
2, 5,
M_DrawGenericOptions,
M_DrawOptionsCogs,
M_OptionsTick,
NULL,
NULL,

View file

@ -53,10 +53,11 @@ menu_t OPTIONS_VideoOGLDef = {
OPTIONS_VideoOGL,
32, 80,
SKINCOLOR_PLAGUE, 0,
0,
MBF_DRAWBGWHILEPLAYING,
NULL,
2, 5,
M_DrawGenericOptions,
M_DrawOptionsCogs,
M_OptionsTick,
NULL,
NULL,

View file

@ -19,10 +19,11 @@ menu_t OPTIONS_VideoModesDef = {
OPTIONS_VideoModes,
48, 80,
SKINCOLOR_PLAGUE, 0,
0,
MBF_DRAWBGWHILEPLAYING,
NULL,
2, 5,
M_DrawVideoModes,
M_DrawOptionsCogs,
M_OptionsTick,
NULL,
NULL,

View file

@ -16,17 +16,30 @@ menuitem_t PLAY_CharSelect[] =
{IT_NOTHING, NULL, NULL, NULL, {NULL}, 0, 0},
};
static void M_DrawCharacterBack(void)
{
if (!optionsmenu.profile)
{
if (gamestate == GS_MENU)
M_DrawMenuBackground();
return;
}
M_DrawOptionsCogs();
}
menu_t PLAY_CharSelectDef = {
sizeof (PLAY_CharSelect) / sizeof (menuitem_t),
&MainDef,
0,
PLAY_CharSelect,
0, 0,
0, 0,
SKINCOLOR_ULTRAMARINE, 0,
0,
NULL,
0, 0,
2, 5, // matches OPTIONS_EditProfileDef
M_DrawCharacterSelect,
M_DrawCharacterBack,
M_CharacterSelectTick,
M_CharacterSelectInit,
M_CharacterSelectQuit,
@ -1409,6 +1422,9 @@ void M_CharacterSelectTick(void)
M_MPConfirmCharacterSelection();
}
}
if (optionsmenu.profile)
M_OptionsTick();
}
boolean M_CharacterSelectQuit(void)

View file

@ -46,6 +46,7 @@ menu_t PLAY_RaceDifficultyDef = {
NULL,
NULL,
NULL,
NULL,
NULL
};

View file

@ -76,6 +76,7 @@ menu_t PLAY_TimeAttackDef = {
NULL,
2, 5,
M_DrawTimeAttack,
NULL,
M_TimeAttackTick,
NULL,
NULL,
@ -120,6 +121,7 @@ menu_t PLAY_TAReplayDef = {
2, 5,
M_DrawTimeAttack,
NULL,
M_TimeAttackTick,
NULL,
NULL,
NULL
@ -165,6 +167,7 @@ menu_t PLAY_TAReplayGuestDef = {
2, 5,
M_DrawTimeAttack,
NULL,
M_TimeAttackTick,
NULL,
NULL,
NULL
@ -205,6 +208,7 @@ menu_t PLAY_TAGhostsDef = {
2, 5,
M_DrawTimeAttack,
NULL,
M_TimeAttackTick,
NULL,
NULL,
NULL
@ -215,6 +219,8 @@ void M_PrepareTimeAttack(INT32 choice)
{
(void) choice;
timeattackmenu.ticker = 0;
// Gametype guess
if (levellist.guessgt != MAXGAMETYPES)
{

View file

@ -103,6 +103,7 @@ menu_t PLAY_MP_OptSelectDef = {
"NETMD2",
-1, 1,
M_DrawMPOptSelect,
M_DrawEggaChannel,
M_MPOptSelectTick,
NULL,
NULL,

View file

@ -39,6 +39,7 @@ menu_t PLAY_MP_HostDef = {
"NETMD2",
-1, 1, // 1 frame transition.... This is really just because I don't want the black fade when we press esc, hehe
M_DrawMPHost,
M_DrawEggaChannel,
M_MPOptSelectTick, // This handles the unfolding options
NULL,
M_MPResetOpts,

View file

@ -19,7 +19,7 @@ menuitem_t PLAY_MP_JoinIP[] =
{IT_STRING, "CONNECT ", "Attempt to connect to the server you entered the IP for.",
NULL, {NULL}, 0, 0},
{IT_STRING | IT_SPACE, "LAST IPs JOINED:", "Kanade best waifu :)",
{IT_STRING | IT_SPACE, "LAST IPs JOINED:", NULL,
NULL, {NULL}, 0, 0},
{IT_STRING, "servip1", "The last 3 IPs you've succesfully joined are displayed here.",
@ -44,6 +44,7 @@ menu_t PLAY_MP_JoinIPDef = {
"NETMD2",
-1, 1, // 1 frame transition.... This is really just because I don't want the black fade when we press esc, hehe
M_DrawMPJoinIP,
M_DrawEggaChannel,
M_MPOptSelectTick, // This handles the unfolding options
NULL,
M_MPResetOpts,

View file

@ -21,6 +21,7 @@ menu_t PLAY_MP_RoomSelectDef = {
"NETMD2",
0, 0,
M_DrawMPRoomSelect,
M_DrawEggaChannel,
M_MPRoomSelectTick,
NULL,
NULL,

View file

@ -43,6 +43,7 @@ menu_t PLAY_MP_ServerBrowserDef = {
"NETMD2",
0, 0,
M_DrawMPServerBrowser,
NULL,
M_MPServerBrowserTick,
NULL,
M_ServerBrowserQuit,

View file

@ -27,6 +27,7 @@ menu_t PLAY_CupSelectDef = {
NULL,
2, 5,
M_DrawCupSelect,
NULL,
M_CupSelectTick,
NULL,
NULL,
@ -275,11 +276,13 @@ void M_CupSelectHandler(INT32 choice)
}
else if (count == 1 && levellist.levelsearch.timeattack == true)
{
PLAY_TimeAttackDef.transitionID = currentMenu->transitionID+1;
currentMenu->transitionID = PLAY_TimeAttackDef.transitionID+1;
M_LevelSelected(0);
}
else
{
currentMenu->transitionID = PLAY_LevelSelectDef.transitionID;
// Keep cursor position if you select the same cup again, reset if it's a different cup
if (oldcup != newcup || levellist.cursor >= count)
{

View file

@ -84,6 +84,7 @@ menu_t MISC_DiscordRequestsDef = {
NULL,
0, 0,
M_DrawDiscordRequests,
NULL,
M_DiscordRequestTick,
NULL,
NULL,

View file

@ -29,6 +29,7 @@ menu_t PLAY_LevelSelectDef = {
NULL,
2, 5,
M_DrawLevelSelect,
NULL,
M_LevelSelectTick,
NULL,
NULL,
@ -281,13 +282,40 @@ boolean M_LevelListFromGametype(INT16 gt)
CV_SetValue(&cv_dummyspbattack, 0);
}
PLAY_CupSelectDef.music = \
PLAY_LevelSelectDef.music = \
PLAY_TimeAttackDef.music = \
currentMenu->music;
if (gamestate == GS_MENU)
{
const char *music;
void (*bgroutine)(void);
if (gt == GT_SPECIAL)
{
music = "SSTAR3";
bgroutine = M_DrawSealedBack;
}
else
{
music = currentMenu->music;
bgroutine = currentMenu->bgroutine;
}
menu_t *remap_menus[] = {
&PLAY_CupSelectDef,
&PLAY_LevelSelectDef,
&PLAY_TimeAttackDef,
&PLAY_TAReplayDef,
&PLAY_TAReplayGuestDef,
&PLAY_TAGhostsDef,
NULL
};
size_t i;
for (i = 0; remap_menus[i]; i++)
{
remap_menus[i]->music = music;
remap_menus[i]->bgroutine = bgroutine;
}
// Not for the time attack ones
PLAY_CupSelectDef.menuitems[0].patch = \
PLAY_LevelSelectDef.menuitems[0].patch = \
currentMenu->menuitems[itemOn].patch;
@ -299,6 +327,8 @@ boolean M_LevelListFromGametype(INT16 gt)
if (levellist.levelsearch.cupmode)
{
PLAY_CupSelectDef.transitionID = PLAY_LevelSelectDef.transitionID;
const boolean secondrowlocked = M_CupSecondRowLocked();
if (cupgrid.cache_secondrowlocked != secondrowlocked)
{
@ -556,10 +586,14 @@ boolean M_LevelListFromGametype(INT16 gt)
possiblecursor++;
}
if (test != NEXTMAP_INVALID)
if (test < nummapheaders)
{
levellist.cursor = possiblecursor;
invalidatedcursor = false;
}
}
else if (invalidatedcursor)
if (invalidatedcursor)
{
levellist.cursor = 0;
}
@ -569,8 +603,15 @@ boolean M_LevelListFromGametype(INT16 gt)
if (gt != -1)
{
PLAY_LevelSelectDef.prevMenu = currentMenu;
M_SetupNextMenu(&PLAY_LevelSelectDef, false);
if (levellist.levelsearch.tutorial && levellist.mapcount == 1)
{
M_LevelSelected(0); // Skip the list!
}
else
{
PLAY_LevelSelectDef.prevMenu = currentMenu;
M_SetupNextMenu(&PLAY_LevelSelectDef, false);
}
}
return true;
@ -707,7 +748,8 @@ void M_LevelSelected(INT16 add)
D_MapChange(levellist.choosemap+1, levellist.newgametype, (cv_kartencore.value == 1), 1, 1, false, false);
if (levellist.levelsearch.tutorial)
if (!M_GameTrulyStarted() ||
levellist.levelsearch.tutorial)
{
restoreMenu = currentMenu;
}
@ -763,8 +805,6 @@ void M_LevelSelectHandler(INT32 choice)
if (M_MenuConfirmPressed(pid) /*|| M_MenuButtonPressed(pid, MBT_START)*/)
{
M_SetMenuDelay(pid);
PLAY_TimeAttackDef.transitionID = currentMenu->transitionID;
M_LevelSelected(levellist.cursor);
}
else if (M_MenuBackPressed(pid))

View file

@ -231,6 +231,7 @@ menu_t PAUSE_CheatsDef = {
0, 0,
draw_menu,
nullptr,
nullptr,
menu_open,
menu_close,
menu_input,

View file

@ -89,6 +89,7 @@ menu_t PAUSE_MainDef = {
NULL,
1, 10, // For transition with some menus!
M_DrawPause,
NULL,
M_PauseTick,
NULL,
NULL,
@ -503,5 +504,12 @@ void M_EndGame(INT32 choice)
if (!Playing())
return;
if (M_GameTrulyStarted() == false)
{
// No returning to the title screen.
M_QuitSRB2(-1);
return;
}
M_StartMessage("Return to Menu", M_GetText("Are you sure you want to\nreturn to the menu?\n"), &M_ExitGameResponse, MM_YESNO, NULL, NULL);
}

View file

@ -120,6 +120,7 @@ menu_t PAUSE_KickHandlerDef = {
NULL,
0, 0,
M_DrawKickHandler,
NULL,
M_KickHandlerTick,
NULL,
NULL,

View file

@ -43,6 +43,7 @@ menu_t PAUSE_PlaybackMenuDef = {
NULL,
0, 0,
M_DrawPlaybackMenu,
NULL,
M_PlaybackTick,
NULL,
NULL,

View file

@ -208,6 +208,7 @@ menu_t MISC_SoundTestDef = {
".",
98, 0,
M_DrawSoundTest,
M_DrawExtrasBack,
M_SoundTestTick,
NULL,
NULL,

View file

@ -74,6 +74,36 @@ enum
#define spb_owner(o) ((o)->target)
#define spb_chase(o) ((o)->tracer)
void Obj_SPBEradicateCapsules(void)
{
thinker_t *think;
mobj_t *mo;
// Expensive operation :D?
for (think = thlist[THINK_MOBJ].next; think != &thlist[THINK_MOBJ]; think = think->next)
{
if (think->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo = (mobj_t *)think;
if (mo->type != MT_ITEMCAPSULE)
continue;
if (!mo->health || mo->fuse)
continue;
P_KillMobj(mo, NULL, NULL, DMG_NORMAL);
}
}
void Obj_SPBThrown(mobj_t *spb, fixed_t finalspeed)
{
spb_speed(spb) = finalspeed;
Obj_SPBEradicateCapsules();
}
static void SPBMantaRings(mobj_t *spb)
{
fixed_t vScale = INT32_MAX;

View file

@ -289,7 +289,7 @@ static void P_ItemPop(mobj_t *actor)
*/
// Here at mapload in battle?
if (!(gametyperules & GTR_CIRCUIT) && (actor->flags2 & MF2_BOSSFLEE))
if (gametype != GT_TUTORIAL && !(gametyperules & GTR_CIRCUIT) && (actor->flags2 & MF2_BOSSFLEE))
{
numgotboxes++;
@ -2041,8 +2041,12 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
INT16 spacing = (target->radius >> 1) / target->scale;
// set respawn fuse
if (damagetype == DMG_INSTAKILL || K_CapsuleTimeAttackRules() == true) // no respawns
;
if (damagetype == DMG_INSTAKILL)
; // Don't respawn (external)
else if (gametype == GT_TUTORIAL)
target->fuse = 5*TICRATE;
else if (K_CapsuleTimeAttackRules() == true)
; // Don't respawn (internal)
else if (target->threshold == KITEM_SUPERRING)
target->fuse = 20*TICRATE;
else

View file

@ -10474,6 +10474,14 @@ static boolean P_FuseThink(mobj_t *mobj)
return false;
case MT_ITEMCAPSULE:
if (mobj->threshold == KITEM_SPB && K_IsSPBInGame())
{
// SPB is in play. Try again in a short bit.
mobj->fuse += TICRATE/2;
return true;
}
if (mobj->spawnpoint)
P_SpawnMapThing(mobj->spawnpoint);
else
@ -12549,8 +12557,8 @@ void P_RespawnBattleBoxes(void)
{
thinker_t *th;
if (gametyperules & GTR_CIRCUIT)
return;
/*if (gametyperules & GTR_CIRCUIT) -- already guarding the call
return;*/
tic_t setduration = (nummapboxes > 1) ? TICRATE : (2*TICRATE);

View file

@ -7847,8 +7847,7 @@ static void P_InitCamera(void)
static void P_InitPlayers(void)
{
UINT8 i;
INT32 skin = -1;
INT32 i, skin = -1, follower = -1;
// Make sure objectplace is OFF when you first start the level!
OP_ResetObjectplace();
@ -7871,6 +7870,18 @@ static void P_InitPlayers(void)
{
skin = 0;
}
if (netgame)
; // shouldn't happen but at least attempt to sync if it does
else for (i = 0; i < numfollowers; i++)
{
if (followers[i].hornsound != sfx_melody)
continue;
if (K_FollowerUsable(i))
follower = i;
break;
}
}
for (i = 0; i < MAXPLAYERS; i++)
@ -7885,8 +7896,10 @@ static void P_InitPlayers(void)
{
players[i].skin = skin;
players[i].skincolor = skins[skin].prefcolor;
players[i].followerskin = -1;
// followercolor can be left alone for hopefully obvious reasons
players[i].followerskin = follower;
if (follower != -1)
players[i].followercolor = followers[follower].defaultcolor;
}
G_SpawnPlayer(i);
@ -7956,7 +7969,7 @@ static void P_InitGametype(void)
G_RecordDemo(buf);
}
if (gamestate != GS_TITLESCREEN)
if (gamestate != GS_TITLESCREEN && M_GameTrulyStarted())
{
// Started a game? Move on to the next jam when you go back to the title screen
// this permits all but titlescreen, instead of only GS_LEVEL

View file

@ -118,7 +118,7 @@ patch_t** get_button_patch(Draw::Button type, int ver)
}; // namespace
void Chain::button(Button type, int ver, std::optional<bool> press) const
void Chain::button_(Button type, int ver, std::optional<bool> press) const
{
const auto _ = Clipper(*this);

View file

@ -163,8 +163,8 @@ public:
void fill(UINT8 color) const;
void button(Button type, std::optional<bool> press = {}) const { button(type, 0, press); }
void small_button(Button type, std::optional<bool> press = {}) const { button(type, 1, press); }
void button(Button type, std::optional<bool> press = {}) const { button_(type, 0, press); }
void small_button(Button type, std::optional<bool> press = {}) const { button_(type, 1, press); }
private:
constexpr Chain() {}
@ -198,7 +198,7 @@ public:
const UINT8* colormap_ = nullptr;
void string(const char* str, INT32 flags, Font font) const;
void button(Button type, int ver, std::optional<bool> press = {}) const;
void button_(Button type, int ver, std::optional<bool> press = {}) const;
friend Draw;
};

View file

@ -28,6 +28,7 @@
#include "r_draw.h"
#include "console.h"
#include "r_fps.h"
#include "k_dialogue.h" // K_GetDialogueSlide
#include "i_video.h" // rendermode
#include "z_zone.h"
@ -516,18 +517,26 @@ void V_AdjustXYWithSnap(INT32 *x, INT32 *y, UINT32 options, INT32 dupx, INT32 du
INT32 baseheight = BASEVIDHEIGHT * dupy;
SINT8 player = R_GetViewNumber();
if (options & V_SPLITSCREEN)
if (r_splitscreen > 0)
{
if (r_splitscreen > 0)
if (options & V_SPLITSCREEN)
{
screenheight /= 2;
baseheight /= 2;
}
if (r_splitscreen > 1)
if (r_splitscreen > 1)
{
screenwidth /= 2;
basewidth /= 2;
}
}
}
else if ((options & (V_SLIDEIN|V_SNAPTOBOTTOM)) == (V_SLIDEIN|V_SNAPTOBOTTOM))
{
INT32 slide = K_GetDialogueSlide(51 * FRACUNIT);
if (slide)
{
screenwidth /= 2;
basewidth /= 2;
*y -= FixedMul(slide, dupy);
}
}