Merge branch 'challenges-continued' into 'master'

Updated Challenges Menu

See merge request KartKrew/Kart!971
This commit is contained in:
Oni 2023-02-25 04:37:02 +00:00
commit e1fd7bce99
12 changed files with 417 additions and 139 deletions

View file

@ -4359,7 +4359,7 @@ void G_LoadGameSettings(void)
} }
#define GD_VERSIONCHECK 0xBA5ED123 // Change every major version, as usual #define GD_VERSIONCHECK 0xBA5ED123 // Change every major version, as usual
#define GD_VERSIONMINOR 0 // Change every format update #define GD_VERSIONMINOR 1 // Change every format update
// G_LoadGameData // G_LoadGameData
// Loads the main data file, which stores information such as emblems found, etc. // Loads the main data file, which stores information such as emblems found, etc.
@ -4369,6 +4369,7 @@ void G_LoadGameData(void)
UINT32 versionID; UINT32 versionID;
UINT8 versionMinor; UINT8 versionMinor;
UINT8 rtemp; UINT8 rtemp;
boolean gridunusable = false;
savebuffer_t save = {0}; savebuffer_t save = {0};
//For records //For records
@ -4423,6 +4424,10 @@ void G_LoadGameData(void)
P_SaveBufferFree(&save); P_SaveBufferFree(&save);
I_Error("Game data is from the future! (expected %d, got %d)", GD_VERSIONMINOR, versionMinor); I_Error("Game data is from the future! (expected %d, got %d)", GD_VERSIONMINOR, versionMinor);
} }
if (versionMinor == 0)
{
gridunusable = true;
}
gamedata->totalplaytime = READUINT32(save.p); gamedata->totalplaytime = READUINT32(save.p);
gamedata->matchesplayed = READUINT32(save.p); gamedata->matchesplayed = READUINT32(save.p);
@ -4469,21 +4474,34 @@ void G_LoadGameData(void)
i += j; i += j;
} }
gamedata->challengegridwidth = READUINT16(save.p); if (gridunusable)
Z_Free(gamedata->challengegrid);
if (gamedata->challengegridwidth)
{ {
gamedata->challengegrid = Z_Malloc( UINT16 burn = READUINT16(save.p); // Previous challengegridwidth
(gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT * sizeof(UINT8)), UINT8 height = (versionMinor > 0) ? CHALLENGEGRIDHEIGHT : 5;
PU_STATIC, NULL); save.p += (burn * height * sizeof(UINT8)); // Step over previous grid data
for (i = 0; i < (gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT); i++)
{ gamedata->challengegridwidth = 0;
gamedata->challengegrid[i] = READUINT8(save.p); Z_Free(gamedata->challengegrid);
} gamedata->challengegrid = NULL;
} }
else else
{ {
gamedata->challengegrid = NULL; gamedata->challengegridwidth = READUINT16(save.p);
Z_Free(gamedata->challengegrid);
if (gamedata->challengegridwidth)
{
gamedata->challengegrid = Z_Malloc(
(gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT * sizeof(UINT8)),
PU_STATIC, NULL);
for (i = 0; i < (gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT); i++)
{
gamedata->challengegrid[i] = READUINT8(save.p);
}
}
else
{
gamedata->challengegrid = NULL;
}
} }
gamedata->timesBeaten = READUINT32(save.p); gamedata->timesBeaten = READUINT32(save.p);

View file

@ -8037,7 +8037,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL, // missilestate S_NULL, // missilestate
S_SPRK1, // deathstate S_SPRK1, // deathstate
S_NULL, // xdeathstate S_NULL, // xdeathstate
sfx_ncitem, // deathsound sfx_None, // deathsound
1, // speed 1, // speed
16*FRACUNIT, // radius 16*FRACUNIT, // radius
30*FRACUNIT, // height 30*FRACUNIT, // height

View file

