From 6ae7f1f64f52214e292dc5d119aa33e4836c4e6d Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 4 Jun 2023 12:44:17 +0100 Subject: [PATCH 01/34] Y_PlayerStandingsDrawer: Fix showing invalid data increase text on tab rankings after an SP intermission --- src/y_inter.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/y_inter.c b/src/y_inter.c index 7e24b28a2..fa5286c64 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -449,7 +449,7 @@ void Y_PlayerStandingsDrawer(y_data_t *standings, INT32 xoffset) patch_t *resbar = W_CachePatchName("R_RESBAR", PU_PATCH); // Results bars for players - if (drawping || data.rankingsmode != 0) + if (drawping || standings->rankingsmode != 0) { inwardshim = 8; } @@ -604,15 +604,15 @@ void Y_PlayerStandingsDrawer(y_data_t *standings, INT32 xoffset) ); } } - else if (data.rankingsmode != 0) + else if (standings->rankingsmode != 0) { char *increasenum = NULL; - if (data.increase[pnum] != INT16_MIN) + if (standings->increase[pnum] != INT16_MIN) { increasenum = va( "(%d)", - data.increase[pnum] + standings->increase[pnum] ); } From 36191fa4db0ee8686f0e41f42c8fde1ac83010a4 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 4 Jun 2023 12:49:08 +0100 Subject: [PATCH 02/34] Y_PlayerStandingsDrawer: Add slide in from bottom of screen for Pause In the process makes all y coordinates in the function relative to a base y, so it's less fragile to future maintenance. --- src/k_menudraw.c | 4 ++-- src/y_inter.c | 40 ++++++++++++++++++++-------------------- src/y_inter.h | 2 +- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 174868fbf..bd844abb5 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -4378,13 +4378,13 @@ void M_DrawPause(void) if (smallroundpatch != NULL) { V_DrawMappedPatch( - 24, 152, + 24, 152 + offset/2, 0, smallroundpatch, NULL); } - Y_RoundQueueDrawer(&standings, false, false); + Y_RoundQueueDrawer(&standings, offset/2, false, false); } } diff --git a/src/y_inter.c b/src/y_inter.c index fa5286c64..e90ab6cd3 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -660,9 +660,9 @@ void Y_PlayerStandingsDrawer(y_data_t *standings, INT32 xoffset) // Y_RoundQueueDrawer // // Handles drawing the bottom-of-screen progression. -// Currently requires intermission y_data to be active, but abstraction is feasible. +// Currently requires intermission y_data for animation only. // -void Y_RoundQueueDrawer(y_data_t *standings, boolean doanimations, boolean widescreen) +void Y_RoundQueueDrawer(y_data_t *standings, INT32 offset, boolean doanimations, boolean widescreen) { if (roundqueue.size == 0) { @@ -766,7 +766,7 @@ void Y_RoundQueueDrawer(y_data_t *standings, boolean doanimations, boolean wides INT32 widthofroundqueue = 24*(workingqueuesize - 1); INT32 x = (BASEVIDWIDTH - widthofroundqueue) / 2; - INT32 y; + INT32 y, basey = 167 + offset; INT32 spacetospecial = 0; @@ -829,13 +829,13 @@ void Y_RoundQueueDrawer(y_data_t *standings, boolean doanimations, boolean wides if (upwa == true) { xiter -= 24; - V_DrawMappedPatch(xiter, 167, baseflags, queuebg_upwa, greymap); + V_DrawMappedPatch(xiter, basey, baseflags, queuebg_upwa, greymap); } while (xiter > -bufferspace) { xiter -= 24; - V_DrawMappedPatch(xiter, 167, baseflags, queuebg_flat, greymap); + V_DrawMappedPatch(xiter, basey, baseflags, queuebg_flat, greymap); } for (i = 0; i < workingqueuesize; i++) @@ -846,9 +846,9 @@ void Y_RoundQueueDrawer(y_data_t *standings, boolean doanimations, boolean wides upwa ^= true; if (upwa == false) { - y = 171; + y = basey + 4; - V_DrawMappedPatch(x, 167, baseflags, queuebg_down, greymap); + V_DrawMappedPatch(x, basey, baseflags, queuebg_down, greymap); if (i+1 != workingqueuesize) // no more line? { @@ -857,17 +857,17 @@ void Y_RoundQueueDrawer(y_data_t *standings, boolean doanimations, boolean wides } else { - y = 179; + y = basey + 12; if (i+1 != workingqueuesize) // no more line? { - V_DrawMappedPatch(x, 167, baseflags, queuebg_upwa, greymap); + V_DrawMappedPatch(x, basey, baseflags, queuebg_upwa, greymap); choose_line = line_upwa; } else { - V_DrawMappedPatch(x, 167, baseflags, queuebg_flat, greymap); + V_DrawMappedPatch(x, basey, baseflags, queuebg_flat, greymap); } } @@ -936,7 +936,7 @@ void Y_RoundQueueDrawer(y_data_t *standings, boolean doanimations, boolean wides // Draw the line to the right of the dot V_DrawMappedPatch( - x - 1, 178, + x - 1, basey + 11, baseflags, choose_line[BPP_SHADOW], NULL @@ -969,7 +969,7 @@ void Y_RoundQueueDrawer(y_data_t *standings, boolean doanimations, boolean wides else { V_DrawMappedPatch( - x - 1, 179, + x - 1, basey + 12, baseflags, choose_line[BPP_DONE], colormap @@ -988,7 +988,7 @@ void Y_RoundQueueDrawer(y_data_t *standings, boolean doanimations, boolean wides } V_DrawMappedPatch( - x - 1, 179, + x - 1, basey + 12, baseflags, choose_line[lineisfull ? BPP_DONE : BPP_AHEAD], lineisfull ? colormap : NULL @@ -1006,7 +1006,7 @@ void Y_RoundQueueDrawer(y_data_t *standings, boolean doanimations, boolean wides while (xiter < BASEVIDWIDTH + bufferspace) { xiter += 24; - V_DrawMappedPatch(xiter, 167, baseflags, queuebg_flat, greymap); + V_DrawMappedPatch(xiter, basey, baseflags, queuebg_flat, greymap); } // Handle special entry on the end @@ -1068,7 +1068,7 @@ void Y_RoundQueueDrawer(y_data_t *standings, boolean doanimations, boolean wides } // Special background bump - V_DrawMappedPatch(x2 - 13, 167, baseflags, queuebg_prize, greymap); + V_DrawMappedPatch(x2 - 13, basey, baseflags, queuebg_prize, greymap); // Draw the final line const fixed_t barstart = x + 6; @@ -1095,14 +1095,14 @@ void Y_RoundQueueDrawer(y_data_t *standings, boolean doanimations, boolean wides while (xiter < fillend) { V_DrawMappedPatch( - xiter - 1, 177, + xiter - 1, basey + 10, baseflags, line_flat[BPP_SHADOW], NULL ); V_DrawMappedPatch( - xiter - 1, 179, + xiter - 1, basey + 12, baseflags, line_flat[BPP_DONE], colormap @@ -1128,14 +1128,14 @@ void Y_RoundQueueDrawer(y_data_t *standings, boolean doanimations, boolean wides while (xiter < barend) { V_DrawMappedPatch( - xiter - 1, 177, + xiter - 1, basey + 10, baseflags, line_flat[BPP_SHADOW], NULL ); V_DrawMappedPatch( - xiter - 1, 179, + xiter - 1, basey + 12, baseflags, line_flat[lineisfull ? BPP_DONE : BPP_AHEAD], lineisfull ? colormap : NULL @@ -1391,7 +1391,7 @@ skiptallydrawer: goto finalcounter; // Returns early if there's no roundqueue entries to draw - Y_RoundQueueDrawer(&data, true, false); + Y_RoundQueueDrawer(&data, 0, true, false); if (netgame) { diff --git a/src/y_inter.h b/src/y_inter.h index 7483e0ba8..27a85fa6d 100644 --- a/src/y_inter.h +++ b/src/y_inter.h @@ -49,7 +49,7 @@ void Y_Ticker(void); // Specific sub-drawers void Y_PlayerStandingsDrawer(y_data_t *standings, INT32 xoffset); -void Y_RoundQueueDrawer(y_data_t *standings, boolean doanimations, boolean widescreen); +void Y_RoundQueueDrawer(y_data_t *standings, INT32 offset, boolean doanimations, boolean widescreen); void Y_StartIntermission(void); void Y_EndIntermission(void); From 3aca89603b0e57875e303bbd7a0ba81ac272db3e Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 4 Jun 2023 16:24:46 +0100 Subject: [PATCH 03/34] M_ChallengesInputs: Debugging code for temporarily re-locking existing opened challenges is now more important than resetting the grid, because the grid can be reset via -resetchallengegrid command line param --- src/menus/extras-challenges.c | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/src/menus/extras-challenges.c b/src/menus/extras-challenges.c index eb49b762a..a61f0f58c 100644 --- a/src/menus/extras-challenges.c +++ b/src/menus/extras-challenges.c @@ -545,24 +545,16 @@ boolean M_ChallengesInputs(INT32 ch) { challengesmenu.unlockcount[CC_CHAONOPE] = 6; S_StartSound(NULL, sfx_s3k7b); //sfx_s3kb2 -#if 0 // debugging - if (challengesmenu.currentunlock < MAXUNLOCKABLES) - { - if (gamedata->unlocked[challengesmenu.currentunlock] && challengesmenu.unlockanim >= UNLOCKTIME) - { - if (challengesmenu.unlockcount[CC_TALLY] > 0) - challengesmenu.unlockcount[CC_TALLY]--; - else - challengesmenu.unlockcount[CC_UNLOCKED]--; - } - Z_Free(gamedata->challengegrid); - gamedata->challengegrid = NULL; - gamedata->challengegridwidth = 0; - M_PopulateChallengeGrid(); - M_UpdateChallengeGridExtraData(challengesmenu.extradata); - challengesmenu.pending = true; - M_ChallengesAutoFocus(challengesmenu.currentunlock, true); +#if 0 // debugging + if (challengesmenu.currentunlock < MAXUNLOCKABLES && challengesmenu.unlockanim >= UNLOCKTIME && gamedata->unlocked[challengesmenu.currentunlock] == true) + { + gamedata->unlocked[challengesmenu.currentunlock] = gamedata->unlockpending[challengesmenu.currentunlock] = false; + + if (challengesmenu.unlockcount[CC_TALLY] > 0) + challengesmenu.unlockcount[CC_TALLY]--; + else + challengesmenu.unlockcount[CC_UNLOCKED]--; } #endif } From 823315667b18406efaa0c3c74347d77a39b638ac Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 4 Jun 2023 16:39:39 +0100 Subject: [PATCH 04/34] Hold C to use a Chao Key - Takes a second and a half. - No accidential usage of your hard-earned Chao Keys. - Does a full clockwise rotation around the unlocked spot, so there's an intuitive understanding of how long you have to bail out. --- src/k_menu.h | 6 ++ src/k_menudraw.c | 124 +++++++++++++++++++++++----------- src/menus/extras-challenges.c | 91 +++++++++++++++++++------ 3 files changed, 162 insertions(+), 59 deletions(-) diff --git a/src/k_menu.h b/src/k_menu.h index 09cfbf772..b8928ad5b 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -1176,6 +1176,10 @@ void M_DrawAddons(void); #define TILEFLIP_MAX 16 +#define CHAOHOLD_MAX (3*TICRATE/2) +#define CHAOHOLD_BEGIN 7 +#define CHAOHOLD_END 3 + extern struct timeattackmenu_s { tic_t ticker; // How long the menu's been open for @@ -1201,7 +1205,9 @@ extern struct challengesmenu_s { boolean pending; boolean requestnew; + boolean chaokeyadd; + UINT8 chaokeyhold; boolean requestflip; diff --git a/src/k_menudraw.c b/src/k_menudraw.c index bd844abb5..295c298fd 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -5333,7 +5333,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y) void M_DrawChallenges(void) { - INT32 x = currentMenu->x, explodex, selectx; + INT32 x = currentMenu->x, explodex, selectx = 0, selecty = 0; INT32 y; INT16 i, j; const char *str; @@ -5410,6 +5410,7 @@ void M_DrawChallenges(void) } selectx = explodex + (challengesmenu.hilix*challengesgridstep); + selecty = currentMenu->y + (challengesmenu.hiliy*challengesgridstep); while (i >= 0 && x >= -(challengesgridstep*2)) { @@ -5447,49 +5448,12 @@ void M_DrawChallenges(void) challengesmenu.hilix, challengesmenu.hiliy, selectx, - currentMenu->y + (challengesmenu.hiliy*challengesgridstep), + selecty, true); M_DrawCharSelectExplosions(false, explodex, currentMenu->y); challengedesc: - // Chao Keys - { - patch_t *key = W_CachePatchName("UN_CHA00", PU_CACHE); - INT32 offs = challengesmenu.unlockcount[CC_CHAONOPE]; - if (offs & 1) - offs = -offs; - offs /= 2; - - if (gamedata->chaokeys > 9) - { - offs -= 6; - if (gamedata->chaokeys > 99) - offs -= 2; // as far as we can go - } - - V_DrawFixedPatch((8+offs)*FRACUNIT, 5*FRACUNIT, FRACUNIT, 0, key, NULL); - V_DrawTimerString((27+offs), 9-challengesmenu.unlockcount[CC_CHAOANIM], 0, va("%u", gamedata->chaokeys)); - - offs = challengekeybarwidth; - if (gamedata->chaokeys < GDMAX_CHAOKEYS) - offs = ((gamedata->pendingkeyroundoffset * challengekeybarwidth)/GDCONVERT_ROUNDSTOKEY); - - if (offs > 0) - V_DrawFill(1, 25, offs, 2, 0); - if (offs < challengekeybarwidth) - V_DrawFadeFill(1+offs, 25, challengekeybarwidth-offs, 2, 0, 31, challengetransparentstrength); - } - - // Tally - { - str = va("%d/%d", - challengesmenu.unlockcount[CC_UNLOCKED] + challengesmenu.unlockcount[CC_TALLY], - challengesmenu.unlockcount[CC_TOTAL] - ); - V_DrawRightAlignedTimerString(BASEVIDWIDTH-7, 9-challengesmenu.unlockcount[CC_ANIM], 0, str); - } - // Name bar { y = 120; @@ -5511,6 +5475,88 @@ challengedesc: V_DrawLSTitleLowString(BASEVIDWIDTH/2 - offset, y+6, 0, str); } + // Tally + { + str = va("%d/%d", + challengesmenu.unlockcount[CC_UNLOCKED] + challengesmenu.unlockcount[CC_TALLY], + challengesmenu.unlockcount[CC_TOTAL] + ); + V_DrawRightAlignedTimerString(BASEVIDWIDTH-7, 9-challengesmenu.unlockcount[CC_ANIM], 0, str); + } + + // Chao Keys + { + patch_t *key = W_CachePatchName("UN_CHA00", PU_CACHE); + INT32 offs = challengesmenu.unlockcount[CC_CHAONOPE]; + if (offs & 1) + offs = -offs; + offs /= 2; + + if (gamedata->chaokeys > 9) + { + offs -= 6; + if (gamedata->chaokeys > 99) + offs -= 2; // as far as we can go + } + + fixed_t keyx = (8+offs)*FRACUNIT, keyy = 5*FRACUNIT; + + if (!challengesmenu.chaokeyhold) + V_DrawFixedPatch(keyx, keyy, FRACUNIT, 0, key, NULL); + + V_DrawTimerString((27+offs), 9-challengesmenu.unlockcount[CC_CHAOANIM], 0, va("%u", gamedata->chaokeys)); + + offs = challengekeybarwidth; + if (gamedata->chaokeys < GDMAX_CHAOKEYS) + offs = ((gamedata->pendingkeyroundoffset * challengekeybarwidth)/GDCONVERT_ROUNDSTOKEY); + + if (offs > 0) + V_DrawFill(1, 25, offs, 2, 0); + if (offs < challengekeybarwidth) + V_DrawFadeFill(1+offs, 25, challengekeybarwidth-offs, 2, 0, 31, challengetransparentstrength); + + if (challengesmenu.chaokeyhold) + { + fixed_t keyholdrotation = 0, radius = challengesgridstep; + + if (challengesmenu.chaokeyhold < CHAOHOLD_BEGIN) + { + radius = (challengesmenu.chaokeyhold*radius)*(FRACUNIT/CHAOHOLD_BEGIN); + keyx += challengesmenu.chaokeyhold*((selectx*FRACUNIT) - keyx)/CHAOHOLD_BEGIN; + keyy += challengesmenu.chaokeyhold*((selecty*FRACUNIT) - keyy)/CHAOHOLD_BEGIN; + } + else + { + if (challengesmenu.chaokeyhold < CHAOHOLD_MAX - CHAOHOLD_END) + { + radius <<= FRACBITS; + + keyholdrotation = 360 * ((challengesmenu.chaokeyhold - CHAOHOLD_BEGIN)) + * (FRACUNIT/(CHAOHOLD_MAX - (CHAOHOLD_BEGIN + CHAOHOLD_END))); + } + else + { + radius = ((CHAOHOLD_MAX - challengesmenu.chaokeyhold)*radius)*(FRACUNIT/CHAOHOLD_END); + } + + keyx = selectx*FRACUNIT; + keyy = selecty*FRACUNIT; + } + + if (radius) + { + angle_t ang = (FixedAngle( + keyholdrotation + ) >> ANGLETOFINESHIFT) & FINEMASK; + + keyx += FixedMul(radius, FINESINE(ang)); + keyy -= FixedMul(radius, FINECOSINE(ang)); + } + } + + V_DrawFixedPatch(keyx, keyy, FRACUNIT, 0, key, NULL); + } + // Derived from M_DrawCharSelectPreview x = 40; y = BASEVIDHEIGHT-16; diff --git a/src/menus/extras-challenges.c b/src/menus/extras-challenges.c index a61f0f58c..51cddb8a1 100644 --- a/src/menus/extras-challenges.c +++ b/src/menus/extras-challenges.c @@ -226,6 +226,7 @@ menu_t *M_InterruptMenuWithChallenges(menu_t *desiredmenu) challengesmenu.requestflip = false; challengesmenu.requestnew = false; challengesmenu.chaokeyadd = false; + challengesmenu.chaokeyhold = 0; challengesmenu.currentunlock = MAXUNLOCKABLES; challengesmenu.unlockcondition = NULL; @@ -284,6 +285,39 @@ void M_Challenges(INT32 choice) M_SetupNextMenu(&MISC_ChallengesDef, false); } +static boolean M_CanKeyHiliTile(void) +{ + // No keys to do it with? + if (gamedata->chaokeys == 0) + return false; + + // No tile data? + if (challengesmenu.extradata == NULL) + return false; + + // No selected tile? + if (challengesmenu.currentunlock >= MAXUNLOCKABLES) + return false; + + // Already unlocked? + if (gamedata->unlocked[challengesmenu.currentunlock] == true) + return false; + + // Marked as unskippable? + if (unlockables[challengesmenu.currentunlock].majorunlock == true) + return false; + + UINT16 i = (challengesmenu.hilix * CHALLENGEGRIDHEIGHT) + challengesmenu.hiliy; + + // Not a hinted tile OR a fresh board. + if (!(challengesmenu.extradata[i].flags & CHE_HINT) + && (challengesmenu.unlockcount[CC_UNLOCKED] + challengesmenu.unlockcount[CC_TALLY] > 0)) + return false; + + // All good! + return true; +} + void M_ChallengesTick(void) { const UINT8 pid = 0; @@ -328,7 +362,38 @@ void M_ChallengesTick(void) } } - if (challengesmenu.pending && challengesmenu.fade < 5) + if (challengesmenu.chaokeyhold) + { + if (M_MenuExtraHeld(pid) && M_CanKeyHiliTile()) + { + // Not pressed just this frame? + if (!M_MenuExtraPressed(pid)) + { + challengesmenu.chaokeyhold++; + + if (challengesmenu.chaokeyhold > CHAOHOLD_MAX) + { + gamedata->chaokeys--; + challengesmenu.chaokeyhold = 0; + challengesmenu.unlockcount[CC_CHAOANIM]++; + + S_StartSound(NULL, sfx_chchng); + + challengesmenu.pending = true; + //M_ChallengesAutoFocus(challengesmenu.currentunlock, false); + challengesmenu.unlockanim = UNLOCKTIME-1; + } + } + } + else + { + challengesmenu.chaokeyhold = 0; + challengesmenu.unlockcount[CC_CHAONOPE] = 6; + S_StartSound(NULL, sfx_s3k7b); //sfx_s3kb2 + } + } + + if ((challengesmenu.pending || challengesmenu.chaokeyhold) && challengesmenu.fade < 5) { // Fade increase. challengesmenu.fade++; @@ -486,7 +551,7 @@ void M_ChallengesTick(void) } } } - else + else if (!challengesmenu.chaokeyhold) { // Tick down the tally. (currently not visible) @@ -517,29 +582,15 @@ boolean M_ChallengesInputs(INT32 ch) const boolean move = (menucmd[pid].dpad_ud != 0 || menucmd[pid].dpad_lr != 0); (void) ch; - if (challengesmenu.fade || challengesmenu.chaokeyadd) + if (challengesmenu.fade || challengesmenu.chaokeyadd || challengesmenu.chaokeyhold) { ; } - else if (M_MenuExtraPressed(pid) - && challengesmenu.extradata) + else if (M_MenuExtraPressed(pid)) { - i = (challengesmenu.hilix * CHALLENGEGRIDHEIGHT) + challengesmenu.hiliy; - - if (challengesmenu.currentunlock < MAXUNLOCKABLES - && !gamedata->unlocked[challengesmenu.currentunlock] - && !unlockables[challengesmenu.currentunlock].majorunlock - && ((challengesmenu.extradata[i].flags & CHE_HINT) - || (challengesmenu.unlockcount[CC_UNLOCKED] + challengesmenu.unlockcount[CC_TALLY] == 0)) - && gamedata->chaokeys > 0) + if (M_CanKeyHiliTile()) { - gamedata->chaokeys--; - challengesmenu.unlockcount[CC_CHAOANIM]++; - - S_StartSound(NULL, sfx_chchng); - - challengesmenu.pending = true; - M_ChallengesAutoFocus(challengesmenu.currentunlock, false); + challengesmenu.chaokeyhold = 1; } else { From d8e2b4a906c62732ef9b2c57e1a218c392ade65d Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 4 Jun 2023 21:36:52 +0100 Subject: [PATCH 05/34] Password entry on Extras menu - Type in anything you want - On closing the field, if a cheat sequence is matched *exactly*, activate it! - Directly hooked up to a modified form of the previously existing SCRAMBLE interpreter system in m_cheat.c - The existing cht_Responder call in D_ProcessEvents is gone - Done this way because the new input paragadim is not very friendly to unqualified keyboard/controller input, and we still want text - Plenty of opportunity to add fun future passwords in addition to the currently underbaked Tournament Mode - Got a debug M_StartMessage just so you can tell what's up without sound --- src/d_main.c | 14 ----- src/k_menu.h | 2 + src/k_menufunc.c | 2 + src/m_cheat.c | 135 +++++++++++++++++++------------------------ src/m_cheat.h | 2 +- src/menus/extras-1.c | 35 +++++++---- 6 files changed, 89 insertions(+), 101 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 5f4cf88ba..a4036cbb5 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -249,12 +249,6 @@ void D_ProcessEvents(void) HandleGamepadDeviceEvents(ev); - if (gameaction == ga_nothing && gamestate == GS_TITLESCREEN) - { - if (cht_Responder(ev)) - continue; - } - if (demo.savemode == DSM_TITLEENTRY) { if (G_DemoTitleResponder(ev)) @@ -295,14 +289,6 @@ void D_ProcessEvents(void) if (eaten) continue; // menu ate the event - // Demo input: - /* - if (demo.playback) - if (M_DemoResponder(ev)) - continue; // demo ate the event - */ - - G_Responder(ev); } diff --git a/src/k_menu.h b/src/k_menu.h index b8928ad5b..8d0e0b5a3 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -1035,6 +1035,7 @@ typedef enum extras_statistics, extras_eggtv, extras_stereo, + extras_password, } extras_e; void M_InitExtras(INT32 choice); // init for the struct @@ -1098,6 +1099,7 @@ void M_AddonsRefresh(void); void M_HandleAddons(INT32 choice); char *M_AddonsHeaderPath(void); extern consvar_t cv_dummyaddonsearch; +extern consvar_t cv_dummyextraspassword; void M_Manual(INT32 choice); void M_HandleImageDef(INT32 choice); diff --git a/src/k_menufunc.c b/src/k_menufunc.c index 32c51d092..660e72050 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -1190,5 +1190,7 @@ void M_Init(void) CV_RegisterVar(&cv_dummyaddonsearch); + CV_RegisterVar(&cv_dummyextraspassword); + M_UpdateMenuBGImage(true); } diff --git a/src/m_cheat.c b/src/m_cheat.c index 72ffd6523..027963290 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -68,9 +68,6 @@ static UINT8 cheatf_warp(void) /*if (modifiedgame) return 0;*/ - if (menuactive && currentMenu != &MainDef) - return 0; // Only on the main menu! - // Unlock EVERYTHING. for (i = 0; i < MAXUNLOCKABLES; i++) { @@ -89,9 +86,8 @@ static UINT8 cheatf_warp(void) S_StartSound(0, sfx_kc42); } - // Refresh secrets menu existing. - M_ClearMenus(true); - M_StartControlPanel(); + M_StartMessage(M_GetText("TOURNAMENT MODE ENGAGED!!\n\nIs what I would be saying if I actually\nimplemented anything special here.\n\nPress (B)\n"), NULL, MM_NOTHING); + return 1; } @@ -103,50 +99,46 @@ static UINT8 cheatf_devmode(void) if (modifiedgame) return 0; - if (menuactive && currentMenu != &MainDef) - return 0; // Only on the main menu! - - S_StartSound(0, sfx_itemup); - // Just unlock all the things and turn on -debug and console devmode. - G_SetUsedCheats(); for (i = 0; i < MAXUNLOCKABLES; i++) + { + if (!unlockables[i].conditionset) + continue; gamedata->unlocked[i] = true; + } + + G_SetUsedCheats(); + S_StartSound(0, sfx_kc42); + devparm = true; cht_debug |= 0x8000; - // Refresh secrets menu existing. - M_ClearMenus(true); - M_StartControlPanel(); return 1; } #endif static cheatseq_t cheat_warp = { - 0, cheatf_warp, + NULL, cheatf_warp, //{ SCRAMBLE('r'), SCRAMBLE('e'), SCRAMBLE('d'), SCRAMBLE('x'), SCRAMBLE('v'), SCRAMBLE('i'), 0xff } (UINT8[]){ SCRAMBLE('b'), SCRAMBLE('a'), SCRAMBLE('n'), SCRAMBLE('a'), SCRAMBLE('n'), SCRAMBLE('a'), 0xff } }; -static cheatseq_t cheat_warp_joy = { - 0, cheatf_warp, - /*{ SCRAMBLE(KEY_LEFTARROW), SCRAMBLE(KEY_LEFTARROW), SCRAMBLE(KEY_UPARROW), - SCRAMBLE(KEY_RIGHTARROW), SCRAMBLE(KEY_RIGHTARROW), SCRAMBLE(KEY_UPARROW), - SCRAMBLE(KEY_LEFTARROW), SCRAMBLE(KEY_UPARROW), - SCRAMBLE(KEY_ENTER), 0xff }*/ - (UINT8[]){ SCRAMBLE(KEY_LEFTARROW), SCRAMBLE(KEY_UPARROW), SCRAMBLE(KEY_RIGHTARROW), - SCRAMBLE(KEY_RIGHTARROW), SCRAMBLE(KEY_UPARROW), SCRAMBLE(KEY_LEFTARROW), - SCRAMBLE(KEY_DOWNARROW), SCRAMBLE(KEY_RIGHTARROW), - SCRAMBLE(KEY_ENTER), 0xff } -}; - #ifdef DEVELOP static cheatseq_t cheat_devmode = { - 0, cheatf_devmode, + NULL, cheatf_devmode, (UINT8[]){ SCRAMBLE('d'), SCRAMBLE('e'), SCRAMBLE('v'), SCRAMBLE('m'), SCRAMBLE('o'), SCRAMBLE('d'), SCRAMBLE('e'), 0xff } }; #endif +cheatseq_t *cheatseqlist[] = +{ + &cheat_warp, +#ifdef DEVELOP + &cheat_devmode, +#endif + NULL +}; + // ========================================================================== // CHEAT SEQUENCE PACKAGE // ========================================================================== @@ -168,73 +160,64 @@ void cht_Init(void) // Called in st_stuff module, which handles the input. // Returns a 1 if the cheat was successful, 0 if failed. // -static UINT8 cht_CheckCheat(cheatseq_t *cht, char key) +static UINT8 cht_CheckCheat(cheatseq_t *cht, char key, boolean shouldend) { - UINT8 rc = 0; + UINT8 rc = 0; // end of sequence character - if (!cht->p) - cht->p = cht->sequence; // initialize if first time + if (cht->p == NULL || *cht->p == 0xff) + return rc; if (*cht->p == 0) *(cht->p++) = key; else if (cheat_xlate_table[(UINT8)key] == *cht->p) cht->p++; else - cht->p = cht->sequence; + { + cht->p = NULL; + return rc; + } if (*cht->p == 1) cht->p++; - else if (*cht->p == 0xff) // end of sequence character - { - cht->p = cht->sequence; + if (shouldend && *cht->p == 0xff) // end of sequence character rc = cht->func(); - } return rc; } -boolean cht_Responder(event_t *ev) +boolean cht_Interpret(const char *password) { - UINT8 ret = 0, ch = 0; - if (ev->type != ev_keydown) + if (!password) return false; - if (ev->data1 > 0xFF) - { - // map some fake (joy) inputs into keys - // map joy inputs into keys - switch (ev->data1) - { - case KEY_JOY1: - case KEY_JOY1 + 2: - ch = KEY_ENTER; - break; - case KEY_HAT1: - ch = KEY_UPARROW; - break; - case KEY_HAT1 + 1: - ch = KEY_DOWNARROW; - break; - case KEY_HAT1 + 2: - ch = KEY_LEFTARROW; - break; - case KEY_HAT1 + 3: - ch = KEY_RIGHTARROW; - break; - default: - // no mapping - return false; - } - } - else - ch = (UINT8)ev->data1; + UINT8 ret = 0; - ret += cht_CheckCheat(&cheat_warp, (char)ch); - ret += cht_CheckCheat(&cheat_warp_joy, (char)ch); -#ifdef DEVELOP - ret += cht_CheckCheat(&cheat_devmode, (char)ch); -#endif - return (ret != 0); + size_t cheatseqid = 0; + + const char *endofpassword = password; + while (*endofpassword && *(endofpassword+1)) + endofpassword++; + + cheatseqid = 0; + while (cheatseqlist[cheatseqid]) + { + cheatseqlist[cheatseqid]->p = cheatseqlist[cheatseqid]->sequence; + cheatseqid++; + } + + while (*password) + { + cheatseqid = 0; + while (cheatseqlist[cheatseqid]) + { + ret += cht_CheckCheat(cheatseqlist[cheatseqid], *password, (password == endofpassword)); + cheatseqid++; + } + + password++; + } + + return (ret > 0); } // Console cheat commands rely on these a lot... diff --git a/src/m_cheat.h b/src/m_cheat.h index 45d57eaae..d8b21d477 100644 --- a/src/m_cheat.h +++ b/src/m_cheat.h @@ -46,7 +46,7 @@ typedef enum { // // Cheat sequences // -boolean cht_Responder(event_t *ev); +boolean cht_Interpret(const char *password); void cht_Init(void); // diff --git a/src/menus/extras-1.c b/src/menus/extras-1.c index 8fe411196..765a95cdc 100644 --- a/src/menus/extras-1.c +++ b/src/menus/extras-1.c @@ -3,6 +3,7 @@ #include "../k_menu.h" #include "../m_cond.h" +#include "../m_cheat.h" #include "../s_sound.h" menuitem_t EXTRAS_Main[] = @@ -28,6 +29,9 @@ menuitem_t EXTRAS_Main[] = {IT_STRING | IT_CALL, NULL, NULL, NULL, {.routine = M_SoundTest}, 0, 0}, + + {IT_STRING | IT_CVAR | IT_CV_STRING, "Password", "If you don't know any passwords, come back later!", + NULL, {.cvar = &cv_dummyextraspassword}, 0, 0}, }; // the extras menu essentially reuses the options menu stuff @@ -53,18 +57,10 @@ menu_t EXTRAS_MainDef = { struct extrasmenu_s extrasmenu; +consvar_t cv_dummyextraspassword = CVAR_INIT ("dummyextraspassword", "", CV_HIDDEN, NULL, NULL); + void M_InitExtras(INT32 choice) { - (void)choice; - - extrasmenu.ticker = 0; - extrasmenu.offset = 0; - - extrasmenu.extx = 0; - extrasmenu.exty = 0; - extrasmenu.textx = 0; - extrasmenu.texty = 0; - // Addons if (M_SecretUnlocked(SECRET_ADDONS, true)) { @@ -127,6 +123,17 @@ void M_InitExtras(INT32 choice) EXTRAS_Main[extras_stereo].text = EXTRAS_Main[extras_stereo].tooltip = "???"; } + if (choice == -1) + return; + + extrasmenu.ticker = 0; + extrasmenu.offset = 0; + + extrasmenu.extx = 0; + extrasmenu.exty = 0; + extrasmenu.textx = 0; + extrasmenu.texty = 0; + M_SetupNextMenu(&EXTRAS_MainDef, false); } @@ -163,6 +170,14 @@ void M_ExtrasTick(void) extrasmenu.textx = 160; extrasmenu.texty = 50; } + + if (menutyping.active == false && cv_dummyextraspassword.string[0] != '\0') + { + if (cht_Interpret(cv_dummyextraspassword.string) == true) + M_InitExtras(-1); + + CV_StealthSet(&cv_dummyextraspassword, ""); + } } boolean M_ExtrasInputs(INT32 ch) From ee8c0392ef373cc54a93fe92918bd353c69309bc Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 4 Jun 2023 21:55:15 +0100 Subject: [PATCH 06/34] Adjust Extras Tutorial tooltip --- src/menus/extras-1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/menus/extras-1.c b/src/menus/extras-1.c index 765a95cdc..9cc211287 100644 --- a/src/menus/extras-1.c +++ b/src/menus/extras-1.c @@ -15,7 +15,7 @@ menuitem_t EXTRAS_Main[] = {IT_STRING | IT_CALL, NULL, NULL, NULL, {.routine = M_Addons}, 0, 0}, - {IT_STRING | IT_CALL, "Tutorial", "Help Dr. Eggman and Tails test out their new Ring Racers.", + {IT_STRING | IT_CALL, "Tutorial", "Help Dr. Robotnik and Tails test out their new Ring Racers.", NULL, {.routine = M_LevelSelectInit}, 0, GT_TUTORIAL}, {IT_STRING | IT_CALL, "Challenges", "View the requirements for some of the secret content you can unlock!", From 98e866c393dc6d6487d66b1b99c906d4a146de93 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 4 Jun 2023 22:34:44 +0100 Subject: [PATCH 07/34] M_LevelListFromGametype: Fix copypaste error causing empty Lost & Found to show up when restoring certain post-Time Attack cupgrids --- src/menus/transient/level-select.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/menus/transient/level-select.c b/src/menus/transient/level-select.c index 68d395abf..d58c40151 100644 --- a/src/menus/transient/level-select.c +++ b/src/menus/transient/level-select.c @@ -347,7 +347,7 @@ boolean M_LevelListFromGametype(INT16 gt) templevelsearch.cup = &dummy_lostandfound; templevelsearch.checklocked = true; - if (M_GetFirstLevelInList(&temp, &levellist.levelsearch) != NEXTMAP_INVALID) + if (M_GetFirstLevelInList(&temp, &templevelsearch) != NEXTMAP_INVALID) { foundany = true; GRID_INSERTCUP; From 2ab046fc306dffcb2e7642f138362a101028e6de Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 6 Jun 2023 15:33:46 +0100 Subject: [PATCH 08/34] M_GetConditionString: Hide Cup for UCRP_PODIUMCUP if not unlocked --- src/m_cond.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/m_cond.c b/src/m_cond.c index 728185978..e6dd45699 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -1322,7 +1322,10 @@ static const char *M_GetConditionString(condition_t *cn) { if (cup->id != cn->requirement) continue; - return va("%s%s %s CUP", completetype, orbetter, cup->name); + return va("%s%s %s CUP", + completetype, orbetter, + (M_CupLocked(cup) ? "???" : cup->name) + ); } return va("INVALID CUP CONDITION \"%d:%d\"", cn->type, cn->requirement); } From 7d57be18c3c33667d9f1ccf683e22c259df5ab6e Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 6 Jun 2023 15:36:59 +0100 Subject: [PATCH 09/34] M_GetConditionString: Since completing a cup at any difficulty now downpopulates, remove all "or better" for GP difficulty related conditions In addition, disable the "on Normal difficulty", as it's impossible to get Emeralds on Easy --- src/m_cond.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/m_cond.c b/src/m_cond.c index e6dd45699..714a513b9 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -1081,7 +1081,7 @@ static const char *M_GetConditionString(condition_t *cn) case UC_ALLSUPER: case UC_ALLEMERALDS: { - const char *chaostext, *speedtext = "", *orbetter = ""; + const char *chaostext, *speedtext = ""; if (!gamedata->everseenspecial) return NULL; @@ -1093,17 +1093,14 @@ static const char *M_GetConditionString(condition_t *cn) else chaostext = "14"; - if (cn->requirement == KARTSPEED_NORMAL) + /*if (cn->requirement == KARTSPEED_NORMAL) -- Emeralds can not be collected on Easy { speedtext = " on Normal difficulty"; - //if (M_SecretUnlocked(SECRET_HARDSPEED, true)) - orbetter = " or better"; } - else if (cn->requirement == KARTSPEED_HARD) + else*/ + if (cn->requirement == KARTSPEED_HARD) { speedtext = " on Hard difficulty"; - if (M_SecretUnlocked(SECRET_MASTERMODE, true)) - orbetter = " or better"; } else if (cn->requirement == KARTGP_MASTER) { @@ -1113,7 +1110,7 @@ static const char *M_GetConditionString(condition_t *cn) speedtext = " on ???"; } - return va("collect all %s Emeralds%s%s", chaostext, speedtext, orbetter); + return va("collect all %s Emeralds%s", chaostext, speedtext); } case UC_TOTALMEDALS: // Requires number of emblems >= x @@ -1265,7 +1262,7 @@ static const char *M_GetConditionString(condition_t *cn) if (cn->requirement == KARTSPEED_NORMAL) { - speedtext = "on Normal difficulty or better"; + speedtext = "on Normal difficulty"; } else if (cn->requirement == KARTSPEED_HARD) { From 4ceeea0bbdd459ad6fd04fddd3f53617f5076258 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 6 Jun 2023 15:53:05 +0100 Subject: [PATCH 10/34] M_GetConditionString: On second thoughts, to avoid misleading with ideas of a Battle win, prefix UC_ALLEMERALDS/UC_ALLCHAOS/UC_ALLSUPER with `GRAND PRIX:` --- src/m_cond.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/m_cond.c b/src/m_cond.c index 714a513b9..5edbbeb4c 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -1110,7 +1110,7 @@ static const char *M_GetConditionString(condition_t *cn) speedtext = " on ???"; } - return va("collect all %s Emeralds%s", chaostext, speedtext); + return va("GRAND PRIX: collect all %s Emeralds%s", chaostext, speedtext); } case UC_TOTALMEDALS: // Requires number of emblems >= x From 7fd957c92982bead3fae1a596158642fd5218995 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 6 Jun 2023 15:55:23 +0100 Subject: [PATCH 11/34] M_InitExtras: Call with parameter -1 in more circumstances, to prevent an incorrect Extras Menu after Addon load/Challenge unlock. --- src/k_menufunc.c | 5 +++++ src/menus/extras-addons.c | 3 +++ 2 files changed, 8 insertions(+) diff --git a/src/k_menufunc.c b/src/k_menufunc.c index 660e72050..55b308fbf 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -487,6 +487,11 @@ menu_t *M_SpecificMenuRestore(menu_t *torestore) // Ticker init M_MPOptSelectInit(-1); } + else if (torestore == &EXTRAS_MainDef) + { + // Disable or enable certain options + M_InitExtras(-1); + } // One last catch. M_SetupPlayMenu(-1); diff --git a/src/menus/extras-addons.c b/src/menus/extras-addons.c index e3cbf192b..147f6e714 100644 --- a/src/menus/extras-addons.c +++ b/src/menus/extras-addons.c @@ -341,6 +341,9 @@ void M_HandleAddons(INT32 choice) // Secret menu! //MainMenu[secrets].status = (M_AnySecretUnlocked()) ? (IT_STRING | IT_CALL) : (IT_DISABLED); + // I could guard it, but let's just always do this. + M_InitExtras(-1); + if (currentMenu->prevMenu) M_SetupNextMenu(M_InterruptMenuWithChallenges(currentMenu->prevMenu), false); else From f106d14d69335eb1036befd4deda2b7f40334188 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 6 Jun 2023 18:41:43 +0100 Subject: [PATCH 12/34] M_SanitiseChallengeGrid Attempts to recover Challenge Grids that aren't quite appropriate for the current suite of unlocks. - If there's multiple small tiles pointing to the same unlock, turn the later ones empty. - If there's a small tile that SHOULD present on the grid and an empty spot, put the needed tile in that spot. - Otherwise, regenerate the entire grid. This will permit us to change the number of unlockables without forcing people to run with the command line param `-resetchallengegrid` to see 'em. --- src/g_game.c | 2 ++ src/m_cond.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/m_cond.h | 1 + 3 files changed, 85 insertions(+) diff --git a/src/g_game.c b/src/g_game.c index d8ddd00ce..553a905cb 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4974,6 +4974,8 @@ void G_LoadGameData(void) gamedata->challengegrid[i] = READUINT16(save.p); } } + + M_SanitiseChallengeGrid(); } else { diff --git a/src/m_cond.c b/src/m_cond.c index 5edbbeb4c..fc24c3986 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -312,6 +312,88 @@ quickcheckagain: } } +void M_SanitiseChallengeGrid(void) +{ + UINT8 seen[MAXUNLOCKABLES]; + UINT16 empty[MAXUNLOCKABLES + (CHALLENGEGRIDHEIGHT-1)]; + UINT16 i, j, numempty = 0; + + if (gamedata->challengegrid == NULL) + return; + + memset(seen, 0, sizeof(seen)); + + // Go through all spots to identify duplicates and absences. + for (j = 0; j < gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT; j++) + { + i = gamedata->challengegrid[j]; + + if (i >= MAXUNLOCKABLES || !unlockables[i].conditionset) + { + empty[numempty++] = j; + continue; + } + + if (seen[i] != 5) // Arbitrary cap greater than 4 + { + seen[i]++; + + if (seen[i] == 1 || unlockables[i].majorunlock) + { + continue; + } + } + + empty[numempty++] = j; + } + + // Go through unlockables to identify if any haven't been seen. + for (i = 0; i < MAXUNLOCKABLES; ++i) + { + if (!unlockables[i].conditionset) + { + continue; + } + + if (unlockables[i].majorunlock && seen[i] != 4) + { + // Probably not enough spots to retrofit. + goto badgrid; + } + + if (seen[i] != 0) + { + // Present on the challenge grid. + continue; + } + + if (numempty != 0) + { + // Small ones can be slotted in easy. + j = empty[--numempty]; + gamedata->challengegrid[j] = i; + } + + // Nothing we can do to recover. + goto badgrid; + } + + // Fill the remaining spots with empties. + while (numempty != 0) + { + j = empty[--numempty]; + gamedata->challengegrid[j] = MAXUNLOCKABLES; + } + + return; + +badgrid: + // Just remove everything and let it get regenerated. + Z_Free(gamedata->challengegrid); + gamedata->challengegrid = NULL; + gamedata->challengegridwidth = 0; +} + void M_UpdateChallengeGridExtraData(challengegridextradata_t *extradata) { UINT16 i, j, num, id, tempid, work; diff --git a/src/m_cond.h b/src/m_cond.h index fb96a14b7..2dfb1a221 100644 --- a/src/m_cond.h +++ b/src/m_cond.h @@ -302,6 +302,7 @@ void M_NewGameDataStruct(void); // Challenges menu stuff void M_PopulateChallengeGrid(void); +void M_SanitiseChallengeGrid(void); struct challengegridextradata_t { From e162fffecfb0a8824df0377e6af09479e336550b Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 7 Jun 2023 08:14:30 +0100 Subject: [PATCH 13/34] UC_PASSWORD Unlockable type that supports entering (case-insensitive) string --- src/deh_soc.c | 7 +++++++ src/m_cond.c | 43 ++++++++++++++++++++++++++++++++++++++++++- src/m_cond.h | 3 +++ src/menus/extras-1.c | 11 ++++++++++- 4 files changed, 62 insertions(+), 2 deletions(-) diff --git a/src/deh_soc.c b/src/deh_soc.c index b466f1158..f6ae6a285 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -2585,6 +2585,13 @@ static void readcondition(UINT8 set, UINT32 id, char *word2) //PARAMCHECK(1); ty = UC_ADDON + offset; } + else if (fastcmp(params[0], "PASSWORD")) + { + PARAMCHECK(1); + ty = UC_PASSWORD; + stringvar = Z_StrDup(params[1]); + re = -1; + } else if ((offset=0) || fastcmp(params[0], "AND") || (++offset && fastcmp(params[0], "COMMA"))) { diff --git a/src/m_cond.c b/src/m_cond.c index fc24c3986..eca1b5433 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -844,6 +844,8 @@ boolean M_CheckCondition(condition_t *cn, player_t *player) return true; } return false; + case UC_PASSWORD: + return (cn->stringvar == NULL); // Just for string building case UC_AND: @@ -1292,6 +1294,8 @@ static const char *M_GetConditionString(condition_t *cn) if (gamedata->evercrashed) return "launch \"Dr. Robotnik's Ring Racers\" again after a game crash"; return NULL; + case UC_PASSWORD: + return "enter a secret password"; case UC_AND: return "&"; @@ -1610,7 +1614,7 @@ char *M_BuildConditionSetString(UINT16 unlockid) static boolean M_CheckUnlockConditions(player_t *player) { - INT32 i; + UINT32 i; conditionset_t *c; boolean ret; @@ -1629,6 +1633,43 @@ static boolean M_CheckUnlockConditions(player_t *player) return ret; } +boolean M_ConditionInterpret(const char *password) +{ + UINT32 i, j; + conditionset_t *c; + condition_t *cn; + + for (i = 0; i < MAXCONDITIONSETS; ++i) + { + c = &conditionSets[i]; + + if (!c->numconditions || gamedata->achieved[i]) + continue; + + for (j = 0; j < c->numconditions; ++j) + { + cn = &c->condition[j]; + + if (cn->type != UC_PASSWORD) + continue; + + if (cn->stringvar == NULL) + continue; + + if (stricmp(cn->stringvar, password)) + continue; + + // Remove the password for this session. + Z_Free(cn->stringvar); + cn->stringvar = NULL; + + return true; + } + } + + return false; +} + boolean M_UpdateUnlockablesAndExtraEmblems(boolean loud, boolean doall) { UINT16 i = 0, response = 0, newkeys = 0; diff --git a/src/m_cond.h b/src/m_cond.h index 2dfb1a221..c178b2f5d 100644 --- a/src/m_cond.h +++ b/src/m_cond.h @@ -55,6 +55,8 @@ typedef enum UC_REPLAY, // Save a replay UC_CRASH, // Hee ho ! + UC_PASSWORD, // Type in something funny + // Just for string building UC_AND, UC_COMMA, @@ -333,6 +335,7 @@ void M_ClearStats(void); boolean M_NotFreePlay(player_t *player); // Updating conditions and unlockables +boolean M_ConditionInterpret(const char *password); boolean M_CheckCondition(condition_t *cn, player_t *player); boolean M_UpdateUnlockablesAndExtraEmblems(boolean loud, boolean doall); diff --git a/src/menus/extras-1.c b/src/menus/extras-1.c index 9cc211287..4331743b6 100644 --- a/src/menus/extras-1.c +++ b/src/menus/extras-1.c @@ -173,8 +173,17 @@ void M_ExtrasTick(void) if (menutyping.active == false && cv_dummyextraspassword.string[0] != '\0') { - if (cht_Interpret(cv_dummyextraspassword.string) == true) + if (M_ConditionInterpret(cv_dummyextraspassword.string) == true) + { + if (M_UpdateUnlockablesAndExtraEmblems(true, true)) + { + M_Challenges(0); + } + } + else if (cht_Interpret(cv_dummyextraspassword.string) == true) + { M_InitExtras(-1); + } CV_StealthSet(&cv_dummyextraspassword, ""); } From c8f74aef2bc456b15f03ac1b3573b18315a5c63f Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 7 Jun 2023 11:51:15 +0100 Subject: [PATCH 14/34] menubehaviourflags_t: Add MBF_NOLOOPENTRIES Abstracts one previously hardcoded exception to M_NextOpt/M_PrevOpt --- src/k_menu.h | 5 +++-- src/k_menufunc.c | 14 ++++++++------ src/menus/extras-addons.c | 2 +- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/k_menu.h b/src/k_menu.h index 8d0e0b5a3..6ae486504 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -131,8 +131,9 @@ void M_HandlePauseMenuGametype(INT32 choice); typedef enum { - MBF_UD_LR_FLIPPED = 1, // flip up-down and left-right axes - MBF_SOUNDLESS = 2, // do not play base menu sounds + 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 } menubehaviourflags_t; struct menuitem_t diff --git a/src/k_menufunc.c b/src/k_menufunc.c index 55b308fbf..2c2bf3d40 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -159,10 +159,11 @@ boolean M_NextOpt(void) if (itemOn + 1 > currentMenu->numitems - 1) { // Prevent looparound here - // If you're going to add any extra exceptions, DON'T. - // Add a "don't loop" flag to the menu_t struct instead. - if (currentMenu == &MISC_AddonsDef) + if (currentMenu->behaviourflags & MBF_NOLOOPENTRIES) + { + itemOn = oldItemOn; return false; + } itemOn = 0; } else @@ -186,10 +187,11 @@ boolean M_PrevOpt(void) if (!itemOn) { // Prevent looparound here - // If you're going to add any extra exceptions, DON'T. - // Add a "don't loop" flag to the menu_t struct instead. - if (currentMenu == &MISC_AddonsDef) + if (currentMenu->behaviourflags & MBF_NOLOOPENTRIES) + { + itemOn = oldItemOn; return false; + } itemOn = currentMenu->numitems - 1; } else diff --git a/src/menus/extras-addons.c b/src/menus/extras-addons.c index 147f6e714..6ecf56398 100644 --- a/src/menus/extras-addons.c +++ b/src/menus/extras-addons.c @@ -23,7 +23,7 @@ menu_t MISC_AddonsDef = { MISC_AddonsMenu, 50, 28, 0, 0, - 0, + MBF_NOLOOPENTRIES, "EXTRAS", 0, 0, M_DrawAddons, From 7bda2f72cf5622c14f001be0cf30b98f172953c8 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 7 Jun 2023 14:24:33 +0100 Subject: [PATCH 15/34] Wrongwarp cheat `banana` was the cheat for the previous entry in the series. Visuals are incomplete but I have to go out in a little bit and the bulk of it is done (The Tournament mode cheat's password is "placeholder" for now.) --- src/k_menu.h | 9 ++++ src/k_menudraw.c | 110 +++++++++++++++++++++++++++++++++++++++ src/m_cheat.c | 15 +++++- src/menus/CMakeLists.txt | 1 + src/menus/extras-wrong.c | 53 +++++++++++++++++++ 5 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 src/menus/extras-wrong.c diff --git a/src/k_menu.h b/src/k_menu.h index 6ae486504..7bb9c3399 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -425,6 +425,8 @@ extern menuitem_t MISC_ChallengesStatsDummyMenu[]; extern menu_t MISC_ChallengesDef; extern menu_t MISC_StatisticsDef; +extern menu_t MISC_WrongWarpDef; + extern menuitem_t MISC_SoundTest[]; extern menu_t MISC_SoundTestDef; @@ -1237,6 +1239,13 @@ void M_Statistics(INT32 choice); void M_DrawStatistics(void); boolean M_StatisticsInputs(INT32 ch); +extern struct wrongwarp_s { + INT32 ticker; +} wrongwarp; + +void M_WrongWarp(INT32 choice); +void M_DrawWrongWarp(void); + typedef enum { stereospecial_none = 0, diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 295c298fd..0e00f927d 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -5900,6 +5900,116 @@ void M_DrawStatistics(void) #undef STATSSTEP +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; +} + +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<width)), (BASEVIDHEIGHT-8)-(SHORT(bumper->height)), 0, bumper); +} + void M_DrawSoundTest(void) { UINT8 pid = 0; // todo: Add ability for any splitscreen player to bring up the menu. diff --git a/src/m_cheat.c b/src/m_cheat.c index 027963290..953d0f350 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -91,6 +91,14 @@ static UINT8 cheatf_warp(void) return 1; } +static UINT8 cheatf_wrongwarp(void) +{ + // Tee hee. + M_WrongWarp(0); + + return 1; +} + #ifdef DEVELOP static UINT8 cheatf_devmode(void) { @@ -119,7 +127,11 @@ static UINT8 cheatf_devmode(void) static cheatseq_t cheat_warp = { NULL, cheatf_warp, - //{ SCRAMBLE('r'), SCRAMBLE('e'), SCRAMBLE('d'), SCRAMBLE('x'), SCRAMBLE('v'), SCRAMBLE('i'), 0xff } + (UINT8[]){ SCRAMBLE('p'), SCRAMBLE('l'), SCRAMBLE('a'), SCRAMBLE('c'), SCRAMBLE('e'), SCRAMBLE('h'), SCRAMBLE('o'), SCRAMBLE('l'), SCRAMBLE('d'), SCRAMBLE('e'), SCRAMBLE('r'), 0xff } +}; + +static cheatseq_t cheat_wrongwarp = { + NULL, cheatf_wrongwarp, (UINT8[]){ SCRAMBLE('b'), SCRAMBLE('a'), SCRAMBLE('n'), SCRAMBLE('a'), SCRAMBLE('n'), SCRAMBLE('a'), 0xff } }; @@ -133,6 +145,7 @@ static cheatseq_t cheat_devmode = { cheatseq_t *cheatseqlist[] = { &cheat_warp, + &cheat_wrongwarp, #ifdef DEVELOP &cheat_devmode, #endif diff --git a/src/menus/CMakeLists.txt b/src/menus/CMakeLists.txt index d5ef8d60e..2fdbb8719 100644 --- a/src/menus/CMakeLists.txt +++ b/src/menus/CMakeLists.txt @@ -4,6 +4,7 @@ target_sources(SRB2SDL2 PRIVATE extras-challenges.c extras-egg-tv.cpp extras-statistics.c + extras-wrong.c main-1.c main-profile-select.c options-1.c diff --git a/src/menus/extras-wrong.c b/src/menus/extras-wrong.c new file mode 100644 index 000000000..a0071a93a --- /dev/null +++ b/src/menus/extras-wrong.c @@ -0,0 +1,53 @@ +/// \file menus/extras-wrong.c +/// \brief Wrongwarp + +#include "../k_menu.h" + +struct wrongwarp_s wrongwarp; + +static menuitem_t MISC_WrongWarpMenu[] = +{ + {IT_NOTHING, NULL, NULL, NULL, {NULL}, 0, 0}, +}; + +void M_WrongWarp(INT32 choice) +{ + (void)choice; + + wrongwarp.ticker = 0; + + MISC_WrongWarpDef.prevMenu = currentMenu; + M_SetupNextMenu(&MISC_WrongWarpDef, false); +} + +static void M_WrongWarpTick(void) +{ + wrongwarp.ticker++; +} + +static boolean M_WrongWarpInputs(INT32 ch) +{ + (void)ch; + + if (wrongwarp.ticker < TICRATE/2) + return true; + + return false; +} + +menu_t MISC_WrongWarpDef = { + sizeof (MISC_WrongWarpMenu)/sizeof (menuitem_t), + &MainDef, + 0, + MISC_WrongWarpMenu, + 0, 0, + 0, 0, + MBF_SOUNDLESS, + "YEAWAY", + 98, 0, + M_DrawWrongWarp, + M_WrongWarpTick, + NULL, + NULL, + M_WrongWarpInputs, +}; From 1957f74853e695bb75bf468b894d3555a1bc9f6a Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 7 Jun 2023 17:55:26 +0100 Subject: [PATCH 16/34] Improve handling for Tournament Mode - Clearer user-facing messages - Returns to title screen clearing menus in the normal case --- src/m_cheat.c | 25 +++++++++++++++++++++++-- src/menus/extras-1.c | 2 +- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/m_cheat.c b/src/m_cheat.c index 953d0f350..c94699a93 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -83,10 +83,31 @@ static UINT8 cheatf_warp(void) if (success) { G_SetUsedCheats(); + M_ClearMenus(true); S_StartSound(0, sfx_kc42); - } - M_StartMessage(M_GetText("TOURNAMENT MODE ENGAGED!!\n\nIs what I would be saying if I actually\nimplemented anything special here.\n\nPress (B)\n"), NULL, MM_NOTHING); + M_StartMessage(M_GetText( + "TOURNAMENT MODE\n\ + \nAll challenges temporarily unlocked.\n\ + Saving is disabled - the game will\n\ + return to normal on next launch.\n\ + \n\ + Press (B)\n" + ), NULL, MM_NOTHING); + } + else + { + S_StartSound(0, sfx_s3k7b); + + M_StartMessage(M_GetText( + "TOURNAMENT MODE\n\ + \nThis is the correct password, but.\n\ + you already have every challenge\n\ + unlocked, so saving is still allowed!\n\ + \n\ + Press (B)\n" + ), NULL, MM_NOTHING); + } return 1; } diff --git a/src/menus/extras-1.c b/src/menus/extras-1.c index 4331743b6..5e11a6121 100644 --- a/src/menus/extras-1.c +++ b/src/menus/extras-1.c @@ -180,7 +180,7 @@ void M_ExtrasTick(void) M_Challenges(0); } } - else if (cht_Interpret(cv_dummyextraspassword.string) == true) + else if (cht_Interpret(cv_dummyextraspassword.string) == true && menuactive == true) { M_InitExtras(-1); } From 8efd4788e7cde06a69400f1790d75d5e27283bbe Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 7 Jun 2023 23:05:19 +0100 Subject: [PATCH 17/34] enum gdmusic_t Replaces existing musicflag system, which only had one flag, with a priority system that overrides menu music in general. Also adds the CHAO KEY FREE DDL WORKING 2023 goofy music for matchesplayed Chao Key generation. --- src/k_menufunc.c | 24 +++++++++++++++++------- src/m_cond.c | 11 +++++++++-- src/m_cond.h | 11 +++++++++-- src/p_setup.c | 2 +- 4 files changed, 36 insertions(+), 12 deletions(-) diff --git a/src/k_menufunc.c b/src/k_menufunc.c index 2c2bf3d40..e04675fb2 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -372,18 +372,19 @@ boolean M_Responder(event_t *ev) void M_PlayMenuJam(void) { menu_t *refMenu = (menuactive ? currentMenu : restoreMenu); - static boolean loserclubpermitted = false; - boolean loserclub = (loserclubpermitted && (gamedata->musicflags & GDMUSIC_LOSERCLUB)); + static boolean musicstatepermitted = false; if (challengesmenu.pending) { S_StopMusic(); S_StopMusicCredit(); - loserclubpermitted = true; + musicstatepermitted = true; return; } + gdmusic_t override = musicstatepermitted ? gamedata->musicstate : 0; + if (Playing() || soundtest.playing) return; @@ -395,7 +396,7 @@ void M_PlayMenuJam(void) S_StopMusicCredit(); return; } - else if (!loserclub) + else if (override == 0) { if (NotCurrentlyPlaying(refMenu->music)) { @@ -406,12 +407,21 @@ void M_PlayMenuJam(void) } } - if (loserclub) + if (override != 0) { - if (refMenu != NULL && NotCurrentlyPlaying("LOSERC")) + // See also gdmusic_t + const char* overridetotrack[GDMUSIC_MAX-1] = { + "KEYGEN", + "LOSERC", + }; + + if (refMenu != NULL && NotCurrentlyPlaying(overridetotrack[override - 1])) { - S_ChangeMusicInternal("LOSERC", true); + S_ChangeMusicInternal(overridetotrack[override - 1], true); S_ShowMusicCredit(); + + if (override < GDMUSIC_KEEPONMENU) + gamedata->musicstate = GDMUSIC_NONE; } return; diff --git a/src/m_cond.c b/src/m_cond.c index eca1b5433..d818e0ee5 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -613,7 +613,7 @@ void M_ClearStats(void) gamedata->eversavedreplay = false; gamedata->everseenspecial = false; gamedata->evercrashed = false; - gamedata->musicflags = 0; + gamedata->musicstate = GDMUSIC_NONE; gamedata->importprofilewins = false; } @@ -840,7 +840,8 @@ boolean M_CheckCondition(condition_t *cn, player_t *player) case UC_CRASH: if (gamedata->evercrashed) { - gamedata->musicflags |= GDMUSIC_LOSERCLUB; + if (gamedata->musicstate < GDMUSIC_LOSERCLUB) + gamedata->musicstate = GDMUSIC_LOSERCLUB; return true; } return false; @@ -1710,7 +1711,13 @@ boolean M_UpdateUnlockablesAndExtraEmblems(boolean loud, boolean doall) { gamedata->keyspending++; newkeys++; + } + + if (newkeys != 0) + { response |= true; + if (gamedata->musicstate < GDMUSIC_KEYG) + gamedata->musicstate = GDMUSIC_KEYG; } } diff --git a/src/m_cond.h b/src/m_cond.h index c178b2f5d..2db467e2a 100644 --- a/src/m_cond.h +++ b/src/m_cond.h @@ -220,7 +220,14 @@ typedef enum #endif #define challengegridloops (gamedata->challengegridwidth >= CHALLENGEGRIDLOOPWIDTH) -#define GDMUSIC_LOSERCLUB 0x01 +// See also M_PlayMenuJam +typedef enum { + GDMUSIC_NONE = 0, + GDMUSIC_KEYG, + GDMUSIC_KEEPONMENU, // Minimum to keep after leaving the Challenge Grid + GDMUSIC_LOSERCLUB = GDMUSIC_KEEPONMENU, + GDMUSIC_MAX +} gdmusic_t; // This is the largest number of 9s that will fit in UINT32 and UINT16 respectively. #define GDMAX_RINGS 999999999 @@ -283,7 +290,7 @@ struct gamedata_t boolean eversavedreplay; boolean everseenspecial; boolean evercrashed; - UINT8 musicflags; + gdmusic_t musicstate; // BACKWARDS COMPAT ASSIST boolean importprofilewins; diff --git a/src/p_setup.c b/src/p_setup.c index 023f31773..b082ad037 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -7813,7 +7813,7 @@ static void P_InitGametype(void) // Started a game? Move on to the next jam when you go back to the title screen CV_SetValue(&cv_menujam_update, 1); - gamedata->musicflags = 0; + gamedata->musicstate = GDMUSIC_NONE; } struct minimapinfo minimapinfo; From 04ceb09fd494474a9f66dd896966303be47a4b78 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 7 Jun 2023 23:05:55 +0100 Subject: [PATCH 18/34] Delay wrongwarp music credit until the kayfabe is dropped --- src/menus/extras-wrong.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/menus/extras-wrong.c b/src/menus/extras-wrong.c index a0071a93a..5f40d7168 100644 --- a/src/menus/extras-wrong.c +++ b/src/menus/extras-wrong.c @@ -2,6 +2,7 @@ /// \brief Wrongwarp #include "../k_menu.h" +#include "../s_sound.h" struct wrongwarp_s wrongwarp; @@ -18,11 +19,17 @@ void M_WrongWarp(INT32 choice) MISC_WrongWarpDef.prevMenu = currentMenu; M_SetupNextMenu(&MISC_WrongWarpDef, false); + + // Done here to avoid immediate music credit + S_ChangeMusicInternal("YEAWAY", true); } static void M_WrongWarpTick(void) { wrongwarp.ticker++; + + if (wrongwarp.ticker == 2*TICRATE) + S_ShowMusicCredit(); } static boolean M_WrongWarpInputs(INT32 ch) @@ -43,7 +50,7 @@ menu_t MISC_WrongWarpDef = { 0, 0, 0, 0, MBF_SOUNDLESS, - "YEAWAY", + ".", 98, 0, M_DrawWrongWarp, M_WrongWarpTick, From 4cd1f894a2fb8948f6db45315fcc856937dcfdd7 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 8 Jun 2023 00:56:46 +0100 Subject: [PATCH 19/34] M_DrawCharacterSprite: Refactor for more fine-grained control of sprite2, angle, and animation frame --- src/k_menudraw.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 0e00f927d..42c1cbdaf 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -1390,16 +1390,14 @@ static void M_DrawCharSelectCircle(setup_player_t *p, INT16 x, INT16 y) } // returns false if the character couldn't be rendered -static boolean M_DrawCharacterSprite(INT16 x, INT16 y, INT16 skin, boolean charflip, boolean animate, INT32 addflags, UINT8 *colormap) +static boolean M_DrawCharacterSprite(INT16 x, INT16 y, INT16 skin, UINT8 spr2, UINT8 rotation, UINT32 frame, INT32 addflags, UINT8 *colormap) { UINT8 spr; spritedef_t *sprdef; spriteframe_t *sprframe; patch_t *sprpatch; - UINT8 rotation = (charflip ? 1 : 7); - UINT32 frame = animate ? setup_animcounter : 0; - spr = P_GetSkinSprite2(&skins[skin], SPR2_STIN, NULL); + spr = P_GetSkinSprite2(&skins[skin], spr2, NULL); sprdef = &skins[skin].sprites[spr]; if (!sprdef->numframes) // No frames ?? @@ -1511,7 +1509,7 @@ static void M_DrawCharSelectSprite(UINT8 num, INT16 x, INT16 y, boolean charflip color = p->color; colormap = R_GetTranslationColormap(p->skin, color, GTC_MENUCACHE); - M_DrawCharacterSprite(x, y, p->skin, charflip, (p->mdepth == CSSTEP_READY), 0, colormap); + M_DrawCharacterSprite(x, y, p->skin, SPR2_STIN, (charflip ? 1 : 7), ((p->mdepth == CSSTEP_READY) ? setup_animcounter : 0), 0, colormap); } static void M_DrawCharSelectPreview(UINT8 num) @@ -1880,7 +1878,7 @@ static void M_DrawProfileCard(INT32 x, INT32 y, boolean greyedout, profile_t *p) if (skinnum >= 0) { - if (M_DrawCharacterSprite(x-22, y+119, skinnum, false, false, 0, colormap)) + if (M_DrawCharacterSprite(x-22, y+119, skinnum, SPR2_STIN, 7, 0, 0, colormap)) V_DrawMappedPatch(x+14, y+66, 0, faceprefix[skinnum][FACE_RANK], colormap); } @@ -1912,7 +1910,7 @@ static void M_DrawProfileCard(INT32 x, INT32 y, boolean greyedout, profile_t *p) (K_FollowerUsable(fln) ? TC_DEFAULT : TC_BLINK), col, GTC_MENUCACHE); - if (M_DrawCharacterSprite(x-22, y+119, skinnum, false, false, 0, ccolormap)) + if (M_DrawCharacterSprite(x-22, y+119, skinnum, SPR2_STIN, 7, 0, 0, ccolormap)) { V_DrawMappedPatch(x+14, y+66, 0, faceprefix[skinnum][FACE_RANK], ccolormap); } @@ -5007,7 +5005,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y) if (skin != -1) { colormap = R_GetTranslationColormap(skin, skins[skin].prefcolor, GTC_MENUCACHE); - M_DrawCharacterSprite(x, y, skin, false, false, 0, colormap); + M_DrawCharacterSprite(x, y, skin, SPR2_STIN, 7, 0, 0, colormap); for (i = 0; i < skin; i++) { @@ -5065,7 +5063,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y) if (skin == -1) skin = 0; colormap = R_GetTranslationColormap(TC_BLINK, SKINCOLOR_BLACK, GTC_MENUCACHE); - M_DrawCharacterSprite(x, y, skin, false, false, 0, colormap); + M_DrawCharacterSprite(x, y, skin, SPR2_STIN, 7, 0, 0, colormap); // Draw follower next to them if (fskin != -1) From d7b46b967a87373559bdfa6dc66f240a70673188 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 8 Jun 2023 00:58:27 +0100 Subject: [PATCH 20/34] Wrongwarp: Randomised SMK character drivealong Eggman always leads the pack --- src/k_menu.h | 10 +++++ src/k_menudraw.c | 31 ++++++++++++++ src/menus/extras-wrong.c | 87 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 128 insertions(+) diff --git a/src/k_menu.h b/src/k_menu.h index 7bb9c3399..b7d07db0e 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -1239,8 +1239,18 @@ void M_Statistics(INT32 choice); void M_DrawStatistics(void); boolean M_StatisticsInputs(INT32 ch); +#define MAXWRONGPLAYER MAXSPLITSCREENPLAYERS +#define WRONGPLAYEROFFSCREEN 48 + extern struct wrongwarp_s { INT32 ticker; + tic_t delaytowrongplayer; + struct wrongplayer_s + { + UINT8 skin; + INT16 across; + boolean spinout; + } wrongplayers[MAXWRONGPLAYER]; } wrongwarp; void M_WrongWarp(INT32 choice); diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 42c1cbdaf..c59a75bac 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -5920,6 +5920,26 @@ static INT32 M_WrongWarpFallingHelper(INT32 y, INT32 falltime) return y; } +static void M_DrawWrongPlayer(UINT8 i) +{ +#define wrongpl wrongwarp.wrongplayers[i] + if (wrongpl.skin >= numskins) + return; + + UINT8 *colormap = R_GetTranslationColormap(wrongpl.skin, skins[wrongpl.skin].prefcolor, GTC_MENUCACHE); + + M_DrawCharacterSprite( + wrongpl.across, + 160 - ((i & 1) ? 0 : 32), + wrongpl.skin, + wrongpl.spinout ? SPR2_SPIN : SPR2_SLWN, + wrongpl.spinout ? ((wrongpl.across/8) & 7) : 6, + (wrongwarp.ticker+i), + 0, colormap + ); +#undef wrongpl +} + void M_DrawWrongWarp(void) { INT32 titleoffset = 0, titlewidth, x, y; @@ -5984,6 +6004,17 @@ void M_DrawWrongWarp(void) V_DrawFadeScreen(31, min((wrongwarp.ticker - 2*TICRATE/3), 5)); + // SMK title screen recreation!? + + if (wrongwarp.ticker >= 2*TICRATE) + { + // Done as four calls and not a loop for the sake of render order + M_DrawWrongPlayer(0); + M_DrawWrongPlayer(2); + M_DrawWrongPlayer(1); + M_DrawWrongPlayer(3); + } + y = 20; x = BASEVIDWIDTH - 8; diff --git a/src/menus/extras-wrong.c b/src/menus/extras-wrong.c index 5f40d7168..c820b1888 100644 --- a/src/menus/extras-wrong.c +++ b/src/menus/extras-wrong.c @@ -3,6 +3,8 @@ #include "../k_menu.h" #include "../s_sound.h" +#include "../m_random.h" +#include "../r_skins.h" struct wrongwarp_s wrongwarp; @@ -26,10 +28,95 @@ void M_WrongWarp(INT32 choice) static void M_WrongWarpTick(void) { + static boolean firsteggman = true; + + UINT8 i, j; + wrongwarp.ticker++; + if (wrongwarp.ticker < 2*TICRATE) + return; if (wrongwarp.ticker == 2*TICRATE) + { S_ShowMusicCredit(); + + for (i = 0; i < MAXWRONGPLAYER; i++) + wrongwarp.wrongplayers[i].skin = MAXSKINS; + + firsteggman = true; + } + + // SMK title screen recreation!? + + for (i = 0; i < MAXWRONGPLAYER; i++) + { + if (wrongwarp.wrongplayers[i].skin == MAXSKINS) + continue; + + wrongwarp.wrongplayers[i].across += 5; + if (wrongwarp.wrongplayers[i].across < BASEVIDWIDTH + WRONGPLAYEROFFSCREEN) + continue; + + wrongwarp.wrongplayers[i].skin = MAXSKINS; + } + + if (wrongwarp.delaytowrongplayer) + { + wrongwarp.delaytowrongplayer--; + return; + } + + wrongwarp.delaytowrongplayer = M_RandomRange(TICRATE/3, 2*TICRATE/3); + + if (wrongwarp.ticker == 2*TICRATE) + return; + + UINT32 rskin = 0; + + if (firsteggman == true) + { + // Eggman always leads the pack. It's not Sonic's game anymore... + firsteggman = false; + + i = 0; + wrongwarp.wrongplayers[i].spinout = false; + } + else + { + rskin = R_GetLocalRandomSkin(); + + for (i = 0; i < MAXWRONGPLAYER; i++) + { + // Already in use. + if (wrongwarp.wrongplayers[i].skin == rskin) + return; + + // Slot isn't free. + if (wrongwarp.wrongplayers[i].skin != MAXSKINS) + continue; + + break; + } + + // No free slots. + if (i == MAXWRONGPLAYER) + return; + + // Check to see if any later entry uses the skin too + for (j = i+1; j < MAXWRONGPLAYER; j++) + { + if (wrongwarp.wrongplayers[j].skin != rskin) + continue; + + return; + } + + wrongwarp.wrongplayers[i].spinout = M_RandomChance(FRACUNIT/10); + } + + // Add the new character! + wrongwarp.wrongplayers[i].skin = rskin; + wrongwarp.wrongplayers[i].across = -WRONGPLAYEROFFSCREEN; } static boolean M_WrongWarpInputs(INT32 ch) From fcaf4e2fc20816cd9151deb74409ece008a89d2b Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 8 Jun 2023 13:44:35 +0100 Subject: [PATCH 21/34] Smoother Virtual Keyboard sliding --- src/k_menudraw.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/k_menudraw.c b/src/k_menudraw.c index c59a75bac..2def0ea47 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -393,7 +393,7 @@ static void M_DrawMenuTyping(void) x = (BASEVIDWIDTH - boxwidth)/2; y = 80; if (menutyping.menutypingfade < 9) - y += (9-menutyping.menutypingfade)*10; + y += floor(pow(2, (double)(9 - menutyping.menutypingfade))); else y += (9-menutyping.menutypingfade); @@ -414,8 +414,12 @@ static void M_DrawMenuTyping(void) V_DrawFill(x + 5 + boxwidth - 8, y + 4 + 5, 1, 8+6, 121); V_DrawString(x + 8, y + 12, V_ALLOWLOWERCASE, cv->string); - if (skullAnimCounter < 4) + if (skullAnimCounter < 4 + && menutyping.menutypingclose == false + && menutyping.menutypingfade == (menutyping.keyboardtyping ? 9 : 18)) + { V_DrawCharacter(x + 8 + V_StringWidth(cv->string, 0), y + 12 + 1, '_' | 0x80, false); + } const INT32 buttonwidth = ((boxwidth + 1)/NUMVIRTUALKEYSINROW); #define BUTTONHEIGHT (11) @@ -426,7 +430,12 @@ static void M_DrawMenuTyping(void) if (menutyping.menutypingfade > 9) { - y += 36 + 80 + (9-menutyping.menutypingfade)*10; // double yoffs for animation + y += 26; + + if (menutyping.menutypingfade < 18) + { + y += floor(pow(2, (double)(18 - menutyping.menutypingfade))); // double yoffs for animation + } INT32 tempkeyboardx = menutyping.keyboardx; @@ -575,14 +584,21 @@ static void M_DrawMenuTyping(void) #undef BUTTONHEIGHT + y = 175; + + if (menutyping.menutypingfade < 9) + { + y += 3 * (9 - menutyping.menutypingfade); + } + // Some contextual stuff if (menutyping.keyboardtyping) { - V_DrawThinString(returnx, 175, V_ALLOWLOWERCASE|V_6WIDTHSPACE|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_ALLOWLOWERCASE|V_6WIDTHSPACE|V_GRAYMAP, "Type using your keyboard. Press Enter to confirm & exit.\nUse your controller or any directional input to use the Virtual Keyboard.\n"); } else { - V_DrawThinString(x, 175, V_ALLOWLOWERCASE|V_6WIDTHSPACE|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_ALLOWLOWERCASE|V_6WIDTHSPACE|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."); } } From cb4a876e5a0bac9c88866a19c7010282be955846 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 8 Jun 2023 17:49:17 +0100 Subject: [PATCH 22/34] K_DrawTimeAttack: Use K_drawButtonAnim --- src/k_menudraw.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 2def0ea47..0204063bf 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -2725,16 +2725,10 @@ void M_DrawTimeAttack(void) // SPB Attack control hint + menu overlay if (levellist.newgametype == GT_RACE && levellist.levelsearch.timeattack == true && M_SecretUnlocked(SECRET_SPBATTACK, true)) { - const UINT8 anim_duration = 16; - const UINT8 anim = (timeattackmenu.ticker % (anim_duration * 2)) < anim_duration; - INT32 buttonx = 162 + t; INT32 buttony = timeheight; - if (anim) - V_DrawScaledPatch(buttonx + 35, buttony - 3, V_SNAPTOLEFT, W_CachePatchName("TLB_I", PU_CACHE)); - else - V_DrawScaledPatch(buttonx + 35, buttony - 3, V_SNAPTOLEFT, W_CachePatchName("TLB_IB", PU_CACHE)); + K_drawButtonAnim(buttonx + 35, buttony - 3, V_SNAPTOLEFT, kp_button_r, timeattackmenu.ticker); if ((timeattackmenu.spbflicker == 0 || timeattackmenu.ticker % 2) == (cv_dummyspbattack.value == 1)) { From 2241c443f1d096638132a4eefbb0323b2af7789b Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 8 Jun 2023 17:49:47 +0100 Subject: [PATCH 23/34] K_DrawMenuTyping: Use V_6WIDTHSPACE for header text --- src/k_menudraw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 0204063bf..0c417c6ca 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -399,7 +399,7 @@ static void M_DrawMenuTyping(void) if (currentMenu->menuitems[itemOn].text) { - V_DrawThinString(x + 5, y - 2, highlightflags|V_ALLOWLOWERCASE, currentMenu->menuitems[itemOn].text); + V_DrawThinString(x + 5, y - 2, highlightflags|V_6WIDTHSPACE|V_ALLOWLOWERCASE, currentMenu->menuitems[itemOn].text); } M_DrawMenuTooltips(); From 986ec8025daca2c39f395bec4fdcc0830c2037c0 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 8 Jun 2023 18:28:18 +0100 Subject: [PATCH 24/34] Polish for Wrongwarp - Anti-tailgate measure for the SMK titlescreen recreation (prevents slots on the same row from being used immediately one after the other) - Slightly reduce spinout chance since it felt too frequent --- src/menus/extras-wrong.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/menus/extras-wrong.c b/src/menus/extras-wrong.c index c820b1888..3a68f3878 100644 --- a/src/menus/extras-wrong.c +++ b/src/menus/extras-wrong.c @@ -29,6 +29,7 @@ void M_WrongWarp(INT32 choice) static void M_WrongWarpTick(void) { static boolean firsteggman = true; + static boolean antitailgate = false; UINT8 i, j; @@ -91,6 +92,10 @@ static void M_WrongWarpTick(void) if (wrongwarp.wrongplayers[i].skin == rskin) return; + // Prevent tailgating. + if (antitailgate == !!(i & 1)) + continue; + // Slot isn't free. if (wrongwarp.wrongplayers[i].skin != MAXSKINS) continue; @@ -111,12 +116,14 @@ static void M_WrongWarpTick(void) return; } - wrongwarp.wrongplayers[i].spinout = M_RandomChance(FRACUNIT/10); + wrongwarp.wrongplayers[i].spinout = M_RandomChance(FRACUNIT/11); } // Add the new character! wrongwarp.wrongplayers[i].skin = rskin; wrongwarp.wrongplayers[i].across = -WRONGPLAYEROFFSCREEN; + + antitailgate = !!(i & 1); } static boolean M_WrongWarpInputs(INT32 ch) From aa4c3ab4a2cafac9a41e381f6355d5e464652d8a Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 9 Jun 2023 14:29:31 +0100 Subject: [PATCH 25/34] K_MenuButtonPressed, K_MenuButtonHeld: Return *actual* booleans, not numerical flag values --- src/k_menufunc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/k_menufunc.c b/src/k_menufunc.c index e04675fb2..c7f2f86df 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -807,12 +807,12 @@ boolean M_MenuButtonPressed(UINT8 pid, UINT32 bt) return false; } - return (menucmd[pid].buttons & bt); + return !!(menucmd[pid].buttons & bt); } boolean M_MenuButtonHeld(UINT8 pid, UINT32 bt) { - return (menucmd[pid].buttons & bt); + return !!(menucmd[pid].buttons & bt); } // Returns true if we press the confirmation button From 2949495c76480e6ee1124517b68d945b6091e97e Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 9 Jun 2023 14:32:07 +0100 Subject: [PATCH 26/34] K_drawButton: Explicitly convert boolean inputs to numerical index, instead of assuming false is 0 and true is 1 --- src/k_hud.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_hud.c b/src/k_hud.c index 995877f8d..f958ff6c9 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -4849,7 +4849,7 @@ K_drawMiniPing (void) void K_drawButton(fixed_t x, fixed_t y, INT32 flags, patch_t *button[2], boolean pressed) { - V_DrawFixedPatch(x, y, FRACUNIT, flags, button[pressed], NULL); + V_DrawFixedPatch(x, y, FRACUNIT, flags, button[(pressed == true) ? 1 : 0], NULL); } void K_drawButtonAnim(INT32 x, INT32 y, INT32 flags, patch_t *button[2], tic_t animtic) From da1e865e8b73dcfdac3eb7f5cfb6fdca152e26d0 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 9 Jun 2023 14:37:06 +0100 Subject: [PATCH 27/34] M_DrawChallenges, M_DrawChallengesPreview: Button prompts - Chao Key usage(/skipping unlock animation) - Toggle text for SECRET_ALTTITLE --- src/k_menudraw.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 0c417c6ca..b9d966016 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -5275,8 +5275,13 @@ static void M_DrawChallengePreview(INT32 x, INT32 y) { x = 8; y = BASEVIDHEIGHT-16; - V_DrawGamemodeString(x, y - 32, V_ALLOWLOWERCASE, R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_PLAGUE, GTC_MENUCACHE), cv_alttitle.string); - V_DrawThinString(x, y, V_6WIDTHSPACE|V_ALLOWLOWERCASE|highlightflags, "Press (A)"); + V_DrawGamemodeString(x, y - 33, V_ALLOWLOWERCASE, R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_PLAGUE, GTC_MENUCACHE), cv_alttitle.string); + + K_drawButtonAnim(x, y, 0, kp_button_a[1], challengesmenu.ticker); + x += SHORT(kp_button_a[1][0]->width); + V_DrawThinString(x, y + 1, V_6WIDTHSPACE|V_ALLOWLOWERCASE|highlightflags, "Toggle"); + + break; } default: @@ -5341,6 +5346,8 @@ static void M_DrawChallengePreview(INT32 x, INT32 y) void M_DrawChallenges(void) { + const UINT8 pid = 0; + INT32 x = currentMenu->x, explodex, selectx = 0, selecty = 0; INT32 y; INT16 i, j; @@ -5509,10 +5516,16 @@ challengedesc: fixed_t keyx = (8+offs)*FRACUNIT, keyy = 5*FRACUNIT; - if (!challengesmenu.chaokeyhold) - V_DrawFixedPatch(keyx, keyy, FRACUNIT, 0, key, NULL); + const char *timerstr = va("%u", gamedata->chaokeys); - V_DrawTimerString((27+offs), 9-challengesmenu.unlockcount[CC_CHAOANIM], 0, va("%u", gamedata->chaokeys)); + V_DrawTimerString((27+offs), 9-challengesmenu.unlockcount[CC_CHAOANIM], 0, timerstr); + + K_drawButton( + (27 + offs + V_TimerStringWidth(timerstr, 0) + 2) << FRACBITS, + 11 << FRACBITS, + 0, kp_button_c[1], + M_MenuExtraHeld(pid) + ); offs = challengekeybarwidth; if (gamedata->chaokeys < GDMAX_CHAOKEYS) @@ -6051,7 +6064,7 @@ void M_DrawWrongWarp(void) void M_DrawSoundTest(void) { - UINT8 pid = 0; // todo: Add ability for any splitscreen player to bring up the menu. + const UINT8 pid = 0; INT32 x, y, i, cursorx = 0; INT32 titleoffset = 0, titlewidth; From bf5aa4b5d820ca7da7caba480774088d9bf5804e Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 9 Jun 2023 16:42:44 +0100 Subject: [PATCH 28/34] M_GetNextAchievedUnlock: Skip over adding Chao Keys if you've already unlocked everything I considered restricting it even further to "unlock every minor unlock that can be unlocked by a Chao Key", but decided that if you haven't "completed the game" yet, you should still be periodically reminded of it. --- src/m_cond.c | 21 ++++++++++++++++++--- src/m_cond.h | 2 +- src/menus/extras-challenges.c | 4 ++-- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/m_cond.c b/src/m_cond.c index d818e0ee5..c0dd67e60 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -1780,32 +1780,47 @@ boolean M_UpdateUnlockablesAndExtraEmblems(boolean loud, boolean doall) return false; } -UINT16 M_GetNextAchievedUnlock(void) +UINT16 M_GetNextAchievedUnlock(boolean canskipchaokeys) { UINT16 i; // Go through unlockables for (i = 0; i < MAXUNLOCKABLES; ++i) { - if (gamedata->unlocked[i] || !unlockables[i].conditionset) + if (!unlockables[i].conditionset) { + // Not worthy of consideration continue; } if (gamedata->unlocked[i] == true) { + // Already unlocked, no need to engage continue; } if (gamedata->unlockpending[i] == false) { + // Not unlocked AND not pending, which means chao keys can be used on something + canskipchaokeys = false; continue; } return i; } - if (gamedata->keyspending != 0) + if (canskipchaokeys == true) + { + // Okay, we're skipping chao keys - let's just insta-digest them. + gamedata->chaokeys += gamedata->keyspending; + gamedata->pendingkeyroundoffset = + (gamedata->pendingkeyroundoffset + gamedata->pendingkeyrounds) + % GDCONVERT_ROUNDSTOKEY; + + gamedata->keyspending = 0; + gamedata->pendingkeyrounds = 0; + } + else if (gamedata->keyspending != 0) { return PENDING_CHAOKEYS; } diff --git a/src/m_cond.h b/src/m_cond.h index 2db467e2a..beb12d039 100644 --- a/src/m_cond.h +++ b/src/m_cond.h @@ -347,7 +347,7 @@ boolean M_CheckCondition(condition_t *cn, player_t *player); boolean M_UpdateUnlockablesAndExtraEmblems(boolean loud, boolean doall); #define PENDING_CHAOKEYS (UINT16_MAX-1) -UINT16 M_GetNextAchievedUnlock(void); +UINT16 M_GetNextAchievedUnlock(boolean canskipchaokeys); UINT16 M_CheckLevelEmblems(void); UINT16 M_CompletionEmblems(void); diff --git a/src/menus/extras-challenges.c b/src/menus/extras-challenges.c index 51cddb8a1..8b8409141 100644 --- a/src/menus/extras-challenges.c +++ b/src/menus/extras-challenges.c @@ -212,7 +212,7 @@ menu_t *M_InterruptMenuWithChallenges(menu_t *desiredmenu) M_UpdateUnlockablesAndExtraEmblems(false, true); - newunlock = M_GetNextAchievedUnlock(); + newunlock = M_GetNextAchievedUnlock(true); if ((challengesmenu.pending = (newunlock != MAXUNLOCKABLES))) { @@ -457,7 +457,7 @@ void M_ChallengesTick(void) { // The menu apparatus is requesting a new unlock. challengesmenu.requestnew = false; - if ((newunlock = M_GetNextAchievedUnlock()) != MAXUNLOCKABLES) + if ((newunlock = M_GetNextAchievedUnlock(false)) != MAXUNLOCKABLES) { // We got one! M_ChallengesAutoFocus(newunlock, false); From 7c91f768d8917882ff632e21c5f4489abef42070 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 9 Jun 2023 16:55:00 +0100 Subject: [PATCH 29/34] Move GDMUSIC_KEYG set to Challenges Menu key addition rather than gamedata, to behave across gameboots --- src/m_cond.c | 6 ------ src/menus/extras-challenges.c | 3 +++ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/m_cond.c b/src/m_cond.c index c0dd67e60..d1fd454d7 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -1711,13 +1711,7 @@ boolean M_UpdateUnlockablesAndExtraEmblems(boolean loud, boolean doall) { gamedata->keyspending++; newkeys++; - } - - if (newkeys != 0) - { response |= true; - if (gamedata->musicstate < GDMUSIC_KEYG) - gamedata->musicstate = GDMUSIC_KEYG; } } diff --git a/src/menus/extras-challenges.c b/src/menus/extras-challenges.c index 8b8409141..1fa4a3f86 100644 --- a/src/menus/extras-challenges.c +++ b/src/menus/extras-challenges.c @@ -449,6 +449,9 @@ void M_ChallengesTick(void) gamedata->keyspending--; gamedata->chaokeys++; challengesmenu.unlockcount[CC_CHAOANIM]++; + + if (gamedata->musicstate < GDMUSIC_KEYG) + gamedata->musicstate = GDMUSIC_KEYG; } } } From 7d4efd6629b53e190cc4acbcf5d40bfeac0221ce Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 9 Jun 2023 17:27:31 +0100 Subject: [PATCH 30/34] M_GetNextAchievedUnlock: Correctly handle reaching the Chao Key limit --- src/m_cond.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/m_cond.c b/src/m_cond.c index d1fd454d7..1bbdef711 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -1806,10 +1806,20 @@ UINT16 M_GetNextAchievedUnlock(boolean canskipchaokeys) if (canskipchaokeys == true) { // Okay, we're skipping chao keys - let's just insta-digest them. - gamedata->chaokeys += gamedata->keyspending; - gamedata->pendingkeyroundoffset = - (gamedata->pendingkeyroundoffset + gamedata->pendingkeyrounds) - % GDCONVERT_ROUNDSTOKEY; + + if (gamedata->chaokeys + gamedata->keyspending < GDMAX_CHAOKEYS) + { + gamedata->chaokeys += gamedata->keyspending; + gamedata->pendingkeyroundoffset = + (gamedata->pendingkeyroundoffset + gamedata->pendingkeyrounds) + % GDCONVERT_ROUNDSTOKEY; + + } + else + { + gamedata->chaokeys = GDMAX_CHAOKEYS; + gamedata->pendingkeyroundoffset = 0; + } gamedata->keyspending = 0; gamedata->pendingkeyrounds = 0; From 341db75d34f0ce0cb1bbf0536d06d28d0a04bf29 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 9 Jun 2023 17:40:14 +0100 Subject: [PATCH 31/34] Wrongwarp: Back to title on closure --- src/menus/extras-challenges.c | 4 ++-- src/menus/extras-wrong.c | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/menus/extras-challenges.c b/src/menus/extras-challenges.c index 1fa4a3f86..c254a14a2 100644 --- a/src/menus/extras-challenges.c +++ b/src/menus/extras-challenges.c @@ -373,7 +373,7 @@ void M_ChallengesTick(void) if (challengesmenu.chaokeyhold > CHAOHOLD_MAX) { - gamedata->chaokeys--; + //gamedata->chaokeys--; challengesmenu.chaokeyhold = 0; challengesmenu.unlockcount[CC_CHAOANIM]++; @@ -600,7 +600,7 @@ boolean M_ChallengesInputs(INT32 ch) challengesmenu.unlockcount[CC_CHAONOPE] = 6; S_StartSound(NULL, sfx_s3k7b); //sfx_s3kb2 -#if 0 // debugging +#if 1 // debugging if (challengesmenu.currentunlock < MAXUNLOCKABLES && challengesmenu.unlockanim >= UNLOCKTIME && gamedata->unlocked[challengesmenu.currentunlock] == true) { gamedata->unlocked[challengesmenu.currentunlock] = gamedata->unlockpending[challengesmenu.currentunlock] = false; diff --git a/src/menus/extras-wrong.c b/src/menus/extras-wrong.c index 3a68f3878..4d4befc22 100644 --- a/src/menus/extras-wrong.c +++ b/src/menus/extras-wrong.c @@ -19,7 +19,6 @@ void M_WrongWarp(INT32 choice) wrongwarp.ticker = 0; - MISC_WrongWarpDef.prevMenu = currentMenu; M_SetupNextMenu(&MISC_WrongWarpDef, false); // Done here to avoid immediate music credit @@ -138,7 +137,7 @@ static boolean M_WrongWarpInputs(INT32 ch) menu_t MISC_WrongWarpDef = { sizeof (MISC_WrongWarpMenu)/sizeof (menuitem_t), - &MainDef, + NULL, 0, MISC_WrongWarpMenu, 0, 0, From ff089afad1b21926a85b660d47866ded56a1988c Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 9 Jun 2023 18:36:48 +0100 Subject: [PATCH 32/34] S_StopSoundByID: Permit NULL origin to be stopped manually --- src/s_sound.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/s_sound.c b/src/s_sound.c index e218870e5..854b65e48 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -363,8 +363,12 @@ void S_StopSoundByID(void *origin, sfxenum_t sfx_id) // Sounds without origin can have multiple sources, they shouldn't // be stopped by new sounds. + // (The above comment predates this codebase using git and cannot be BLAME'd) + // ...yeah, but if it's being stopped by ID, it's clearly an intentful effect. ~toast 090623 +#if 0 if (!origin) return; +#endif #ifdef HW3SOUND if (hws_mode != HWS_DEFAULT_MODE) { From e235f29dfe0a642129c987673429610faa18443d Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 9 Jun 2023 18:39:00 +0100 Subject: [PATCH 33/34] Sounds for Roundqueue Board, which is what I've decided I'm calling the thing at the bottom of Intermission under roundqueue conditions now - Landing sound when doing a hop (uses a Knuckles Chaotix sound, maybe temporary) - Meter fill sound when checking Rank for Sealed Star - Stopping early when Rank is too low (same sound as Landing, potentially temporary if someone gets inspired) --- src/sounds.c | 1 + src/sounds.h | 1 + src/y_inter.c | 29 +++++++++++++++++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/src/sounds.c b/src/sounds.c index 85b111a50..9e2702a10 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -1102,6 +1102,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"typri2", false, 64, 16, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // SA2 final boss-type typewriting {"eggspr", false, 64, 16, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Sonic Unleashed Trap Spring {"achiev", false, 204, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Achievement"}, + {"gpmetr", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // End of a "Tutorial Teleport" {"endwrp", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // End of a "Tutorial Teleport" // SRB2Kart - Drop target sounds diff --git a/src/sounds.h b/src/sounds.h index a2f786030..a3a72c6a7 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -1169,6 +1169,7 @@ typedef enum sfx_typri2, sfx_eggspr, sfx_achiev, + sfx_gpmetr, sfx_endwrp, // SRB2Kart - Drop target sounds diff --git a/src/y_inter.c b/src/y_inter.c index e90ab6cd3..54e301db6 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -1498,6 +1498,35 @@ void Y_Ticker(void) return; } + // Animation sounds for roundqueue, see Y_RoundQueueDrawer + if (roundqueue.size != 0 + && roundqueue.position != 0 + && (timer - 1) <= 2*TICRATE) + { + const INT32 through = ((2*TICRATE) - (timer - 1)); + + if (data.showrank == true + && roundqueue.position == roundqueue.size-1) + { + // Handle special entry on the end + if (through == data.linemeter && timer > 2) + { + S_StopSoundByID(NULL, sfx_gpmetr); + S_StartSound(NULL, sfx_kc50); + } + else if (through == 0) + { + S_StartSound(NULL, sfx_gpmetr); + } + } + else if (through == 9 + && roundqueue.position < roundqueue.size) + { + // Impactful landing + S_StartSound(NULL, sfx_kc50); + } + } + if (intertic < TICRATE || endtic != -1) { return; From 874e9642253a3890caa6ae80a73d9837261f44ff Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 9 Jun 2023 19:19:55 +0100 Subject: [PATCH 34/34] Revert accidentially committed repeatable debug behaviour for Chao Keys, and guard it behind a single #define --- src/menus/extras-challenges.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/menus/extras-challenges.c b/src/menus/extras-challenges.c index c254a14a2..5c50c4eef 100644 --- a/src/menus/extras-challenges.c +++ b/src/menus/extras-challenges.c @@ -8,6 +8,8 @@ #include "../r_skins.h" #include "../s_sound.h" +//#define CHAOKEYDEBUG + menuitem_t MISC_ChallengesStatsDummyMenu[] = { {IT_STRING | IT_CALL, "Back", NULL, NULL, {.routine = M_GoBack}, 0, 0}, @@ -373,7 +375,9 @@ void M_ChallengesTick(void) if (challengesmenu.chaokeyhold > CHAOHOLD_MAX) { - //gamedata->chaokeys--; +#ifndef CHAOKEYDEBUG + gamedata->chaokeys--; +#endif challengesmenu.chaokeyhold = 0; challengesmenu.unlockcount[CC_CHAOANIM]++; @@ -600,7 +604,7 @@ boolean M_ChallengesInputs(INT32 ch) challengesmenu.unlockcount[CC_CHAONOPE] = 6; S_StartSound(NULL, sfx_s3k7b); //sfx_s3kb2 -#if 1 // debugging +#ifdef CHAOKEYDEBUG if (challengesmenu.currentunlock < MAXUNLOCKABLES && challengesmenu.unlockanim >= UNLOCKTIME && gamedata->unlocked[challengesmenu.currentunlock] == true) { gamedata->unlocked[challengesmenu.currentunlock] = gamedata->unlockpending[challengesmenu.currentunlock] = false;