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;
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;

View file

@ -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)<<FRACBITS, ((y+25)<<FRACBITS) - (rubyheight<<1), FRACUNIT, 0, W_CachePatchName("RUBYICON", PU_CACHE), NULL);
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)
{
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_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
{
UINT8 mvtype = MV_VISITED;
if (cn->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)

View file

@ -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)

View file

@ -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);

View file

@ -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.