From 03f9ff08473099b5a7f9c066bce019bd06167e6a Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 26 Jul 2023 14:20:46 +0100 Subject: [PATCH 1/5] Character Select menu: Put B, D on the right side of the PLAYER/profile name text, to avoid overlapping the player's eyes --- src/k_menudraw.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 8324cbada..d15e39d42 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -1633,17 +1633,17 @@ static void M_DrawCharSelectPreview(UINT8 num) if (p->showextra == false) { - V_DrawScaledPatch(x+9, y+2, 0, W_CachePatchName("FILEBACK", PU_CACHE)); - V_DrawScaledPatch(x, y+2, 0, W_CachePatchName(va("CHARSEL%c", letter), PU_CACHE)); + INT32 backx = x + ((num & 1) ? -1 : 11); + V_DrawScaledPatch(backx, y+2, 0, W_CachePatchName("FILEBACK", PU_CACHE)); + + V_DrawScaledPatch(x + ((num & 1) ? 44 : 0), y+2, 0, W_CachePatchName(va("CHARSEL%c", letter), PU_CACHE)); + + profile_t *pr = NULL; if (p->mdepth > CSSTEP_PROFILE) { - profile_t *pr = PR_GetProfile(p->profilen); - V_DrawCenteredFileString(x+16+18, y+2, 0, pr->profilename); - } - else - { - V_DrawFileString(x+16, y+2, 0, "PLAYER"); + pr = PR_GetProfile(p->profilen); } + V_DrawCenteredFileString(backx+26, y+2, 0, pr ? pr->profilename : "PLAYER"); } if (p->mdepth >= CSSTEP_FOLLOWER) From 23f479f365d24f2a6ec81a2808e9815170a2b2f4 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 26 Jul 2023 14:31:50 +0100 Subject: [PATCH 2/5] Intermission - DUEL mode Show players' appearances on intermissions with less than or equal to 2 players, in port priority order, to mimic Sonic 3 Competition. Also shows player letter and profile name in Match Race, to really drive the reference home. --- src/k_menu.h | 1 + src/k_menudraw.c | 2 +- src/y_inter.c | 109 ++++++++++++++++++++++++++++++++++++++++++++--- src/y_inter.h | 1 + 4 files changed, 105 insertions(+), 8 deletions(-) diff --git a/src/k_menu.h b/src/k_menu.h index ff7876ef8..ab3a26443 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -1155,6 +1155,7 @@ void M_DrawMessageMenu(void); void M_DrawImageDef(void); void M_DrawCharacterSelect(void); +boolean M_DrawCharacterSprite(INT16 x, INT16 y, INT16 skin, UINT8 spr2, UINT8 rotation, UINT32 frame, INT32 addflags, UINT8 *colormap); void M_DrawCupSelect(void); void M_DrawLevelSelect(void); diff --git a/src/k_menudraw.c b/src/k_menudraw.c index d15e39d42..5821e474c 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -1474,7 +1474,7 @@ static void M_DrawCharSelectCircle(setup_player_t *p, INT16 x, INT16 y) } // returns false if the character couldn't be rendered -static boolean M_DrawCharacterSprite(INT16 x, INT16 y, INT16 skin, UINT8 spr2, UINT8 rotation, UINT32 frame, INT32 addflags, UINT8 *colormap) +boolean M_DrawCharacterSprite(INT16 x, INT16 y, INT16 skin, UINT8 spr2, UINT8 rotation, UINT32 frame, INT32 addflags, UINT8 *colormap) { UINT8 spr; spritedef_t *sprdef; diff --git a/src/y_inter.c b/src/y_inter.c index 935691a17..524c84fd9 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -178,6 +178,8 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32)) data.numplayers = 0; data.roundnum = 0; + data.isduel = (numplayersingame <= 2); + for (j = 0; j < numplayersingame; j++) { for (i = 0; i < MAXPLAYERS; i++) @@ -441,7 +443,7 @@ void Y_PlayerStandingsDrawer(y_data_t *standings, INT32 xoffset) INT32 x, y; INT32 x2, returny, inwardshim = 0; - boolean verticalresults = (standings->numplayers < 4); + boolean verticalresults = (standings->numplayers < 4 && (standings->numplayers == 1 || standings->isduel == false)); boolean datarightofcolumn = false; boolean drawping = (netgame && gamestate == GS_LEVEL); @@ -488,7 +490,11 @@ void Y_PlayerStandingsDrawer(y_data_t *standings, INT32 xoffset) y = 106 - (heightcount * yspacing)/2; - if (y < 70) + if (standings->isduel) + { + y += 38; + } + else if (y < 70) { // One sanity check. y = 70; @@ -502,7 +508,20 @@ void Y_PlayerStandingsDrawer(y_data_t *standings, INT32 xoffset) : P_IsLocalPlayer ); - for (i = 0; i < standings->numplayers; i++) + boolean doreverse = ( + standings->isduel && standings->numplayers == 2 + && standings->num[0] > standings->num[1] + ); + + i = 0; + UINT8 halfway = (standings->numplayers-1)/2; + if (doreverse) + { + i = standings->numplayers-1; + halfway++; + } + + do // don't use "continue" in this loop just for sanity's sake { const UINT8 pnum = standings->num[i]; @@ -512,6 +531,67 @@ void Y_PlayerStandingsDrawer(y_data_t *standings, INT32 xoffset) standings->num[i] = MAXPLAYERS; // this should be the only field setting in this function else { + UINT8 *charcolormap = NULL; + if (standings->color[i] != SKINCOLOR_NONE) + { + charcolormap = R_GetTranslationColormap(standings->character[i], standings->color[i], GTC_CACHE); + } + + if (standings->isduel) + { + INT32 duelx = x + 25 - inwardshim/2, duely = y - 80; + if (datarightofcolumn) + duelx += inwardshim/2; + else + duelx -= inwardshim/2; + + V_DrawScaledPatch(duelx, duely, 0, W_CachePatchName("DUELGRPH", PU_CACHE)); + V_DrawScaledPatch(duelx + 8, duely + 9, V_TRANSLUCENT, W_CachePatchName("PREVBACK", PU_CACHE)); + + UINT8 spr2 = SPR2_STIN; + if (standings->pos[i] == 2) + { + spr2 = (datarightofcolumn ? SPR2_STGR : SPR2_STGL); + } + + M_DrawCharacterSprite( + duelx + 40, duely + 78, + standings->character[i], + spr2, + (datarightofcolumn ? 1 : 7), + 0, + 0, + charcolormap + ); + + if (!netgame) + { + UINT8 j, profilen = 0; + for (j = 0; j <= splitscreen; j++) + { + if (pnum == g_localplayers[j]) + break; + } + + if (j > splitscreen) + continue; + + profilen = cv_lastprofile[j].value; + + duelx += 8; + duely += 5; + + INT32 backx = duelx + (datarightofcolumn ? -1 : 11); + + V_DrawScaledPatch(backx, duely, 0, W_CachePatchName("FILEBACK", PU_CACHE)); + + V_DrawScaledPatch(duelx + (datarightofcolumn ? 44 : 0), duely, 0, W_CachePatchName(va("CHARSEL%c", 'A' + j), PU_CACHE)); + + profile_t *pr = PR_GetProfile(profilen); + V_DrawCenteredFileString(backx+26, duely, 0, pr ? pr->profilename : "PLAYER"); + } + } + // Apply the jitter offset (later reversed) if (standings->jitter[pnum] > 0) y--; @@ -522,12 +602,15 @@ void Y_PlayerStandingsDrawer(y_data_t *standings, INT32 xoffset) if (standings->color[i] != SKINCOLOR_NONE) { - UINT8 *charcolormap; if ((players[pnum].pflags & PF_NOCONTEST) && players[pnum].bot) { // RETIRED !! - charcolormap = R_GetTranslationColormap(TC_DEFAULT, standings->color[i], GTC_CACHE); - V_DrawMappedPatch(x+14, y-5, 0, W_CachePatchName("MINIDEAD", PU_CACHE), charcolormap); + V_DrawMappedPatch( + x+14, y-5, + 0, + W_CachePatchName("MINIDEAD", PU_CACHE), + R_GetTranslationColormap(TC_DEFAULT, standings->color[i], GTC_CACHE) + ); } else { @@ -645,7 +728,7 @@ void Y_PlayerStandingsDrawer(y_data_t *standings, INT32 xoffset) y += yspacing; - if (verticalresults == false && i == (standings->numplayers-1)/2) + if (verticalresults == false && i == halfway) { x = 169 + xoffset - inwardshim; y = returny; @@ -653,7 +736,19 @@ void Y_PlayerStandingsDrawer(y_data_t *standings, INT32 xoffset) datarightofcolumn = true; x2 = x + 118 + 5; } + + if (!doreverse) + { + if (++i < standings->numplayers) + continue; + break; + } + + if (i == 0) + break; + i--; } + while (true); } // diff --git a/src/y_inter.h b/src/y_inter.h index 27a85fa6d..6995023db 100644 --- a/src/y_inter.h +++ b/src/y_inter.h @@ -22,6 +22,7 @@ typedef struct boolean gotthrough; // show "got through" boolean showrank; // show rank-restricted queue entry at the end, if it exists boolean encore; // encore mode + boolean isduel; // duel mode UINT8 roundnum; // round number char headerstring[64]; // holds levelnames up to 64 characters From 8553581d806517f23535caaa100bd21290639f11 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 26 Jul 2023 15:51:39 +0100 Subject: [PATCH 3/5] Improved behaviour for skipping second half of intermission in offline games Instead of tying it directly to the number of players, instead base it on whether the points are important to keep track of. - Match Race or Time Attack - No next map override, since points will persist to that one - No maps queued, so points aren't relevant - OR maps are queued but you haven't started them yet, so the points will be discarded --- src/y_inter.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/y_inter.c b/src/y_inter.c index 524c84fd9..64801bd1c 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -1786,9 +1786,22 @@ void Y_StartIntermission(void) // Prevent a weird bug timer = 1; } - else if (nump < 2 && !netgame) + else if ( + ( // Match Race or Time Attack + netgame == false + && grandprixinfo.gp == false + ) + && ( + modeattacking != ATTACKING_NONE // Definitely never another map + || ( // Any level sequence? + roundqueue.size == 0 // No maps queued, points aren't relevant + || roundqueue.position == 0 // OR points from this round will be discarded + ) + ) + ) { // No PWR/global score, skip it + // (the above is influenced by G_GetNextMap) timer /= 2; } else From 2b4cd831e1097f1bc666e9a952f05e673fedcf91 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 26 Jul 2023 16:51:05 +0100 Subject: [PATCH 4/5] Fix on-screen alignment of Duel Intermission boxes - Now more consistent between time/score and rankings mode - Symmetrical if you flipped the screen, no slight rightward bias in placement --- src/y_inter.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/y_inter.c b/src/y_inter.c index 64801bd1c..b074c9e4a 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -539,11 +539,8 @@ void Y_PlayerStandingsDrawer(y_data_t *standings, INT32 xoffset) if (standings->isduel) { - INT32 duelx = x + 25 - inwardshim/2, duely = y - 80; - if (datarightofcolumn) - duelx += inwardshim/2; - else - duelx -= inwardshim/2; + INT32 duelx = x + 22 + (datarightofcolumn ? inwardshim : -inwardshim); + INT32 duely = y - 80; V_DrawScaledPatch(duelx, duely, 0, W_CachePatchName("DUELGRPH", PU_CACHE)); V_DrawScaledPatch(duelx + 8, duely + 9, V_TRANSLUCENT, W_CachePatchName("PREVBACK", PU_CACHE)); From 1b5d59746f49fd1c38b733004f579d73700aa2f6 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 28 Jul 2023 22:21:37 +0100 Subject: [PATCH 5/5] Adjustments/fixes to Duel Intermission view - Always show, even in online - Add Egga Channel/CPU icon if not a local player-controlled character - This fixes an infinite loop crash that could previously affect 1v1s VS bots --- src/y_inter.c | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/src/y_inter.c b/src/y_inter.c index b074c9e4a..bfaa71521 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -561,31 +561,38 @@ void Y_PlayerStandingsDrawer(y_data_t *standings, INT32 xoffset) charcolormap ); - if (!netgame) + duelx += 8; + duely += 5; + + UINT8 j; + for (j = 0; j <= splitscreen; j++) { - UINT8 j, profilen = 0; - for (j = 0; j <= splitscreen; j++) - { - if (pnum == g_localplayers[j]) - break; - } + if (pnum == g_localplayers[j]) + break; + } - if (j > splitscreen) - continue; + INT32 letterpos = duelx + (datarightofcolumn ? 44 : 0); - profilen = cv_lastprofile[j].value; + if (j > splitscreen) + { + V_DrawScaledPatch(letterpos, duely, 0, W_CachePatchName(va("CHAR%s", (players[pnum].bot ? "CPU" : "EGGA")), PU_CACHE)); + } + else + { + duelx += (datarightofcolumn ? -1 : 11); - duelx += 8; - duely += 5; + UINT8 profilen = cv_lastprofile[j].value; - INT32 backx = duelx + (datarightofcolumn ? -1 : 11); + V_DrawScaledPatch(duelx, duely, 0, W_CachePatchName("FILEBACK", PU_CACHE)); - V_DrawScaledPatch(backx, duely, 0, W_CachePatchName("FILEBACK", PU_CACHE)); + if (datarightofcolumn && j == 0) + letterpos++; // A is one pixel thinner - V_DrawScaledPatch(duelx + (datarightofcolumn ? 44 : 0), duely, 0, W_CachePatchName(va("CHARSEL%c", 'A' + j), PU_CACHE)); + V_DrawScaledPatch(letterpos, duely, 0, W_CachePatchName(va("CHARSEL%c", 'A' + j), PU_CACHE)); profile_t *pr = PR_GetProfile(profilen); - V_DrawCenteredFileString(backx+26, duely, 0, pr ? pr->profilename : "PLAYER"); + + V_DrawCenteredFileString(duelx+26, duely, 0, pr ? pr->profilename : "PLAYER"); } }