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
This commit is contained in:
toaster 2023-03-05 20:48:31 +00:00
parent 99b5fe7bf4
commit 87b80a62f2
6 changed files with 74 additions and 14 deletions

View file

@ -2290,6 +2290,8 @@ void readunlockable(MYFILE *f, INT32 num)
unlockables[num].type = SECRET_BREAKTHECAPSULES; unlockables[num].type = SECRET_BREAKTHECAPSULES;
else if (fastcmp(word2, "SPECIALATTACK")) else if (fastcmp(word2, "SPECIALATTACK"))
unlockables[num].type = SECRET_SPECIALATTACK; unlockables[num].type = SECRET_SPECIALATTACK;
else if (fastcmp(word2, "SPBATTACK"))
unlockables[num].type = SECRET_SPBATTACK;
else if (fastcmp(word2, "ONLINE")) else if (fastcmp(word2, "ONLINE"))
unlockables[num].type = SECRET_ONLINE; unlockables[num].type = SECRET_ONLINE;
else if (fastcmp(word2, "ADDONS")) 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") else if ((offset=0) || fastcmp(params[0], "MAPVISITED")
|| (++offset && fastcmp(params[0], "MAPBEATEN")) || (++offset && fastcmp(params[0], "MAPBEATEN"))
|| (++offset && fastcmp(params[0], "MAPENCORE"))) || (++offset && fastcmp(params[0], "MAPENCORE"))
|| (++offset && fastcmp(params[0], "MAPSPBATTACK")))
{ {
PARAMCHECK(1); PARAMCHECK(1);
ty = UC_MAPVISITED + offset; ty = UC_MAPVISITED + offset;

View file

@ -2384,7 +2384,7 @@ void M_DrawTimeAttack(void)
K_drawKartTimestamp(timerec, 162+t, timeheight+6, 0, 1); K_drawKartTimestamp(timerec, 162+t, timeheight+6, 0, 1);
// SPB Attack control hint + menu overlay // 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_duration = 16;
const UINT8 anim = (timeattackmenu.ticker % (anim_duration * 2)) < anim_duration; const UINT8 anim = (timeattackmenu.ticker % (anim_duration * 2)) < anim_duration;
@ -2397,10 +2397,9 @@ void M_DrawTimeAttack(void)
else else
V_DrawScaledPatch(buttonx + 35, buttony - 3, V_SNAPTOLEFT, W_CachePatchName("TLB_IB", PU_CACHE)); 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_TIMEATTACK:
case SECRET_BREAKTHECAPSULES: case SECRET_BREAKTHECAPSULES:
case SECRET_SPECIALATTACK: case SECRET_SPECIALATTACK:
case SECRET_SPBATTACK:
categoryid = '7'; categoryid = '7';
break; break;
} }
@ -4845,6 +4845,9 @@ static void M_DrawChallengeTile(INT16 i, INT16 j, INT32 x, INT32 y, boolean hili
case SECRET_SPECIALATTACK: case SECRET_SPECIALATTACK:
iconid = 9; iconid = 9;
break; break;
case SECRET_SPBATTACK:
iconid = 0; // TEMPORARY
break;
default: default:
{ {
@ -5062,6 +5065,16 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
specialmap = sscmapcache; specialmap = sscmapcache;
break; 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: case SECRET_HARDSPEED:
{ {
static UINT16 hardmapcache = NEXTMAP_INVALID; static UINT16 hardmapcache = NEXTMAP_INVALID;
@ -5124,6 +5137,13 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
V_DrawFixedPatch((x+40)<<FRACBITS, ((y+25)<<FRACBITS) - (rubyheight<<1), FRACUNIT, 0, W_CachePatchName("RUBYICON", PU_CACHE), NULL); V_DrawFixedPatch((x+40)<<FRACBITS, ((y+25)<<FRACBITS) - (rubyheight<<1), FRACUNIT, 0, W_CachePatchName("RUBYICON", PU_CACHE), NULL);
rubyfloattime += FixedMul(ANGLE_MAX/NEWTICRATE, renderdeltatics); rubyfloattime += FixedMul(ANGLE_MAX/NEWTICRATE, renderdeltatics);
} }
else if (ref->type == SECRET_SPBATTACK)
{
V_DrawFixedPatch((x+40-25)<<FRACBITS, ((y+25-25)<<FRACBITS),
FRACUNIT, 0,
W_CachePatchName(K_GetItemPatch(KITEM_SPB, false), PU_CACHE),
NULL);
}
else if (ref->type == SECRET_HARDSPEED) else if (ref->type == SECRET_HARDSPEED)
{ {
V_DrawFixedPatch((x+40-25)<<FRACBITS, ((y+25-25)<<FRACBITS), V_DrawFixedPatch((x+40-25)<<FRACBITS, ((y+25-25)<<FRACBITS),

View file

@ -674,12 +674,15 @@ boolean M_CheckCondition(condition_t *cn, player_t *player)
case UC_MAPVISITED: // Requires map x to be visited case UC_MAPVISITED: // Requires map x to be visited
case UC_MAPBEATEN: // Requires map x to be beaten case UC_MAPBEATEN: // Requires map x to be beaten
case UC_MAPENCORE: // Requires map x to be beaten in encore case UC_MAPENCORE: // Requires map x to be beaten in encore
case UC_MAPSPBATTACK: // Requires map x to be beaten in SPB Attack
{ {
UINT8 mvtype = MV_VISITED; UINT8 mvtype = MV_VISITED;
if (cn->type == UC_MAPBEATEN) if (cn->type == UC_MAPBEATEN)
mvtype = MV_BEATEN; mvtype = MV_BEATEN;
else if (cn->type == UC_MAPENCORE) else if (cn->type == UC_MAPENCORE)
mvtype = MV_ENCORE; mvtype = MV_ENCORE;
else if (cn->type == UC_MAPSPBATTACK)
mvtype = MV_SPBATTACK;
return ((cn->requirement < nummapheaders) return ((cn->requirement < nummapheaders)
&& (mapheaderinfo[cn->requirement]) && (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_MAPVISITED: // Requires map x to be visited
case UC_MAPBEATEN: // Requires map x to be beaten case UC_MAPBEATEN: // Requires map x to be beaten
case UC_MAPENCORE: // Requires map x to be beaten in encore 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]) if (cn->requirement >= nummapheaders || !mapheaderinfo[cn->requirement])
return va("INVALID MAP CONDITION \"%d:%d\"", cn->type, cn->requirement); return va("INVALID MAP CONDITION \"%d:%d\"", cn->type, cn->requirement);
title = BUILDCONDITIONTITLE(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, title,
(cn->type == UC_MAPENCORE) ? " in Encore Mode" : ""); (cn->type == UC_MAPENCORE) ? " in Encore Mode" : "");
Z_Free(title); Z_Free(title);
@ -973,7 +992,16 @@ static const char *M_GetConditionString(condition_t *cn)
switch (emblemlocations[i].type) switch (emblemlocations[i].type)
{ {
case ET_MAP: 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; break;
case ET_TIME: case ET_TIME:
if (emblemlocations[i].color <= 0 || emblemlocations[i].color >= numskincolors) if (emblemlocations[i].color <= 0 || emblemlocations[i].color >= numskincolors)

View file

@ -37,6 +37,7 @@ typedef enum
UC_MAPVISITED, // MAPVISITED [map] UC_MAPVISITED, // MAPVISITED [map]
UC_MAPBEATEN, // MAPBEATEN [map] UC_MAPBEATEN, // MAPBEATEN [map]
UC_MAPENCORE, // MAPENCORE [map] UC_MAPENCORE, // MAPENCORE [map]
UC_MAPSPBATTACK, // MAPSPBATTACK [map]
UC_MAPTIME, // MAPTIME [map] [time to beat, tics] UC_MAPTIME, // MAPTIME [map] [time to beat, tics]
UC_TRIGGER, // TRIGGER [trigger number] UC_TRIGGER, // TRIGGER [trigger number]
UC_TOTALMEDALS, // TOTALMEDALS [number of emblems] UC_TOTALMEDALS, // TOTALMEDALS [number of emblems]
@ -160,6 +161,7 @@ typedef enum
SECRET_TIMEATTACK, // Permit Time attack SECRET_TIMEATTACK, // Permit Time attack
SECRET_BREAKTHECAPSULES, // Permit SP Capsule attack SECRET_BREAKTHECAPSULES, // Permit SP Capsule attack
SECRET_SPECIALATTACK, // Permit Special attack (You're blue now!) SECRET_SPECIALATTACK, // Permit Special attack (You're blue now!)
SECRET_SPBATTACK, // Permit SPB mode of Time attack
// Option restrictions // Option restrictions
SECRET_ONLINE, // Permit netplay (ankle-high barrier to jumping in the deep end) SECRET_ONLINE, // Permit netplay (ankle-high barrier to jumping in the deep end)

View file

@ -9,6 +9,7 @@
#include "../d_main.h" // srb2home #include "../d_main.h" // srb2home
#include "../m_misc.h" // M_MkdirEach #include "../m_misc.h" // M_MkdirEach
#include "../z_zone.h" // Z_StrDup/Z_Free #include "../z_zone.h" // Z_StrDup/Z_Free
#include "../m_cond.h"
static void CV_SPBAttackChanged(void) static void CV_SPBAttackChanged(void)
{ {
@ -21,7 +22,11 @@ struct timeattackmenu_s timeattackmenu;
void M_TimeAttackTick(void) void M_TimeAttackTick(void)
{ {
timeattackmenu.ticker++; timeattackmenu.ticker++;
if (timeattackmenu.spbflicker > 0)
{
timeattackmenu.spbflicker--;
}
} }
boolean M_TimeAttackInputs(INT32 ch) boolean M_TimeAttackInputs(INT32 ch)
@ -30,10 +35,10 @@ boolean M_TimeAttackInputs(INT32 ch)
const boolean buttonR = M_MenuButtonPressed(pid, MBT_R); const boolean buttonR = M_MenuButtonPressed(pid, MBT_R);
(void) ch; (void) ch;
if (buttonR && levellist.newgametype == GT_RACE) if (buttonR && levellist.newgametype == GT_RACE && M_SecretUnlocked(SECRET_SPBATTACK, true))
{ {
CV_AddValue(&cv_dummyspbattack, 1); CV_AddValue(&cv_dummyspbattack, 1);
timeattackmenu.spbflicker = timeattackmenu.ticker; timeattackmenu.spbflicker = TICRATE/6;
if (cv_dummyspbattack.value) if (cv_dummyspbattack.value)
{ {
S_StartSound(NULL, sfx_s3k9f); 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 // Time-sticker Medals
G_UpdateTimeStickerMedals(levellist.choosemap, false); G_UpdateTimeStickerMedals(levellist.choosemap, false);

View file

@ -227,12 +227,11 @@ boolean M_LevelListFromGametype(INT16 gt)
levellist.levelsearch.cupmode = (!(gametypes[gt]->rules & GTR_NOCUPSELECT)); levellist.levelsearch.cupmode = (!(gametypes[gt]->rules & GTR_NOCUPSELECT));
CV_SetValue(&cv_dummyspbattack, 0);
first = false; 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. // Obviously go to Cup Select in gametypes that have cups.
// Use a really long level select in gametypes that don't use cups. // Use a really long level select in gametypes that don't use cups.