@ -46,7 +46,6 @@ void K_DrawMapThumbnail(INT32 x, INT32 y, INT32 width, UINT32 flags, UINT16 map,
void K_DrawLikeMapThumbnail(INT32 x, INT32 y, INT32 width, UINT32 flags, patch_t *patch, UINT8 *colormap); void K_DrawLikeMapThumbnail(INT32 x, INT32 y, INT32 width, UINT32 flags, patch_t *patch, UINT8 *colormap);
void K_drawTargetHUD(const vector3_t *origin, player_t *player); void K_drawTargetHUD(const vector3_t *origin, player_t *player);
extern patch_t *kp_facehighlight[8];
extern patch_t *kp_capsuletarget_arrow[2][2]; extern patch_t *kp_capsuletarget_arrow[2][2];
extern patch_t *kp_capsuletarget_icon[2]; extern patch_t *kp_capsuletarget_icon[2];
extern patch_t *kp_capsuletarget_far[2]; extern patch_t *kp_capsuletarget_far[2];

View file

@ -1137,6 +1137,8 @@ void M_DrawAddons(void);
#define CC_ANIM 3 #define CC_ANIM 3
#define CC_MAX 4 #define CC_MAX 4
#define TILEFLIP_MAX 16
// Keep track of some pause menu data for visual goodness. // Keep track of some pause menu data for visual goodness.
extern struct challengesmenu_s { extern struct challengesmenu_s {
@ -1151,7 +1153,7 @@ extern struct challengesmenu_s {
SINT8 row, hilix, focusx; SINT8 row, hilix, focusx;
UINT8 col, hiliy; UINT8 col, hiliy;
UINT8 *extradata; challengegridextradata_t *extradata;
boolean pending; boolean pending;
boolean requestnew; boolean requestnew;

View file

@ -1479,7 +1479,7 @@ static void M_DrawCharSelectPreview(UINT8 num)
static void M_DrawCharSelectExplosions(boolean charsel, INT16 basex, INT16 basey) static void M_DrawCharSelectExplosions(boolean charsel, INT16 basex, INT16 basey)
{ {
UINT8 i; UINT8 i;
INT16 quadx = 0, quady = 0; INT16 quadx = 2, quady = 2, mul = 22;
for (i = 0; i < CSEXPLOSIONS; i++) for (i = 0; i < CSEXPLOSIONS; i++)
{ {
@ -1495,13 +1495,14 @@ static void M_DrawCharSelectExplosions(boolean charsel, INT16 basex, INT16 basey
{ {
quadx = 4 * (setup_explosions[i].x / 3); quadx = 4 * (setup_explosions[i].x / 3);
quady = 4 * (setup_explosions[i].y / 3); quady = 4 * (setup_explosions[i].y / 3);
mul = 16;
} }
colormap = R_GetTranslationColormap(TC_DEFAULT, setup_explosions[i].color, GTC_MENUCACHE); colormap = R_GetTranslationColormap(TC_DEFAULT, setup_explosions[i].color, GTC_MENUCACHE);
V_DrawMappedPatch( V_DrawMappedPatch(
basex + (setup_explosions[i].x*16) + quadx - 6, basex + (setup_explosions[i].x*mul) + quadx - 6,
basey + (setup_explosions[i].y*16) + quady - 6, basey + (setup_explosions[i].y*mul) + quady - 6,
0, W_CachePatchName(va("CHCNFRM%d", frame), PU_CACHE), 0, W_CachePatchName(va("CHCNFRM%d", frame), PU_CACHE),
colormap colormap
); );
@ -4516,10 +4517,11 @@ static void M_DrawChallengeTile(INT16 i, INT16 j, INT32 x, INT32 y, boolean hili
{ {
unlockable_t *ref = NULL; unlockable_t *ref = NULL;
patch_t *pat = missingpat; patch_t *pat = missingpat;
UINT8 *colormap = NULL; UINT8 *colormap = NULL, *bgmap = NULL;
fixed_t siz; fixed_t siz, accordion;
UINT8 id, num; UINT8 id, num;
UINT32 edgelength; boolean unlockedyet;
boolean categoryside;
id = (i * CHALLENGEGRIDHEIGHT) + j; id = (i * CHALLENGEGRIDHEIGHT) + j;
num = gamedata->challengegrid[id]; num = gamedata->challengegrid[id];
@ -4533,18 +4535,116 @@ static void M_DrawChallengeTile(INT16 i, INT16 j, INT32 x, INT32 y, boolean hili
// Okay, this is what we want to draw. // Okay, this is what we want to draw.
ref = &unlockables[num]; ref = &unlockables[num];
edgelength = (ref->majorunlock ? 30 : 14); unlockedyet = !((gamedata->unlocked[num] == false)
|| (challengesmenu.pending && num == challengesmenu.currentunlock && challengesmenu.unlockanim <= UNLOCKTIME));
// ...unless we simply aren't unlocked yet. // If we aren't unlocked yet, return early.
if ((gamedata->unlocked[num] == false) if (!unlockedyet)
|| (challengesmenu.pending && num == challengesmenu.currentunlock && challengesmenu.unlockanim <= UNLOCKTIME))
{ {
V_DrawFill(x+1, y+1, edgelength, edgelength, UINT32 flags = 0;
((challengesmenu.extradata[id] == CHE_HINT) ? 132 : 11));
if (challengesmenu.extradata[id].flags != CHE_HINT)
{
colormap = R_GetTranslationColormap(TC_BLINK, SKINCOLOR_BLACK, GTC_CACHE);
flags = V_SUBTRACT|V_90TRANS;
}
pat = W_CachePatchName(
va("UN_HNT%c%c",
(hili && !colormap) ? '1' : '2',
ref->majorunlock ? 'B' : 'A'
),
PU_CACHE);
V_DrawFixedPatch(
x*FRACUNIT, y*FRACUNIT,
FRACUNIT,
flags, pat,
colormap
);
pat = missingpat;
colormap = NULL;
goto drawborder; goto drawborder;
} }
if (ref->icon != NULL && ref->icon[0]) accordion = FRACUNIT;
if (challengesmenu.extradata[id].flip != 0
&& challengesmenu.extradata[id].flip != (TILEFLIP_MAX/2))
{
angle_t bad = (FixedAngle((fixed_t)(challengesmenu.extradata[id].flip) * (360*FRACUNIT/TILEFLIP_MAX)) >> ANGLETOFINESHIFT) & FINEMASK;
accordion = FINECOSINE(bad);
if (accordion < 0)
accordion = -accordion;
}
pat = W_CachePatchName(
(ref->majorunlock ? "UN_BORDB" : "UN_BORDA"),
PU_CACHE);
bgmap = R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_SILVER, GTC_MENUCACHE);
V_DrawStretchyFixedPatch(
(x*FRACUNIT) + (SHORT(pat->width)*(FRACUNIT-accordion)/2), y*FRACUNIT,
accordion,
FRACUNIT,
0, pat,
bgmap
);
pat = missingpat;
categoryside = (challengesmenu.extradata[id].flip <= TILEFLIP_MAX/4
|| challengesmenu.extradata[id].flip > (3*TILEFLIP_MAX)/4);
if (categoryside)
{
char categoryid = '8';
colormap = bgmap;
switch (ref->type)
{
case SECRET_SKIN:
categoryid = '1';
break;
case SECRET_FOLLOWER:
categoryid = '2';
break;
/*case SECRET_COLOR:
categoryid = '3';
break;*/
case SECRET_CUP:
categoryid = '4';
break;
//case SECRET_MASTERBOTS:
case SECRET_HARDSPEED:
case SECRET_ENCORE:
categoryid = '5';
break;
case SECRET_ALTTITLE:
case SECRET_SOUNDTEST:
categoryid = '6';
break;
case SECRET_TIMEATTACK:
case SECRET_BREAKTHECAPSULES:
case SECRET_SPECIALATTACK:
categoryid = '7';
break;
}
pat = W_CachePatchName(va("UN_RR0%c%c",
categoryid,
(ref->majorunlock) ? 'B' : 'A'),
PU_CACHE);
if (pat == missingpat)
{
pat = W_CachePatchName(va("UN_RR0%c%c",
categoryid,
(ref->majorunlock) ? 'A' : 'B'),
PU_CACHE);
}
}
else if (ref->icon != NULL && ref->icon[0])
{ {
pat = W_CachePatchName(ref->icon, PU_CACHE); pat = W_CachePatchName(ref->icon, PU_CACHE);
if (ref->color != SKINCOLOR_NONE && ref->color < numskincolors) if (ref->color != SKINCOLOR_NONE && ref->color < numskincolors)
@ -4552,58 +4652,110 @@ static void M_DrawChallengeTile(INT16 i, INT16 j, INT32 x, INT32 y, boolean hili
colormap = R_GetTranslationColormap(TC_DEFAULT, ref->color, GTC_MENUCACHE); colormap = R_GetTranslationColormap(TC_DEFAULT, ref->color, GTC_MENUCACHE);
} }
} }
else switch (ref->type) else
{ {
case SECRET_SKIN: UINT8 iconid = 0;
switch (ref->type)
{ {
INT32 skin = M_UnlockableSkinNum(ref); case SECRET_SKIN:
if (skin != -1)
{ {
colormap = R_GetTranslationColormap(skin, skins[skin].prefcolor, GTC_MENUCACHE); INT32 skin = M_UnlockableSkinNum(ref);
pat = faceprefix[skin][(ref->majorunlock) ? FACE_WANTED : FACE_RANK]; if (skin != -1)
{
colormap = R_GetTranslationColormap(skin, skins[skin].prefcolor, GTC_MENUCACHE);
pat = faceprefix[skin][(ref->majorunlock) ? FACE_WANTED : FACE_RANK];
}
break;
}
case SECRET_FOLLOWER:
{
INT32 skin = M_UnlockableFollowerNum(ref);
if (skin != -1)
{
UINT16 col = K_GetEffectiveFollowerColor(followers[skin].defaultcolor, cv_playercolor[0].value);
colormap = R_GetTranslationColormap(TC_DEFAULT, col, GTC_MENUCACHE);
pat = W_CachePatchName(followers[skin].icon, PU_CACHE);
}
break;
}
/*case SECRET_MASTERBOTS:
iconid = 4;
break;*/
case SECRET_HARDSPEED:
iconid = 3;
break;
case SECRET_ENCORE:
iconid = 5;
break;
case SECRET_ALTTITLE:
iconid = 6;
break;
case SECRET_SOUNDTEST:
iconid = 1;
break;
case SECRET_TIMEATTACK:
iconid = 7;
break;
case SECRET_BREAKTHECAPSULES:
iconid = 8;
break;
case SECRET_SPECIALATTACK:
iconid = 9;
break;
default:
{
if (!colormap && ref->color != SKINCOLOR_NONE && ref->color < numskincolors)
{
colormap = R_GetTranslationColormap(TC_RAINBOW, ref->color, GTC_MENUCACHE);
}
break;
} }
break;
} }
case SECRET_FOLLOWER:
if (pat == missingpat)
{ {
INT32 skin = M_UnlockableFollowerNum(ref); pat = W_CachePatchName(va("UN_IC%02u%c",
if (skin != -1) iconid,
ref->majorunlock ? 'B' : 'A'),
PU_CACHE);
if (pat == missingpat)
{ {
UINT16 col = K_GetEffectiveFollowerColor(followers[skin].defaultcolor, cv_playercolor[0].value); pat = W_CachePatchName(va("UN_IC%02u%c",
colormap = R_GetTranslationColormap(TC_DEFAULT, col, GTC_MENUCACHE); iconid,
pat = W_CachePatchName(followers[skin].icon, PU_CACHE); ref->majorunlock ? 'A' : 'B'),
PU_CACHE);
} }
break;
}
default:
{
pat = W_CachePatchName(va("UN_RR00%c", ref->majorunlock ? 'B' : 'A'), PU_CACHE);
if (ref->color != SKINCOLOR_NONE && ref->color < numskincolors)
{
//CONS_Printf(" color for %d is %s\n", num, skincolors[unlockables[num].color].name);
colormap = R_GetTranslationColormap(TC_RAINBOW, ref->color, GTC_MENUCACHE);
}
break;
} }
} }
siz = (SHORT(pat->width) << FRACBITS); siz = (SHORT(pat->width) << FRACBITS);
siz = FixedDiv(((ref->majorunlock) ? 32 : 16) << FRACBITS, siz);
V_SetClipRect( if (!siz)
(x+1) << FRACBITS, (y+1) << FRACBITS, ; // prevent div/0
edgelength << FRACBITS, edgelength << FRACBITS, else if (ref->majorunlock)
0 {
); V_DrawStretchyFixedPatch(
((x + 5)*FRACUNIT) + (32*(FRACUNIT-accordion)/2), (y + 5)*FRACUNIT,
V_DrawFixedPatch( FixedDiv(32*accordion, siz),
x*FRACUNIT, y*FRACUNIT, FixedDiv(32 << FRACBITS, siz),
siz, 0, pat,
0, pat, colormap
colormap );
); }
else
V_ClearClipRect(); {
V_DrawStretchyFixedPatch(
((x + 2)*FRACUNIT) + (16*(FRACUNIT-accordion)/2), (y + 2)*FRACUNIT,
FixedDiv(16*accordion, siz),
FixedDiv(16 << FRACBITS, siz),
0, pat,
colormap
);
}
drawborder: drawborder:
if (!hili) if (!hili)
@ -4611,12 +4763,23 @@ drawborder:
return; return;
} }
V_DrawFixedPatch( {
x*FRACUNIT, y*FRACUNIT, boolean maj = (ref != NULL && ref->majorunlock);
((ref != NULL && ref->majorunlock) ? FRACUNIT*2 : FRACUNIT), char buffer[9];
0, kp_facehighlight[(challengesmenu.ticker / 4) % 8], sprintf(buffer, "UN_RETA1");
NULL buffer[6] = maj ? 'B' : 'A';
); buffer[7] = (skullAnimCounter/5) ? '2' : '1';
pat = W_CachePatchName(buffer, PU_CACHE);
colormap = R_GetTranslationColormap(TC_DEFAULT, cv_playercolor[0].value, GTC_MENUCACHE);
V_DrawFixedPatch(
x*FRACUNIT, y*FRACUNIT,
FRACUNIT,
0, pat,
colormap
);
}
} }
static void M_DrawChallengePreview(INT32 x, INT32 y) static void M_DrawChallengePreview(INT32 x, INT32 y)
@ -4819,6 +4982,9 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
} }
} }
#define challengetransparentstrength 8
#define challengesgridstep 22
void M_DrawChallenges(void) void M_DrawChallenges(void)
{ {
INT32 x = currentMenu->x, explodex, selectx; INT32 x = currentMenu->x, explodex, selectx;
@ -4828,8 +4994,25 @@ void M_DrawChallenges(void)
INT16 offset; INT16 offset;
{ {
patch_t *bg = W_CachePatchName("BGUNLCK2", PU_CACHE); #define questionslow 4 // slows down the scroll by this factor
#define questionloop (questionslow*100) // modulo
INT32 questionoffset = (challengesmenu.ticker % questionloop);
patch_t *bg = W_CachePatchName("BGUNLCKG", PU_CACHE);
patch_t *qm = W_CachePatchName("BGUNLSC", PU_CACHE);
// Background gradient
V_DrawFixedPatch(0, 0, FRACUNIT, 0, bg, NULL); V_DrawFixedPatch(0, 0, FRACUNIT, 0, bg, NULL);
// Scrolling question mark overlay
V_DrawFixedPatch(
-((160 + questionoffset)*FRACUNIT)/questionslow,
-(4*FRACUNIT) - (245*(FixedDiv((questionloop - questionoffset)*FRACUNIT, questionloop*FRACUNIT))),
FRACUNIT,
V_MODULATE,
qm,
NULL);
#undef questionslow
#undef questionloop
} }
if (gamedata->challengegrid == NULL || challengesmenu.extradata == NULL) if (gamedata->challengegrid == NULL || challengesmenu.extradata == NULL)
@ -4838,43 +5021,45 @@ void M_DrawChallenges(void)
goto challengedesc; goto challengedesc;
} }
x -= 16; V_DrawFadeFill(0, y-2, BASEVIDWIDTH, 90, 0, 31, challengetransparentstrength);
x -= (challengesgridstep-1);
x += challengesmenu.offset; x += challengesmenu.offset;
if (challengegridloops) if (challengegridloops)
{ {
if (!challengesmenu.col && challengesmenu.hilix) if (!challengesmenu.col && challengesmenu.hilix)
x -= gamedata->challengegridwidth*16; x -= gamedata->challengegridwidth*challengesgridstep;
i = challengesmenu.col + challengesmenu.focusx; i = challengesmenu.col + challengesmenu.focusx;
explodex = x - (i*16); explodex = x - (i*challengesgridstep);
while (x < BASEVIDWIDTH-16) while (x < BASEVIDWIDTH-challengesgridstep)
{ {
i = (i + 1) % gamedata->challengegridwidth; i = (i + 1) % gamedata->challengegridwidth;
x += 16; x += challengesgridstep;
} }
} }
else else
{ {
if (gamedata->challengegridwidth & 1) if (gamedata->challengegridwidth & 1)
x += 8; x += (challengesgridstep/2);
i = gamedata->challengegridwidth-1; i = gamedata->challengegridwidth-1;
explodex = x - (i*16)/2; explodex = x - (i*challengesgridstep)/2;
x += (i*16)/2; x += (i*challengesgridstep)/2;
} }
selectx = explodex + (challengesmenu.hilix*16); selectx = explodex + (challengesmenu.hilix*challengesgridstep);
while (i >= 0 && x >= -32) while (i >= 0 && x >= -(challengesgridstep*2))
{ {
y = currentMenu->y-16; y = currentMenu->y-challengesgridstep;
for (j = 0; j < CHALLENGEGRIDHEIGHT; j++) for (j = 0; j < CHALLENGEGRIDHEIGHT; j++)
{ {
y += 16; y += challengesgridstep;
if (challengesmenu.extradata[(i * CHALLENGEGRIDHEIGHT) + j] & CHE_DONTDRAW) if (challengesmenu.extradata[(i * CHALLENGEGRIDHEIGHT) + j].flags & CHE_DONTDRAW)
{ {
continue; continue;
} }
@ -4887,7 +5072,7 @@ void M_DrawChallenges(void)
M_DrawChallengeTile(i, j, x, y, false); M_DrawChallengeTile(i, j, x, y, false);
} }
x -= 16; x -= challengesgridstep;
i--; i--;
if (challengegridloops && i < 0) if (challengegridloops && i < 0)
{ {
@ -4903,7 +5088,7 @@ void M_DrawChallenges(void)
challengesmenu.hilix, challengesmenu.hilix,
challengesmenu.hiliy, challengesmenu.hiliy,
selectx, selectx,
currentMenu->y + (challengesmenu.hiliy*16), currentMenu->y + (challengesmenu.hiliy*challengesgridstep),
true); true);
M_DrawCharSelectExplosions(false, explodex, currentMenu->y); M_DrawCharSelectExplosions(false, explodex, currentMenu->y);
@ -4922,6 +5107,12 @@ challengedesc:
{ {
y = 120; y = 120;
V_DrawScaledPatch(0, y,
(10-challengetransparentstrength)<<V_ALPHASHIFT,
W_CachePatchName("MENUHINT", PU_CACHE));
V_DrawFadeFill(0, y+27, BASEVIDWIDTH, BASEVIDHEIGHT - (y+27), 0, 31, challengetransparentstrength);
if (challengesmenu.currentunlock < MAXUNLOCKABLES) if (challengesmenu.currentunlock < MAXUNLOCKABLES)
{ {
str = unlockables[challengesmenu.currentunlock].name; str = unlockables[challengesmenu.currentunlock].name;
@ -4953,7 +5144,7 @@ challengedesc:
&& challengesmenu.currentunlock < MAXUNLOCKABLES && challengesmenu.currentunlock < MAXUNLOCKABLES
&& ((gamedata->unlocked[challengesmenu.currentunlock] == true) && ((gamedata->unlocked[challengesmenu.currentunlock] == true)
|| ((challengesmenu.extradata != NULL) || ((challengesmenu.extradata != NULL)
&& (challengesmenu.extradata[i] & CHE_HINT)) && (challengesmenu.extradata[i].flags & CHE_HINT))
) )
) )
{ {
@ -4961,6 +5152,9 @@ challengedesc:
} }
} }
#undef challengetransparentstrength
#undef challengesgridstep
// Statistics menu // Statistics menu
#define STATSSTEP 10 #define STATSSTEP 10

View file

@ -1,5 +1,6 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2022-2023 by Vivian "toaster" Grannell.
// Copyright (C) 2012-2016 by Matthew "Kaito Sinclaire" Walsh. // Copyright (C) 2012-2016 by Matthew "Kaito Sinclaire" Walsh.
// Copyright (C) 2012-2020 by Sonic Team Junior. // Copyright (C) 2012-2020 by Sonic Team Junior.
// //
@ -259,28 +260,34 @@ quickcheckagain:
} }
} }
UINT8 *M_ChallengeGridExtraData(void) void M_UpdateChallengeGridExtraData(challengegridextradata_t *extradata)
{ {
UINT8 i, j, num, id, tempid, work; UINT8 i, j, num, id, tempid, work;
UINT8 *extradata;
boolean idchange; boolean idchange;
if (!gamedata->challengegrid) if (gamedata->challengegrid == NULL)
{ {
return NULL; return;
} }
extradata = Z_Malloc( if (extradata == NULL)
(gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT * sizeof(UINT8)),
PU_STATIC, NULL);
if (!extradata)
{ {
I_Error("M_ChallengeGridExtraData: was not able to allocate extradata"); return;
} }
//CONS_Printf(" --- \n"); //CONS_Printf(" --- \n");
// Pre-wipe flags.
for (i = 0; i < gamedata->challengegridwidth; i++)
{
for (j = 0; j < CHALLENGEGRIDHEIGHT; j++)
{
id = (i * CHALLENGEGRIDHEIGHT) + j;
extradata[id].flags = CHE_NONE;
}
}
// Populate extra data.
for (i = 0; i < gamedata->challengegridwidth; i++) for (i = 0; i < gamedata->challengegridwidth; i++)
{ {
for (j = 0; j < CHALLENGEGRIDHEIGHT; j++) for (j = 0; j < CHALLENGEGRIDHEIGHT; j++)
@ -289,8 +296,6 @@ UINT8 *M_ChallengeGridExtraData(void)
num = gamedata->challengegrid[id]; num = gamedata->challengegrid[id];
idchange = false; idchange = false;
extradata[id] = CHE_NONE;
// Empty spots in the grid are always unconnected. // Empty spots in the grid are always unconnected.
if (num >= MAXUNLOCKABLES) if (num >= MAXUNLOCKABLES)
{ {
@ -304,13 +309,13 @@ UINT8 *M_ChallengeGridExtraData(void)
work = gamedata->challengegrid[tempid]; work = gamedata->challengegrid[tempid];
if (work == num) if (work == num)
{ {
extradata[id] = CHE_CONNECTEDUP; extradata[id].flags = CHE_CONNECTEDUP;
// Get the id to write extra hint data to. // Get the id to write extra hint data to.
// This check is safe because extradata's order of population // This check is safe because extradata's order of population
if (extradata[tempid] & CHE_CONNECTEDLEFT) if (extradata[tempid].flags & CHE_CONNECTEDLEFT)
{ {
extradata[id] |= CHE_CONNECTEDLEFT; extradata[id].flags |= CHE_CONNECTEDLEFT;
//CONS_Printf(" %d - %d above %d is invalid, check to left\n", num, tempid, id); //CONS_Printf(" %d - %d above %d is invalid, check to left\n", num, tempid, id);
if (i > 0) if (i > 0)
{ {
@ -327,14 +332,14 @@ UINT8 *M_ChallengeGridExtraData(void)
id = tempid; id = tempid;
idchange = true; idchange = true;
if (extradata[id] == CHE_HINT) if (extradata[id].flags == CHE_HINT)
{ {
continue; continue;
} }
} }
else if (work < MAXUNLOCKABLES && gamedata->unlocked[work]) else if (work < MAXUNLOCKABLES && gamedata->unlocked[work])
{ {
extradata[id] = CHE_HINT; extradata[id].flags = CHE_HINT;
} }
} }
@ -356,11 +361,11 @@ UINT8 *M_ChallengeGridExtraData(void)
{ {
//CONS_Printf(" %d - %d to left of %d is valid\n", work, tempid, id); //CONS_Printf(" %d - %d to left of %d is valid\n", work, tempid, id);
// If we haven't already updated our id, it's the one to our left. // If we haven't already updated our id, it's the one to our left.
if (extradata[id] == CHE_HINT) if (extradata[id].flags == CHE_HINT)
{ {
extradata[tempid] = CHE_HINT; extradata[tempid].flags = CHE_HINT;
} }
extradata[id] = CHE_CONNECTEDLEFT; extradata[id].flags = CHE_CONNECTEDLEFT;
id = tempid; id = tempid;
} }
/*else /*else
@ -368,13 +373,13 @@ UINT8 *M_ChallengeGridExtraData(void)
} }
else if (work < MAXUNLOCKABLES && gamedata->unlocked[work]) else if (work < MAXUNLOCKABLES && gamedata->unlocked[work])
{ {
extradata[id] = CHE_HINT; extradata[id].flags = CHE_HINT;
continue; continue;
} }
} }
// Since we're not modifying id past this point, the conditions become much simpler. // Since we're not modifying id past this point, the conditions become much simpler.
if (extradata[id] == CHE_HINT) if ((extradata[id].flags & (CHE_HINT|CHE_DONTDRAW)) == CHE_HINT)
{ {
continue; continue;
} }
@ -391,7 +396,7 @@ UINT8 *M_ChallengeGridExtraData(void)
} }
else if (work < MAXUNLOCKABLES && gamedata->unlocked[work]) else if (work < MAXUNLOCKABLES && gamedata->unlocked[work])
{ {
extradata[id] = CHE_HINT; extradata[id].flags = CHE_HINT;
continue; continue;
} }
} }
@ -414,14 +419,12 @@ UINT8 *M_ChallengeGridExtraData(void)
} }
else if (work < MAXUNLOCKABLES && gamedata->unlocked[work]) else if (work < MAXUNLOCKABLES && gamedata->unlocked[work])
{ {
extradata[id] = CHE_HINT; extradata[id].flags = CHE_HINT;
continue; continue;
} }
} }
} }
} }
return extradata;
} }
void M_AddRawCondition(UINT8 set, UINT8 id, conditiontype_t c, INT32 r, INT16 x1, INT16 x2) void M_AddRawCondition(UINT8 set, UINT8 id, conditiontype_t c, INT32 r, INT16 x1, INT16 x2)
@ -909,7 +912,7 @@ boolean M_UpdateUnlockablesAndExtraEmblems(boolean loud)
{ {
if (loud) if (loud)
{ {
S_StartSound(NULL, sfx_ncitem); S_StartSound(NULL, sfx_achiev);
} }
return true; return true;
} }

View file

@ -1,5 +1,6 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2022-2023 by Vivian "toaster" Grannell.
// Copyright (C) 2012-2016 by Matthew "Kaito Sinclaire" Walsh. // Copyright (C) 2012-2016 by Matthew "Kaito Sinclaire" Walsh.
// Copyright (C) 2012-2020 by Sonic Team Junior. // Copyright (C) 2012-2020 by Sonic Team Junior.
// //
@ -138,7 +139,7 @@ typedef enum
#define MAXEMBLEMS 512 #define MAXEMBLEMS 512
#define MAXUNLOCKABLES MAXCONDITIONSETS #define MAXUNLOCKABLES MAXCONDITIONSETS
#define CHALLENGEGRIDHEIGHT 5 #define CHALLENGEGRIDHEIGHT 4
#ifdef DEVELOP #ifdef DEVELOP
#define CHALLENGEGRIDLOOPWIDTH 3 #define CHALLENGEGRIDLOOPWIDTH 3
#else #else
@ -192,12 +193,21 @@ void M_NewGameDataStruct(void);
// Challenges menu stuff // Challenges menu stuff
void M_PopulateChallengeGrid(void); void M_PopulateChallengeGrid(void);
UINT8 *M_ChallengeGridExtraData(void);
struct challengegridextradata_t
{
UINT8 flags;
UINT8 flip;
};
void M_UpdateChallengeGridExtraData(challengegridextradata_t *extradata);
#define CHE_NONE 0 #define CHE_NONE 0
#define CHE_HINT 1 #define CHE_HINT 1
#define CHE_CONNECTEDLEFT (1<<1) #define CHE_CONNECTEDLEFT (1<<1)
#define CHE_CONNECTEDUP (1<<2) #define CHE_CONNECTEDUP (1<<2)
#define CHE_DONTDRAW (CHE_CONNECTEDLEFT|CHE_CONNECTEDUP) #define CHE_DONTDRAW (CHE_CONNECTEDLEFT|CHE_CONNECTEDUP)
char *M_BuildConditionSetString(UINT8 unlockid); char *M_BuildConditionSetString(UINT8 unlockid);
#define DESCRIPTIONWIDTH 170 #define DESCRIPTIONWIDTH 170

View file

@ -72,7 +72,7 @@ static void M_ChallengesAutoFocus(UINT8 unlockid, boolean fresh)
continue; continue;
} }
if (challengesmenu.extradata[i] & CHE_CONNECTEDLEFT) if (challengesmenu.extradata[i].flags & CHE_CONNECTEDLEFT)
{ {
// no need to check for CHE_CONNECTEDUP in linear iteration // no need to check for CHE_CONNECTEDUP in linear iteration
continue; continue;
@ -84,6 +84,16 @@ static void M_ChallengesAutoFocus(UINT8 unlockid, boolean fresh)
challengesmenu.col = challengesmenu.hilix = i/CHALLENGEGRIDHEIGHT; challengesmenu.col = challengesmenu.hilix = i/CHALLENGEGRIDHEIGHT;
challengesmenu.row = challengesmenu.hiliy = i%CHALLENGEGRIDHEIGHT; challengesmenu.row = challengesmenu.hiliy = i%CHALLENGEGRIDHEIGHT;
// Begin animation
if (challengesmenu.extradata[i].flip == 0)
{
challengesmenu.extradata[i].flip =
(challengesmenu.pending
? (TILEFLIP_MAX/2)
: 1
);
}
if (fresh) if (fresh)
{ {
// We're just entering the menu. Immediately jump to the desired position... // We're just entering the menu. Immediately jump to the desired position...
@ -174,7 +184,12 @@ menu_t *M_InterruptMenuWithChallenges(menu_t *desiredmenu)
M_PopulateChallengeGrid(); M_PopulateChallengeGrid();
if (gamedata->challengegrid) if (gamedata->challengegrid)
challengesmenu.extradata = M_ChallengeGridExtraData(); {
challengesmenu.extradata = Z_Calloc(
(gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT * sizeof(challengegridextradata_t)),
PU_STATIC, NULL);
M_UpdateChallengeGridExtraData(challengesmenu.extradata);
}
memset(setup_explosions, 0, sizeof(setup_explosions)); memset(setup_explosions, 0, sizeof(setup_explosions));
memset(&challengesmenu.unlockcount, 0, sizeof(challengesmenu.unlockcount)); memset(&challengesmenu.unlockcount, 0, sizeof(challengesmenu.unlockcount));
@ -256,7 +271,8 @@ void M_Challenges(INT32 choice)
void M_ChallengesTick(void) void M_ChallengesTick(void)
{ {
const UINT8 pid = 0; const UINT8 pid = 0;
UINT8 i, newunlock = MAXUNLOCKABLES; UINT16 i;
UINT8 newunlock = MAXUNLOCKABLES;
// Ticking // Ticking
challengesmenu.ticker++; challengesmenu.ticker++;
@ -270,6 +286,29 @@ void M_ChallengesTick(void)
challengesmenu.unlockcount[CC_ANIM]--; challengesmenu.unlockcount[CC_ANIM]--;
M_CupSelectTick(); M_CupSelectTick();
// Update tile flip state.
if (challengesmenu.extradata != NULL)
{
UINT16 id = (challengesmenu.hilix * CHALLENGEGRIDHEIGHT) + challengesmenu.hiliy;
boolean seeeveryone = M_MenuButtonHeld(pid, MBT_R);
boolean allthewaythrough;
UINT8 maxflip;
for (i = 0; i < (CHALLENGEGRIDHEIGHT * gamedata->challengegridwidth); i++)
{
allthewaythrough = (!seeeveryone && !challengesmenu.pending && i != id);
maxflip = ((seeeveryone || !allthewaythrough) ? (TILEFLIP_MAX/2) : TILEFLIP_MAX);
if ((seeeveryone || (challengesmenu.extradata[i].flip > 0))
&& (challengesmenu.extradata[i].flip != maxflip))
{
challengesmenu.extradata[i].flip++;
if (challengesmenu.extradata[i].flip >= TILEFLIP_MAX)
{
challengesmenu.extradata[i].flip = 0;
}
}
}
}
if (challengesmenu.pending) if (challengesmenu.pending)
{ {
// Pending mode. // Pending mode.
@ -318,11 +357,15 @@ void M_ChallengesTick(void)
challengesmenu.unlockcount[CC_TALLY]++; challengesmenu.unlockcount[CC_TALLY]++;
challengesmenu.unlockcount[CC_ANIM]++; challengesmenu.unlockcount[CC_ANIM]++;
Z_Free(challengesmenu.extradata); if (challengesmenu.extradata)
if ((challengesmenu.extradata = M_ChallengeGridExtraData()))
{ {
unlockable_t *ref = &unlockables[challengesmenu.currentunlock]; unlockable_t *ref;
UINT16 bombcolor = SKINCOLOR_NONE; UINT16 bombcolor;
M_UpdateChallengeGridExtraData(challengesmenu.extradata);
ref = &unlockables[challengesmenu.currentunlock];
bombcolor = SKINCOLOR_NONE;
if (ref->color != SKINCOLOR_NONE && ref->color < numskincolors) if (ref->color != SKINCOLOR_NONE && ref->color < numskincolors)
{ {
@ -413,8 +456,7 @@ boolean M_ChallengesInputs(INT32 ch)
gamedata->challengegrid = NULL; gamedata->challengegrid = NULL;
gamedata->challengegridwidth = 0; gamedata->challengegridwidth = 0;
M_PopulateChallengeGrid(); M_PopulateChallengeGrid();
Z_Free(challengesmenu.extradata); M_UpdateChallengeGridExtraData(challengesmenu.extradata);
challengesmenu.extradata = M_ChallengeGridExtraData();
M_ChallengesAutoFocus(challengesmenu.currentunlock, true); M_ChallengesAutoFocus(challengesmenu.currentunlock, true);
@ -461,8 +503,8 @@ boolean M_ChallengesInputs(INT32 ch)
} }
if (!(challengesmenu.extradata[ if (!(challengesmenu.extradata[
(challengesmenu.col * CHALLENGEGRIDHEIGHT) (challengesmenu.col * CHALLENGEGRIDHEIGHT)
+ challengesmenu.row] + challengesmenu.row
& CHE_CONNECTEDUP)) ].flags & CHE_CONNECTEDUP))
{ {
break; break;
} }
@ -475,8 +517,8 @@ boolean M_ChallengesInputs(INT32 ch)
{ {
i = (challengesmenu.extradata[ i = (challengesmenu.extradata[
(challengesmenu.col * CHALLENGEGRIDHEIGHT) (challengesmenu.col * CHALLENGEGRIDHEIGHT)
+ challengesmenu.row] + challengesmenu.row
& CHE_CONNECTEDUP) ? 2 : 1; ].flags & CHE_CONNECTEDUP) ? 2 : 1;
while (i > 0) while (i > 0)
{ {
if (challengesmenu.row > 0) if (challengesmenu.row > 0)
@ -516,8 +558,8 @@ boolean M_ChallengesInputs(INT32 ch)
if (!(challengesmenu.extradata[ if (!(challengesmenu.extradata[
(challengesmenu.col * CHALLENGEGRIDHEIGHT) (challengesmenu.col * CHALLENGEGRIDHEIGHT)
+ challengesmenu.row] + challengesmenu.row
& CHE_CONNECTEDLEFT)) ].flags & CHE_CONNECTEDLEFT))
{ {
break; break;
} }
@ -531,8 +573,8 @@ boolean M_ChallengesInputs(INT32 ch)
{ {
i = (challengesmenu.extradata[ i = (challengesmenu.extradata[
(challengesmenu.col * CHALLENGEGRIDHEIGHT) (challengesmenu.col * CHALLENGEGRIDHEIGHT)
+ challengesmenu.row] + challengesmenu.row
& CHE_CONNECTEDLEFT) ? 2 : 1; ].flags & CHE_CONNECTEDLEFT) ? 2 : 1;
while (i > 0) while (i > 0)
{ {
// Slide the focus counter to movement, if we can. // Slide the focus counter to movement, if we can.
@ -570,12 +612,12 @@ boolean M_ChallengesInputs(INT32 ch)
{ {
// Adjust highlight coordinates up/to the left for large tiles. // Adjust highlight coordinates up/to the left for large tiles.
if (challengesmenu.hiliy > 0 && (challengesmenu.extradata[i] & CHE_CONNECTEDUP)) if (challengesmenu.hiliy > 0 && (challengesmenu.extradata[i].flags & CHE_CONNECTEDUP))
{ {
challengesmenu.hiliy--; challengesmenu.hiliy--;
} }
if ((challengesmenu.extradata[i] & CHE_CONNECTEDLEFT)) if ((challengesmenu.extradata[i].flags & CHE_CONNECTEDLEFT))
{ {
if (challengesmenu.hilix > 0) if (challengesmenu.hilix > 0)
{ {
@ -586,8 +628,14 @@ boolean M_ChallengesInputs(INT32 ch)
challengesmenu.hilix = gamedata->challengegridwidth-1; challengesmenu.hilix = gamedata->challengegridwidth-1;
} }
} }
i = (challengesmenu.hilix * CHALLENGEGRIDHEIGHT) + challengesmenu.hiliy;
} }
// Begin animation
if (challengesmenu.extradata[i].flip == 0)
challengesmenu.extradata[i].flip++;
return true; return true;
} }

View file

@ -552,7 +552,8 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
if (P_IsLocalPlayer(player) && !gamedata->collected[special->health-1]) if (P_IsLocalPlayer(player) && !gamedata->collected[special->health-1])
{ {
gamedata->collected[special->health-1] = gotcollected = true; gamedata->collected[special->health-1] = gotcollected = true;
M_UpdateUnlockablesAndExtraEmblems(true); if (!M_UpdateUnlockablesAndExtraEmblems(true))
S_StartSound(NULL, sfx_ncitem);
G_SaveGameData(); G_SaveGameData();
} }

View file

@ -1101,6 +1101,7 @@ sfxinfo_t S_sfx[NUMSFX] =
{"typri1", false, 64, 16, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // SA2 boss typewriting 1 {"typri1", false, 64, 16, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // SA2 boss typewriting 1
{"typri2", false, 64, 16, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // SA2 final boss-type typewriting {"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 {"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"},
// SRB2Kart - Drop target sounds // SRB2Kart - Drop target sounds
{"kdtrg1", false, 64, 16, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Low energy, SF_X8AWAYSOUND {"kdtrg1", false, 64, 16, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Low energy, SF_X8AWAYSOUND

View file

@ -1168,6 +1168,7 @@ typedef enum
sfx_typri1, sfx_typri1,
sfx_typri2, sfx_typri2,
sfx_eggspr, sfx_eggspr,
sfx_achiev,
// SRB2Kart - Drop target sounds // SRB2Kart - Drop target sounds
sfx_kdtrg1, sfx_kdtrg1,

View file

@ -209,6 +209,7 @@ TYPEDEF (conditionset_t);
TYPEDEF (emblem_t); TYPEDEF (emblem_t);
TYPEDEF (unlockable_t); TYPEDEF (unlockable_t);
TYPEDEF (gamedata_t); TYPEDEF (gamedata_t);
TYPEDEF (challengegridextradata_t);
// m_dllist.h // m_dllist.h
TYPEDEF (mdllistitem_t); TYPEDEF (mdllistitem_t);