Ring Racers-specific Evaluation

- Four evaluation modes.
    - Perfect
        - Currently no visual implementation
    - All others have a cool set of visuals
        - Multi-stage animation of a glowing threat and a Star that's Sealed
        - If they're relevant, show the gems you HAVEN'T grabbed
        - Three modes here
            - No gems
                - For Easy mode, asks you to brave a higher difficulty
            - Chaos Emeralds
                - Not all 7 chaos emeralds? Push your rank harder!
            - Super Emeralds
                - Not all 7 super emeralds? Further challenge awaits!
- `useBlackRock` to make evaluation context less specific for custom material is replaced with `useSeal` option
- M_CheckCupEmeralds(difficulty)
    - Returns the Emeralds you have for that difficulty
    - Obviously returns 0 for Easy
    - Makes the method of checking collected Emeralds for cup contexts significantly easier
This commit is contained in:
toaster 2023-06-23 23:13:25 +01:00
parent f15a7a946d
commit 060c03f011
6 changed files with 281 additions and 106 deletions

View file

@ -3120,9 +3120,9 @@ void readmaincfg(MYFILE *f, boolean mainfile)
if (creditscutscene > 128) if (creditscutscene > 128)
creditscutscene = 128; creditscutscene = 128;
} }
else if (fastcmp(word, "USEBLACKROCK")) else if (fastcmp(word, "USESEAL"))
{ {
useBlackRock = (UINT8)(value || word2[0] == 'T' || word2[0] == 'Y'); useSeal = (UINT8)(value || word2[0] == 'T' || word2[0] == 'Y');
} }
else if (fastcmp(word, "LOOPTITLE")) else if (fastcmp(word, "LOOPTITLE"))
{ {

View file

@ -748,7 +748,7 @@ extern INT32 flameseg;
extern UINT8 introtoplay; extern UINT8 introtoplay;
extern UINT8 creditscutscene; extern UINT8 creditscutscene;
extern UINT8 useBlackRock; extern UINT8 useSeal;
extern UINT8 use1upSound; extern UINT8 use1upSound;
extern UINT8 maxXtraLife; // Max extra lives from rings extern UINT8 maxXtraLife; // Max extra lives from rings

View file

@ -129,10 +129,6 @@ static UINT8 *waitcolormap; // colormap for the spinning character
static patch_t *ttuser[TTMAX_USER]; static patch_t *ttuser[TTMAX_USER];
static INT32 ttuser_count = 0; static INT32 ttuser_count = 0;
static boolean goodending;
static INT32 sparkloffs[3][2]; // eggrock explosions/blackrock sparkles
static INT32 sparklloop;
// //
// PROMPT STATE // PROMPT STATE
// //
@ -889,8 +885,26 @@ boolean F_CreditResponder(event_t *event)
// EVALUATION // EVALUATION
// ============ // ============
#if 0
static INT32 sparkloffs[3][2]; // eggrock explosions/blackrock sparkles
static INT32 sparklloop;
#define SPARKLLOOPTIME 7 // must be odd #define SPARKLLOOPTIME 7 // must be odd
#endif
typedef enum
{
EVAL_NOTHING,
EVAL_CHAOS,
EVAL_SUPER,
EVAL_PERFECT
} evaluationtype_t;
static evaluationtype_t evaluationtype;
UINT16 finaleemeralds = 0;
void F_StartGameEvaluation(void) void F_StartGameEvaluation(void)
{ {
// Credits option in extras menu // Credits option in extras menu
@ -902,20 +916,39 @@ void F_StartGameEvaluation(void)
} }
S_FadeOutStopMusic(5*MUSICRATE); S_FadeOutStopMusic(5*MUSICRATE);
S_StopMusicCredit();
G_SetGamestate(GS_EVALUATION); G_SetGamestate(GS_EVALUATION);
// Just in case they're open ... somehow // Just in case they're open ... somehow
M_ClearMenus(true); M_ClearMenus(true);
goodending = (ALLCHAOSEMERALDS(emeralds)); UINT8 difficulty = KARTSPEED_NORMAL;
if (grandprixinfo.gp == true)
{
if (grandprixinfo.masterbots == true)
difficulty = KARTGP_MASTER;
else
difficulty = grandprixinfo.gamespeed;
}
finaleemeralds = M_CheckCupEmeralds(difficulty);
if (difficulty == KARTSPEED_EASY)
evaluationtype = EVAL_NOTHING;
else if (!ALLCHAOSEMERALDS(finaleemeralds))
evaluationtype = EVAL_CHAOS;
else if (!ALLSUPEREMERALDS(finaleemeralds))
evaluationtype = EVAL_SUPER;
else
evaluationtype = EVAL_PERFECT;
gameaction = ga_nothing; gameaction = ga_nothing;
paused = false; paused = false;
CON_ToggleOff(); CON_ToggleOff();
finalecount = -1; finalecount = -1;
sparklloop = 0; //sparklloop = 0;
} }
void F_GameEvaluationDrawer(void) void F_GameEvaluationDrawer(void)
@ -923,68 +956,155 @@ void F_GameEvaluationDrawer(void)
INT32 x, y, i; INT32 x, y, i;
angle_t fa; angle_t fa;
INT32 eemeralds_cur; INT32 eemeralds_cur;
char patchname[7] = "CEMGx0"; const char *endingtext = NULL, *rankharder = NULL;
const char* endingtext;
if (marathonmode) if (marathonmode)
{
endingtext = "THANKS FOR THE RUN!"; endingtext = "THANKS FOR THE RUN!";
else if (goodending) }
endingtext = "CONGRATULATIONS!"; else switch (evaluationtype)
else {
case EVAL_PERFECT:
endingtext = "CONGRATULATIONS!";
break;
case EVAL_SUPER:
rankharder = "Further challenge awaits!";
break;
default:
rankharder = "...push your rank harder";
break;
case EVAL_NOTHING:
rankharder = "Brave a higher difficulty";
break;
}
if (endingtext == NULL)
endingtext = "TRY AGAIN..."; endingtext = "TRY AGAIN...";
if (usedCheats)
rankharder = "Cheated games can't unlock extras!";
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
const INT32 gainaxtime = ((3*TICRATE)/2) - finalecount;
const INT32 sealtime = finalecount - (4*TICRATE);
INT32 crossfade = 0;
// Draw all the good crap here. // Draw all the good crap here.
if (finalecount > 0 && useBlackRock) x = BASEVIDWIDTH<<(FRACBITS-1);
y = (BASEVIDHEIGHT + 16)<<(FRACBITS-1);
if (useSeal && evaluationtype != EVAL_PERFECT)
{ {
INT32 scale = FRACUNIT; patch_t *sealpat;
patch_t *rockpat;
UINT8 *colormap[2] = {NULL, NULL};
patch_t *glow;
INT32 trans = 0;
x = (((BASEVIDWIDTH-82)/2)+11)<<FRACBITS; if (gainaxtime > 0)
y = (((BASEVIDHEIGHT-82)/2)+12)<<FRACBITS;
if (finalecount < 5)
{ {
scale = (finalecount<<(FRACBITS-2)); // Stage 1 - blank
x += (30*(FRACUNIT-scale)); sealpat = W_CachePatchName(
y += (30*(FRACUNIT-scale)); "K_FINB01",
PU_PATCH_LOWPRIORITY
);
} }
else if (sealtime < 0)
if (goodending)
{ {
rockpat = W_CachePatchName(va("ROID00%.2d", 34 - (finalecount % 35)), PU_PATCH_LOWPRIORITY); // Stage 2 - Catcher Glow
glow = W_CachePatchName(va("ENDGLOW%.1d", 2+(finalecount & 1)), PU_PATCH_LOWPRIORITY); sealpat = W_CachePatchName(
x -= FRACUNIT; va("K_FINB0%u", 2+(finalecount & 1)),
PU_PATCH_LOWPRIORITY
);
crossfade = 10 + sealtime/3;
} }
else else
{ {
rockpat = W_CachePatchName("ROID0000", PU_PATCH_LOWPRIORITY); // Stage 3 - Star Within The Seal
glow = W_CachePatchName(va("ENDGLOW%.1d", (finalecount & 1)), PU_PATCH_LOWPRIORITY); sealpat = W_CachePatchName(
"K_FINB05",
PU_PATCH_LOWPRIORITY
);
#define SEAL_PULSELEN (TICRATE)
crossfade = (sealtime % (2*SEAL_PULSELEN)) - SEAL_PULSELEN;
if (crossfade < 0)
crossfade = -crossfade;
crossfade = (crossfade * 10)/SEAL_PULSELEN;
#undef SEAL_PULSELEN
} }
if (finalecount >= 5) if (crossfade != 10)
trans = (finalecount-5)>>1;
if (trans < 10)
V_DrawFixedPatch(x, y, scale, trans<<V_ALPHASHIFT, glow, NULL);
trans = (15-finalecount);
if (trans < 0)
trans = -trans;
if (finalecount < 15)
colormap[0] = R_GetTranslationColormap(TC_ALLWHITE, 0, GTC_CACHE);
V_DrawFixedPatch(x, y, scale, 0, rockpat, colormap[0]);
if (trans < 10)
{ {
colormap[1] = R_GetTranslationColormap(TC_BLINK, SKINCOLOR_AQUAMARINE, GTC_CACHE); V_DrawFixedPatch(
V_DrawFixedPatch(x, y, scale, trans<<V_ALPHASHIFT, rockpat, colormap[1]); x, y,
FRACUNIT,
0,
sealpat,
NULL
);
} }
if (goodending)
if (crossfade > 0)
{
sealpat = W_CachePatchName(
"K_FINB04",
PU_PATCH_LOWPRIORITY
);
V_DrawFixedPatch(
x, y,
FRACUNIT,
(10-crossfade)<<V_ALPHASHIFT,
sealpat,
NULL
);
}
else
crossfade = 0;
// Lens flare
if (sealtime < 0 && crossfade < 10)
{
spritedef_t *sprdef = &sprites[SPR_LENS];
INT32 refframes = (sprdef->numframes - 2);
if (refframes < 0)
; // Not enough sprites
else if (gainaxtime <= refframes)
{
// Animation in progress!
INT32 gainaxframe;
if (gainaxtime <= 0)
{
// Flicker
gainaxframe = refframes + (finalecount & 1);
}
else
{
// Shwing in
gainaxframe = (sprdef->numframes - 2) - gainaxtime;
}
spriteframe_t *sprframe = &sprdef->spriteframes[gainaxframe];
if (sprframe->lumppat[0] != LUMPERROR)
{
V_DrawFixedPatch(
x, (y - (20*FRACUNIT)),
FRACUNIT/2,
V_ADD
|(crossfade<<V_ALPHASHIFT)
|((sprframe->flip & 1) ? V_FLIP : 0),
W_CachePatchNum(sprframe->lumppat[0], PU_CACHE),
NULL
);
}
}
}
#if 0
if (evaluationtype == EVAL_PERFECT)
{ {
INT32 j = (sparklloop & 1) ? 2 : 3; INT32 j = (sparklloop & 1) ? 2 : 3;
if (j > (finalecount/SPARKLLOOPTIME)) if (j > (finalecount/SPARKLLOOPTIME))
@ -1003,33 +1123,94 @@ void F_GameEvaluationDrawer(void)
j--; j--;
} }
} }
#endif
}
if ((evaluationtype == EVAL_CHAOS || evaluationtype == EVAL_SUPER)
&& finalecount > 0)
{
INT32 gemtrans;
if (useSeal && sealtime > 0)
{
// Stage 3 - aggressive overexposure
gemtrans = 3 + ((10 - crossfade)/3);
}
else if (useSeal && crossfade > 0)
{
// Stage 2 - some overexposure
gemtrans = (crossfade/3);
}
else else
{ {
patch_t *eggrock = W_CachePatchName("ENDEGRK5", PU_PATCH_LOWPRIORITY); // Stage 1 - initial fade in
V_DrawFixedPatch(x, y, scale, 0, eggrock, colormap[0]); gemtrans = max(10-finalecount, 0);
if (trans < 10) }
V_DrawFixedPatch(x, y, scale, trans<<V_ALPHASHIFT, eggrock, colormap[1]);
else if (sparklloop) gemtrans <<= V_ALPHASHIFT;
V_DrawFixedPatch(x, y, scale, (10-sparklloop)<<V_ALPHASHIFT,
W_CachePatchName("ENDEGRK0", PU_PATCH_LOWPRIORITY), colormap[1]); eemeralds_cur = (finalecount % 360)<<FRACBITS;
patch_t *empat = W_CachePatchName(
(evaluationtype == EVAL_CHAOS) ? "EMEMAP" : "SUPMAP",
PU_PATCH_LOWPRIORITY
);
x -= 6*FRACUNIT;
y -= 6*FRACUNIT;
UINT8 basegem = (evaluationtype == EVAL_SUPER)
? 7 : 0;
for (i = basegem; i < (basegem+7); ++i, eemeralds_cur += (360<<FRACBITS)/7)
{
if (finaleemeralds & (1<<i))
continue;
fa = (FixedAngle(eemeralds_cur)>>ANGLETOFINESHIFT) & FINEMASK;
V_DrawFixedPatch(
x + (75*FINECOSINE(fa)), y + (75*FINESINE(fa)),
FRACUNIT,
gemtrans,
empat,
R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_CHAOSEMERALD1+(i-basegem), GTC_CACHE)
);
} }
} }
eemeralds_cur = (finalecount % 360)<<FRACBITS; V_DrawCenteredGamemodeString(
BASEVIDWIDTH/2,
15,
0,
NULL,
endingtext
);
for (i = 0; i < 7; ++i) if (rankharder != NULL)
{ {
fa = (FixedAngle(eemeralds_cur)>>ANGLETOFINESHIFT) & FINEMASK; x = (BASEVIDWIDTH<<(FRACBITS-1)) - \
x = (BASEVIDWIDTH<<(FRACBITS-1)) + (60*FINECOSINE(fa)); V_StringScaledWidth(
y = ((BASEVIDHEIGHT+16)<<(FRACBITS-1)) + (60*FINESINE(fa)); FRACUNIT,
eemeralds_cur += (360<<FRACBITS)/7; FRACUNIT,
FRACUNIT,
0,
KART_FONT,
rankharder
)/2;
patchname[4] = 'A'+(char)i; V_DrawStringScaled(
V_DrawFixedPatch(x, y, FRACUNIT, ((emeralds & (1<<i)) ? 0 : V_80TRANS), W_CachePatchName(patchname, PU_PATCH_LOWPRIORITY), NULL); x,
(BASEVIDHEIGHT - 15 - 14) * FRACUNIT,
FRACUNIT,
FRACUNIT,
FRACUNIT,
0,
NULL,
KART_FONT,
rankharder
);
} }
V_DrawCreditString((BASEVIDWIDTH - V_CreditStringWidth(endingtext))<<(FRACBITS-1), (BASEVIDHEIGHT-100)<<(FRACBITS-1), 0, endingtext);
if (marathonmode) if (marathonmode)
{ {
const char *rtatext, *cuttext; const char *rtatext, *cuttext;
@ -1048,20 +1229,12 @@ void F_GameEvaluationTicker(void)
return; return;
} }
if (!useBlackRock) #if 0
if (!useSeal)
; ;
else if (!goodending) else if (evaluationtype != EVAL_PERFECT)
{ {
if (sparklloop) ;
sparklloop--;
if (finalecount == (5*TICRATE)/2
|| finalecount == (7*TICRATE)/2
|| finalecount == ((7*TICRATE)/2)+5)
{
S_StartSound(NULL, sfx_s3k5c);
sparklloop = 10;
}
} }
else if (++sparklloop == SPARKLLOOPTIME) // time to roll the randomisation again else if (++sparklloop == SPARKLLOOPTIME) // time to roll the randomisation again
{ {
@ -1077,6 +1250,7 @@ void F_GameEvaluationTicker(void)
sparkloffs[0][1] = (30<<FRACBITS) + workingradius*FINESINE(workingangle); sparkloffs[0][1] = (30<<FRACBITS) + workingradius*FINESINE(workingangle);
sparklloop = 0; sparklloop = 0;
} }
#endif
if (finalecount == 5*TICRATE) if (finalecount == 5*TICRATE)
{ {
@ -1087,13 +1261,6 @@ void F_GameEvaluationTicker(void)
M_UpdateUnlockablesAndExtraEmblems(true, true); M_UpdateUnlockablesAndExtraEmblems(true, true);
G_SaveGameData(); G_SaveGameData();
} }
else
{
HU_SetCEchoFlags(V_YELLOWMAP);
HU_SetCEchoDuration(6);
HU_DoCEcho("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Cheated games can't unlock extras!");
S_StartSound(NULL, sfx_s3k68);
}
} }
} }

