diff --git a/src/g_game.c b/src/g_game.c index e522d82e2..1919ecb0c 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4359,7 +4359,7 @@ void G_LoadGameSettings(void) } #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 // Loads the main data file, which stores information such as emblems found, etc. @@ -4369,6 +4369,7 @@ void G_LoadGameData(void) UINT32 versionID; UINT8 versionMinor; UINT8 rtemp; + boolean gridunusable = false; savebuffer_t save = {0}; //For records @@ -4423,6 +4424,10 @@ void G_LoadGameData(void) P_SaveBufferFree(&save); 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->matchesplayed = READUINT32(save.p); @@ -4469,21 +4474,34 @@ void G_LoadGameData(void) i += j; } - gamedata->challengegridwidth = READUINT16(save.p); - Z_Free(gamedata->challengegrid); - if (gamedata->challengegridwidth) + if (gridunusable) { - 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); - } + UINT16 burn = READUINT16(save.p); // Previous challengegridwidth + UINT8 height = (versionMinor > 0) ? CHALLENGEGRIDHEIGHT : 5; + save.p += (burn * height * sizeof(UINT8)); // Step over previous grid data + + gamedata->challengegridwidth = 0; + Z_Free(gamedata->challengegrid); + gamedata->challengegrid = NULL; } 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); diff --git a/src/info.c b/src/info.c index 2c22b4bf4..4807869e6 100644 --- a/src/info.c +++ b/src/info.c @@ -8037,7 +8037,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // missilestate S_SPRK1, // deathstate S_NULL, // xdeathstate - sfx_ncitem, // deathsound + sfx_None, // deathsound 1, // speed 16*FRACUNIT, // radius 30*FRACUNIT, // height diff --git a/src/k_hud.h b/src/k_hud.h index b80760c2c..e9b0603f2 100644 --- a/src/k_hud.h +++ b/src/k_hud.h @@ -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_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_icon[2]; extern patch_t *kp_capsuletarget_far[2]; diff --git a/src/k_menu.h b/src/k_menu.h index ec6a96111..fb08ff4ab 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -1137,6 +1137,8 @@ void M_DrawAddons(void); #define CC_ANIM 3 #define CC_MAX 4 +#define TILEFLIP_MAX 16 + // Keep track of some pause menu data for visual goodness. extern struct challengesmenu_s { @@ -1151,7 +1153,7 @@ extern struct challengesmenu_s { SINT8 row, hilix, focusx; UINT8 col, hiliy; - UINT8 *extradata; + challengegridextradata_t *extradata; boolean pending; boolean requestnew; diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 32476585a..5f5f69726 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -1479,7 +1479,7 @@ static void M_DrawCharSelectPreview(UINT8 num) static void M_DrawCharSelectExplosions(boolean charsel, INT16 basex, INT16 basey) { UINT8 i; - INT16 quadx = 0, quady = 0; + INT16 quadx = 2, quady = 2, mul = 22; 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); quady = 4 * (setup_explosions[i].y / 3); + mul = 16; } colormap = R_GetTranslationColormap(TC_DEFAULT, setup_explosions[i].color, GTC_MENUCACHE); V_DrawMappedPatch( - basex + (setup_explosions[i].x*16) + quadx - 6, - basey + (setup_explosions[i].y*16) + quady - 6, + basex + (setup_explosions[i].x*mul) + quadx - 6, + basey + (setup_explosions[i].y*mul) + quady - 6, 0, W_CachePatchName(va("CHCNFRM%d", frame), PU_CACHE), colormap ); @@ -4516,10 +4517,11 @@ static void M_DrawChallengeTile(INT16 i, INT16 j, INT32 x, INT32 y, boolean hili { unlockable_t *ref = NULL; patch_t *pat = missingpat; - UINT8 *colormap = NULL; - fixed_t siz; + UINT8 *colormap = NULL, *bgmap = NULL; + fixed_t siz, accordion; UINT8 id, num; - UINT32 edgelength; + boolean unlockedyet; + boolean categoryside; id = (i * CHALLENGEGRIDHEIGHT) + j; 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. 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 ((gamedata->unlocked[num] == false) - || (challengesmenu.pending && num == challengesmenu.currentunlock && challengesmenu.unlockanim <= UNLOCKTIME)) + // If we aren't unlocked yet, return early. + if (!unlockedyet) { - V_DrawFill(x+1, y+1, edgelength, edgelength, - ((challengesmenu.extradata[id] == CHE_HINT) ? 132 : 11)); + UINT32 flags = 0; + + 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; } - 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); 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); } } - else switch (ref->type) + else { - case SECRET_SKIN: + UINT8 iconid = 0; + switch (ref->type) { - INT32 skin = M_UnlockableSkinNum(ref); - if (skin != -1) + case SECRET_SKIN: { - colormap = R_GetTranslationColormap(skin, skins[skin].prefcolor, GTC_MENUCACHE); - pat = faceprefix[skin][(ref->majorunlock) ? FACE_WANTED : FACE_RANK]; + INT32 skin = M_UnlockableSkinNum(ref); + 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); - if (skin != -1) + pat = W_CachePatchName(va("UN_IC%02u%c", + iconid, + ref->majorunlock ? 'B' : 'A'), + PU_CACHE); + if (pat == missingpat) { - 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); + pat = W_CachePatchName(va("UN_IC%02u%c", + iconid, + 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 = FixedDiv(((ref->majorunlock) ? 32 : 16) << FRACBITS, siz); - V_SetClipRect( - (x+1) << FRACBITS, (y+1) << FRACBITS, - edgelength << FRACBITS, edgelength << FRACBITS, - 0 - ); - - V_DrawFixedPatch( - x*FRACUNIT, y*FRACUNIT, - siz, - 0, pat, - colormap - ); - - V_ClearClipRect(); + if (!siz) + ; // prevent div/0 + else if (ref->majorunlock) + { + V_DrawStretchyFixedPatch( + ((x + 5)*FRACUNIT) + (32*(FRACUNIT-accordion)/2), (y + 5)*FRACUNIT, + FixedDiv(32*accordion, siz), + FixedDiv(32 << FRACBITS, siz), + 0, pat, + colormap + ); + } + else + { + V_DrawStretchyFixedPatch( + ((x + 2)*FRACUNIT) + (16*(FRACUNIT-accordion)/2), (y + 2)*FRACUNIT, + FixedDiv(16*accordion, siz), + FixedDiv(16 << FRACBITS, siz), + 0, pat, + colormap + ); + } drawborder: if (!hili) @@ -4611,12 +4763,23 @@ drawborder: return; } - V_DrawFixedPatch( - x*FRACUNIT, y*FRACUNIT, - ((ref != NULL && ref->majorunlock) ? FRACUNIT*2 : FRACUNIT), - 0, kp_facehighlight[(challengesmenu.ticker / 4) % 8], - NULL - ); + { + boolean maj = (ref != NULL && ref->majorunlock); + char buffer[9]; + sprintf(buffer, "UN_RETA1"); + 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) @@ -4819,6 +4982,9 @@ static void M_DrawChallengePreview(INT32 x, INT32 y) } } +#define challengetransparentstrength 8 +#define challengesgridstep 22 + void M_DrawChallenges(void) { INT32 x = currentMenu->x, explodex, selectx; @@ -4828,8 +4994,25 @@ void M_DrawChallenges(void) 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); + + // 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) @@ -4838,43 +5021,45 @@ void M_DrawChallenges(void) goto challengedesc; } - x -= 16; + V_DrawFadeFill(0, y-2, BASEVIDWIDTH, 90, 0, 31, challengetransparentstrength); + + x -= (challengesgridstep-1); x += challengesmenu.offset; if (challengegridloops) { if (!challengesmenu.col && challengesmenu.hilix) - x -= gamedata->challengegridwidth*16; + x -= gamedata->challengegridwidth*challengesgridstep; 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; - x += 16; + x += challengesgridstep; } } else { if (gamedata->challengegridwidth & 1) - x += 8; + x += (challengesgridstep/2); i = gamedata->challengegridwidth-1; - explodex = x - (i*16)/2; - x += (i*16)/2; + explodex = x - (i*challengesgridstep)/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++) { - y += 16; + y += challengesgridstep; - if (challengesmenu.extradata[(i * CHALLENGEGRIDHEIGHT) + j] & CHE_DONTDRAW) + if (challengesmenu.extradata[(i * CHALLENGEGRIDHEIGHT) + j].flags & CHE_DONTDRAW) { continue; } @@ -4887,7 +5072,7 @@ void M_DrawChallenges(void) M_DrawChallengeTile(i, j, x, y, false); } - x -= 16; + x -= challengesgridstep; i--; if (challengegridloops && i < 0) { @@ -4903,7 +5088,7 @@ void M_DrawChallenges(void) challengesmenu.hilix, challengesmenu.hiliy, selectx, - currentMenu->y + (challengesmenu.hiliy*16), + currentMenu->y + (challengesmenu.hiliy*challengesgridstep), true); M_DrawCharSelectExplosions(false, explodex, currentMenu->y); @@ -4922,6 +5107,12 @@ challengedesc: { y = 120; + V_DrawScaledPatch(0, y, + (10-challengetransparentstrength)<unlocked[challengesmenu.currentunlock] == true) || ((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 #define STATSSTEP 10 diff --git a/src/m_cond.c b/src/m_cond.c index abc228d3a..070c5b9ea 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -1,5 +1,6 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- +// Copyright (C) 2022-2023 by Vivian "toaster" Grannell. // Copyright (C) 2012-2016 by Matthew "Kaito Sinclaire" Walsh. // 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 *extradata; boolean idchange; - if (!gamedata->challengegrid) + if (gamedata->challengegrid == NULL) { - return NULL; + return; } - extradata = Z_Malloc( - (gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT * sizeof(UINT8)), - PU_STATIC, NULL); - - if (!extradata) + if (extradata == NULL) { - I_Error("M_ChallengeGridExtraData: was not able to allocate extradata"); + return; } //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 (j = 0; j < CHALLENGEGRIDHEIGHT; j++) @@ -289,8 +296,6 @@ UINT8 *M_ChallengeGridExtraData(void) num = gamedata->challengegrid[id]; idchange = false; - extradata[id] = CHE_NONE; - // Empty spots in the grid are always unconnected. if (num >= MAXUNLOCKABLES) { @@ -304,13 +309,13 @@ UINT8 *M_ChallengeGridExtraData(void) work = gamedata->challengegrid[tempid]; if (work == num) { - extradata[id] = CHE_CONNECTEDUP; + extradata[id].flags = CHE_CONNECTEDUP; // Get the id to write extra hint data to. // 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); if (i > 0) { @@ -327,14 +332,14 @@ UINT8 *M_ChallengeGridExtraData(void) id = tempid; idchange = true; - if (extradata[id] == CHE_HINT) + if (extradata[id].flags == CHE_HINT) { continue; } } 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); // 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; } /*else @@ -368,13 +373,13 @@ UINT8 *M_ChallengeGridExtraData(void) } else if (work < MAXUNLOCKABLES && gamedata->unlocked[work]) { - extradata[id] = CHE_HINT; + extradata[id].flags = CHE_HINT; continue; } } // 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; } @@ -391,7 +396,7 @@ UINT8 *M_ChallengeGridExtraData(void) } else if (work < MAXUNLOCKABLES && gamedata->unlocked[work]) { - extradata[id] = CHE_HINT; + extradata[id].flags = CHE_HINT; continue; } } @@ -414,14 +419,12 @@ UINT8 *M_ChallengeGridExtraData(void) } else if (work < MAXUNLOCKABLES && gamedata->unlocked[work]) { - extradata[id] = CHE_HINT; + extradata[id].flags = CHE_HINT; continue; } } } } - - return extradata; } 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) { - S_StartSound(NULL, sfx_ncitem); + S_StartSound(NULL, sfx_achiev); } return true; } diff --git a/src/m_cond.h b/src/m_cond.h index 735894c71..367f3d720 100644 --- a/src/m_cond.h +++ b/src/m_cond.h @@ -1,5 +1,6 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- +// Copyright (C) 2022-2023 by Vivian "toaster" Grannell. // Copyright (C) 2012-2016 by Matthew "Kaito Sinclaire" Walsh. // Copyright (C) 2012-2020 by Sonic Team Junior. // @@ -138,7 +139,7 @@ typedef enum #define MAXEMBLEMS 512 #define MAXUNLOCKABLES MAXCONDITIONSETS -#define CHALLENGEGRIDHEIGHT 5 +#define CHALLENGEGRIDHEIGHT 4 #ifdef DEVELOP #define CHALLENGEGRIDLOOPWIDTH 3 #else @@ -192,12 +193,21 @@ void M_NewGameDataStruct(void); // Challenges menu stuff 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_HINT 1 #define CHE_CONNECTEDLEFT (1<<1) #define CHE_CONNECTEDUP (1<<2) #define CHE_DONTDRAW (CHE_CONNECTEDLEFT|CHE_CONNECTEDUP) + char *M_BuildConditionSetString(UINT8 unlockid); #define DESCRIPTIONWIDTH 170 diff --git a/src/menus/extras-challenges.c b/src/menus/extras-challenges.c index 583dc7a1a..a9d056cd4 100644 --- a/src/menus/extras-challenges.c +++ b/src/menus/extras-challenges.c @@ -72,7 +72,7 @@ static void M_ChallengesAutoFocus(UINT8 unlockid, boolean fresh) continue; } - if (challengesmenu.extradata[i] & CHE_CONNECTEDLEFT) + if (challengesmenu.extradata[i].flags & CHE_CONNECTEDLEFT) { // no need to check for CHE_CONNECTEDUP in linear iteration continue; @@ -84,6 +84,16 @@ static void M_ChallengesAutoFocus(UINT8 unlockid, boolean fresh) challengesmenu.col = challengesmenu.hilix = 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) { // 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(); 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(&challengesmenu.unlockcount, 0, sizeof(challengesmenu.unlockcount)); @@ -256,7 +271,8 @@ void M_Challenges(INT32 choice) void M_ChallengesTick(void) { const UINT8 pid = 0; - UINT8 i, newunlock = MAXUNLOCKABLES; + UINT16 i; + UINT8 newunlock = MAXUNLOCKABLES; // Ticking challengesmenu.ticker++; @@ -270,6 +286,29 @@ void M_ChallengesTick(void) challengesmenu.unlockcount[CC_ANIM]--; 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) { // Pending mode. @@ -318,11 +357,15 @@ void M_ChallengesTick(void) challengesmenu.unlockcount[CC_TALLY]++; challengesmenu.unlockcount[CC_ANIM]++; - Z_Free(challengesmenu.extradata); - if ((challengesmenu.extradata = M_ChallengeGridExtraData())) + if (challengesmenu.extradata) { - unlockable_t *ref = &unlockables[challengesmenu.currentunlock]; - UINT16 bombcolor = SKINCOLOR_NONE; + unlockable_t *ref; + UINT16 bombcolor; + + M_UpdateChallengeGridExtraData(challengesmenu.extradata); + + ref = &unlockables[challengesmenu.currentunlock]; + bombcolor = SKINCOLOR_NONE; if (ref->color != SKINCOLOR_NONE && ref->color < numskincolors) { @@ -413,8 +456,7 @@ boolean M_ChallengesInputs(INT32 ch) gamedata->challengegrid = NULL; gamedata->challengegridwidth = 0; M_PopulateChallengeGrid(); - Z_Free(challengesmenu.extradata); - challengesmenu.extradata = M_ChallengeGridExtraData(); + M_UpdateChallengeGridExtraData(challengesmenu.extradata); M_ChallengesAutoFocus(challengesmenu.currentunlock, true); @@ -461,8 +503,8 @@ boolean M_ChallengesInputs(INT32 ch) } if (!(challengesmenu.extradata[ (challengesmenu.col * CHALLENGEGRIDHEIGHT) - + challengesmenu.row] - & CHE_CONNECTEDUP)) + + challengesmenu.row + ].flags & CHE_CONNECTEDUP)) { break; } @@ -475,8 +517,8 @@ boolean M_ChallengesInputs(INT32 ch) { i = (challengesmenu.extradata[ (challengesmenu.col * CHALLENGEGRIDHEIGHT) - + challengesmenu.row] - & CHE_CONNECTEDUP) ? 2 : 1; + + challengesmenu.row + ].flags & CHE_CONNECTEDUP) ? 2 : 1; while (i > 0) { if (challengesmenu.row > 0) @@ -516,8 +558,8 @@ boolean M_ChallengesInputs(INT32 ch) if (!(challengesmenu.extradata[ (challengesmenu.col * CHALLENGEGRIDHEIGHT) - + challengesmenu.row] - & CHE_CONNECTEDLEFT)) + + challengesmenu.row + ].flags & CHE_CONNECTEDLEFT)) { break; } @@ -531,8 +573,8 @@ boolean M_ChallengesInputs(INT32 ch) { i = (challengesmenu.extradata[ (challengesmenu.col * CHALLENGEGRIDHEIGHT) - + challengesmenu.row] - & CHE_CONNECTEDLEFT) ? 2 : 1; + + challengesmenu.row + ].flags & CHE_CONNECTEDLEFT) ? 2 : 1; while (i > 0) { // 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. - if (challengesmenu.hiliy > 0 && (challengesmenu.extradata[i] & CHE_CONNECTEDUP)) + if (challengesmenu.hiliy > 0 && (challengesmenu.extradata[i].flags & CHE_CONNECTEDUP)) { challengesmenu.hiliy--; } - if ((challengesmenu.extradata[i] & CHE_CONNECTEDLEFT)) + if ((challengesmenu.extradata[i].flags & CHE_CONNECTEDLEFT)) { if (challengesmenu.hilix > 0) { @@ -586,8 +628,14 @@ boolean M_ChallengesInputs(INT32 ch) 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; } diff --git a/src/p_inter.c b/src/p_inter.c index 8a13e5f8c..c9121620e 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -552,7 +552,8 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (P_IsLocalPlayer(player) && !gamedata->collected[special->health-1]) { gamedata->collected[special->health-1] = gotcollected = true; - M_UpdateUnlockablesAndExtraEmblems(true); + if (!M_UpdateUnlockablesAndExtraEmblems(true)) + S_StartSound(NULL, sfx_ncitem); G_SaveGameData(); } diff --git a/src/sounds.c b/src/sounds.c index 207d2713c..0fc59206a 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -1101,6 +1101,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"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 {"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 {"kdtrg1", false, 64, 16, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Low energy, SF_X8AWAYSOUND diff --git a/src/sounds.h b/src/sounds.h index b6f910c6f..46f1eedf8 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -1168,6 +1168,7 @@ typedef enum sfx_typri1, sfx_typri2, sfx_eggspr, + sfx_achiev, // SRB2Kart - Drop target sounds sfx_kdtrg1, diff --git a/src/typedef.h b/src/typedef.h index a38b018a0..632684d1e 100644 --- a/src/typedef.h +++ b/src/typedef.h @@ -209,6 +209,7 @@ TYPEDEF (conditionset_t); TYPEDEF (emblem_t); TYPEDEF (unlockable_t); TYPEDEF (gamedata_t); +TYPEDEF (challengegridextradata_t); // m_dllist.h TYPEDEF (mdllistitem_t);