From 87b80a62f2b2963351f9b51a5484dd4f14d8555e Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 5 Mar 2023 20:48:31 +0000 Subject: [PATCH] SPB Attack: Integrate into `conditions-cascading` affairs - All `cv_dummyspbattack`-related material is now gated with the assistance of SECRET_SPBATTACK. - SPB_ATTACK - Add UC_MAPSPBATTACK condition. - Both this and emblems with MV_SPBATTACK have the string "SPB ATTACK: Conquer [LEVEL NAME]", compared to the regular round completion conditions having "Finish a round on [LEVEL NAME]". - If SPBATTACK is not unlocked, shows ???: Conquer [LEVEL NAME] instead --- src/deh_soc.c | 5 +++- src/k_menudraw.c | 28 +++++++++++++++++--- src/m_cond.c | 34 ++++++++++++++++++++++--- src/m_cond.h | 2 ++ src/menus/play-local-race-time-attack.c | 14 +++++++--- src/menus/transient/level-select.c | 5 ++-- 6 files changed, 74 insertions(+), 14 deletions(-) diff --git a/src/deh_soc.c b/src/deh_soc.c index 9f796ec7a..d3686f6c7 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -2290,6 +2290,8 @@ void readunlockable(MYFILE *f, INT32 num) unlockables[num].type = SECRET_BREAKTHECAPSULES; else if (fastcmp(word2, "SPECIALATTACK")) unlockables[num].type = SECRET_SPECIALATTACK; + else if (fastcmp(word2, "SPBATTACK")) + unlockables[num].type = SECRET_SPBATTACK; else if (fastcmp(word2, "ONLINE")) unlockables[num].type = SECRET_ONLINE; else if (fastcmp(word2, "ADDONS")) @@ -2445,7 +2447,8 @@ static void readcondition(UINT8 set, UINT32 id, char *word2) } else if ((offset=0) || fastcmp(params[0], "MAPVISITED") || (++offset && fastcmp(params[0], "MAPBEATEN")) - || (++offset && fastcmp(params[0], "MAPENCORE"))) + || (++offset && fastcmp(params[0], "MAPENCORE")) + || (++offset && fastcmp(params[0], "MAPSPBATTACK"))) { PARAMCHECK(1); ty = UC_MAPVISITED + offset; diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 2ff0301c1..ebe9a6b17 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -2384,7 +2384,7 @@ void M_DrawTimeAttack(void) K_drawKartTimestamp(timerec, 162+t, timeheight+6, 0, 1); // SPB Attack control hint + menu overlay - if (levellist.newgametype == GT_RACE && levellist.levelsearch.timeattack == true) + 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; @@ -2397,10 +2397,9 @@ void M_DrawTimeAttack(void) else V_DrawScaledPatch(buttonx + 35, buttony - 3, V_SNAPTOLEFT, W_CachePatchName("TLB_IB", PU_CACHE)); - if (timeattackmenu.ticker > (timeattackmenu.spbflicker + TICRATE/6) || timeattackmenu.ticker % 2) + if ((timeattackmenu.spbflicker == 0 || timeattackmenu.ticker % 2) == (cv_dummyspbattack.value == 1)) { - if (cv_dummyspbattack.value) - V_DrawMappedPatch(buttonx + 7, buttony - 1, 0, W_CachePatchName("K_SPBATK", PU_CACHE), R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_RED, GTC_MENUCACHE)); + V_DrawMappedPatch(buttonx + 7, buttony - 1, 0, W_CachePatchName("K_SPBATK", PU_CACHE), R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_RED, GTC_MENUCACHE)); } } @@ -4760,6 +4759,7 @@ static void M_DrawChallengeTile(INT16 i, INT16 j, INT32 x, INT32 y, boolean hili case SECRET_TIMEATTACK: case SECRET_BREAKTHECAPSULES: case SECRET_SPECIALATTACK: + case SECRET_SPBATTACK: categoryid = '7'; break; } @@ -4845,6 +4845,9 @@ static void M_DrawChallengeTile(INT16 i, INT16 j, INT32 x, INT32 y, boolean hili case SECRET_SPECIALATTACK: iconid = 9; break; + case SECRET_SPBATTACK: + iconid = 0; // TEMPORARY + break; default: { @@ -5062,6 +5065,16 @@ static void M_DrawChallengePreview(INT32 x, INT32 y) specialmap = sscmapcache; break; } + case SECRET_SPBATTACK: + { + static UINT16 spbmapcache = NEXTMAP_INVALID; + if (spbmapcache > nummapheaders) + { + spbmapcache = G_RandMap(G_TOLFlag(GT_RACE), -1, 2, 0, false, NULL); + } + specialmap = spbmapcache; + break; + } case SECRET_HARDSPEED: { static UINT16 hardmapcache = NEXTMAP_INVALID; @@ -5124,6 +5137,13 @@ static void M_DrawChallengePreview(INT32 x, INT32 y) V_DrawFixedPatch((x+40)<type == SECRET_SPBATTACK) + { + V_DrawFixedPatch((x+40-25)<type == SECRET_HARDSPEED) { V_DrawFixedPatch((x+40-25)<type == UC_MAPBEATEN) mvtype = MV_BEATEN; else if (cn->type == UC_MAPENCORE) mvtype = MV_ENCORE; + else if (cn->type == UC_MAPSPBATTACK) + mvtype = MV_SPBATTACK; return ((cn->requirement < nummapheaders) && (mapheaderinfo[cn->requirement]) @@ -928,13 +931,29 @@ static const char *M_GetConditionString(condition_t *cn) case UC_MAPVISITED: // Requires map x to be visited case UC_MAPBEATEN: // Requires map x to be beaten case UC_MAPENCORE: // Requires map x to be beaten in encore + case UC_MAPSPBATTACK: // Requires map x to be beaten in SPB Attack { + const char *prefix = ""; + if (cn->requirement >= nummapheaders || !mapheaderinfo[cn->requirement]) return va("INVALID MAP CONDITION \"%d:%d\"", cn->type, cn->requirement); title = BUILDCONDITIONTITLE(cn->requirement); - work = va("%s %s%s", - (cn->type == UC_MAPVISITED) ? "Visit" : "Finish a round on", + + if (cn->type == UC_MAPSPBATTACK) + prefix = (M_SecretUnlocked(SECRET_SPBATTACK, true) ? "SPB ATTACK: " : "???: "); + else if (cn->type == UC_MAPENCORE) + prefix = (M_SecretUnlocked(SECRET_ENCORE, true) ? "ENCORE MODE: " : "???: "); + + work = "Finish a round on"; + if (cn->type == UC_MAPVISITED) + work = "Visit"; + else if (cn->type == UC_MAPSPBATTACK) + work = "Conquer"; + + work = va("%s%s %s%s", + prefix, + work, title, (cn->type == UC_MAPENCORE) ? " in Encore Mode" : ""); Z_Free(title); @@ -973,7 +992,16 @@ static const char *M_GetConditionString(condition_t *cn) switch (emblemlocations[i].type) { case ET_MAP: - work = va("Beat %s", title); + work = ""; + if (emblemlocations[i].flags & ME_SPBATTACK) + work = (M_SecretUnlocked(SECRET_SPBATTACK, true) ? "SPB ATTACK: " : "???: "); + else if (emblemlocations[i].flags & ME_ENCORE) + work = (M_SecretUnlocked(SECRET_ENCORE, true) ? "ENCORE MODE: " : "???: "); + + work = va("%s%s %s", + work, + (emblemlocations[i].flags & ME_SPBATTACK) ? "Conquer" : "Finish a round on", + title); break; case ET_TIME: if (emblemlocations[i].color <= 0 || emblemlocations[i].color >= numskincolors) diff --git a/src/m_cond.h b/src/m_cond.h index 0b51b0130..bf826f210 100644 --- a/src/m_cond.h +++ b/src/m_cond.h @@ -37,6 +37,7 @@ typedef enum UC_MAPVISITED, // MAPVISITED [map] UC_MAPBEATEN, // MAPBEATEN [map] UC_MAPENCORE, // MAPENCORE [map] + UC_MAPSPBATTACK, // MAPSPBATTACK [map] UC_MAPTIME, // MAPTIME [map] [time to beat, tics] UC_TRIGGER, // TRIGGER [trigger number] UC_TOTALMEDALS, // TOTALMEDALS [number of emblems] @@ -160,6 +161,7 @@ typedef enum SECRET_TIMEATTACK, // Permit Time attack SECRET_BREAKTHECAPSULES, // Permit SP Capsule attack SECRET_SPECIALATTACK, // Permit Special attack (You're blue now!) + SECRET_SPBATTACK, // Permit SPB mode of Time attack // Option restrictions SECRET_ONLINE, // Permit netplay (ankle-high barrier to jumping in the deep end) diff --git a/src/menus/play-local-race-time-attack.c b/src/menus/play-local-race-time-attack.c index abdff5762..4c51a2a6c 100644 --- a/src/menus/play-local-race-time-attack.c +++ b/src/menus/play-local-race-time-attack.c @@ -9,6 +9,7 @@ #include "../d_main.h" // srb2home #include "../m_misc.h" // M_MkdirEach #include "../z_zone.h" // Z_StrDup/Z_Free +#include "../m_cond.h" static void CV_SPBAttackChanged(void) { @@ -21,7 +22,11 @@ struct timeattackmenu_s timeattackmenu; void M_TimeAttackTick(void) { - timeattackmenu.ticker++; + timeattackmenu.ticker++; + if (timeattackmenu.spbflicker > 0) + { + timeattackmenu.spbflicker--; + } } boolean M_TimeAttackInputs(INT32 ch) @@ -30,10 +35,10 @@ boolean M_TimeAttackInputs(INT32 ch) const boolean buttonR = M_MenuButtonPressed(pid, MBT_R); (void) ch; - if (buttonR && levellist.newgametype == GT_RACE) + if (buttonR && levellist.newgametype == GT_RACE && M_SecretUnlocked(SECRET_SPBATTACK, true)) { CV_AddValue(&cv_dummyspbattack, 1); - timeattackmenu.spbflicker = timeattackmenu.ticker; + timeattackmenu.spbflicker = TICRATE/6; if (cv_dummyspbattack.value) { S_StartSound(NULL, sfx_s3k9f); @@ -231,6 +236,9 @@ void M_PrepareTimeAttack(INT32 choice) } } + if (levellist.levelsearch.timeattack == false || levellist.newgametype != GT_RACE || !M_SecretUnlocked(SECRET_SPBATTACK, true)) + CV_SetValue(&cv_dummyspbattack, 0); + // Time-sticker Medals G_UpdateTimeStickerMedals(levellist.choosemap, false); diff --git a/src/menus/transient/level-select.c b/src/menus/transient/level-select.c index 20442ceb6..a8f4203af 100644 --- a/src/menus/transient/level-select.c +++ b/src/menus/transient/level-select.c @@ -227,12 +227,11 @@ boolean M_LevelListFromGametype(INT16 gt) levellist.levelsearch.cupmode = (!(gametypes[gt]->rules & GTR_NOCUPSELECT)); + CV_SetValue(&cv_dummyspbattack, 0); + first = false; } - if (levellist.levelsearch.timeattack == false || levellist.newgametype != GT_RACE) - CV_SetValue(&cv_dummyspbattack, 0); - // Obviously go to Cup Select in gametypes that have cups. // Use a really long level select in gametypes that don't use cups.