View file

@ -264,7 +264,7 @@ UINT8 maxXtraLife = 2; // Max extra lives from rings
UINT8 introtoplay; UINT8 introtoplay;
UINT8 creditscutscene; UINT8 creditscutscene;
UINT8 useBlackRock = 1; UINT8 useSeal = 1;
// Emerald locations // Emerald locations
mobj_t *hunt1; mobj_t *hunt1;

View file

@ -738,6 +738,31 @@ boolean M_NotFreePlay(player_t *player)
return false; return false;
} }
UINT16 M_CheckCupEmeralds(UINT8 difficulty)
{
if (difficulty == 0)
return 0;
if (difficulty >= KARTGP_MAX)
difficulty = KARTGP_MASTER;
cupheader_t *cup;
UINT16 ret = 0;
for (cup = kartcupheaders; cup; cup = cup->next)
{
if (cup->emeraldnum == 0)
continue;
if (cup->windata[difficulty].got_emerald == false)
continue;
ret |= 1<<(cup->emeraldnum-1);
}
return ret;
}
// See also M_GetConditionString // See also M_GetConditionString
boolean M_CheckCondition(condition_t *cn, player_t *player) boolean M_CheckCondition(condition_t *cn, player_t *player)
{ {
@ -791,30 +816,12 @@ boolean M_CheckCondition(condition_t *cn, player_t *player)
case UC_ALLSUPER: case UC_ALLSUPER:
case UC_ALLEMERALDS: case UC_ALLEMERALDS:
{ {
cupheader_t *cup;
UINT16 ret = 0; UINT16 ret = 0;
UINT8 i;
if (gamestate == GS_LEVEL) if (gamestate == GS_LEVEL)
return false; // this one could be laggy with many cups available return false; // this one could be laggy with many cups available
for (cup = kartcupheaders; cup; cup = cup->next) ret = M_CheckCupEmeralds(cn->requirement);
{
if (cup->emeraldnum == 0)
continue;
i = cn->requirement;
for (i = cn->requirement; i < KARTGP_MAX; i++)
{
if (cup->windata[i].got_emerald == true)
break;
}
if (i == KARTGP_MAX)
continue;
ret |= 1<<(cup->emeraldnum-1);
}
if (cn->type == UC_ALLCHAOS) if (cn->type == UC_ALLCHAOS)
return ALLCHAOSEMERALDS(ret); return ALLCHAOSEMERALDS(ret);

View file

@ -340,6 +340,7 @@ void M_ClearSecrets(void);
void M_ClearStats(void); void M_ClearStats(void);
boolean M_NotFreePlay(player_t *player); boolean M_NotFreePlay(player_t *player);
UINT16 M_CheckCupEmeralds(UINT8 difficulty);
// Updating conditions and unlockables // Updating conditions and unlockables
boolean M_ConditionInterpret(const char *password); boolean M_ConditionInterpret(const char *password);