From 7e7bd7dbb21fb5815cdcbd4a88d77fe921ffd2e5 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 27 May 2022 23:16:02 +0100 Subject: [PATCH] New `kartgametypepreference` cvar. * A "canon" adaptation of the community-created server option `lessbattlevotes`. * If set to "None", voting behaves as before. * If set to "Race" or "Battle". that gametype is considered the preference. * The voting screen is always operated from the perspective of the preferred gametype. * If you're in an un-preferred gametype, the third vote option will always allow you to continue the gametype. * If the preferred gametype is Race and you've just exited a Battle map, Encore may now appear on the second vote option. * A number of bugs with voting have been corrected. * If `kartencore` is on, the third vote option will now correctly have Encore applied. * If a custom EXE or malformed packet sends an Encore flag alongside a Battle gametype ID, actively strip it. * Just to note, clients do not enter Battle Encore with or without this change - this just prevents a promise the rest of the game couldn't fulfill. --- src/d_netcmd.c | 35 ++++++++++++++++++++++++----- src/d_netcmd.h | 1 + src/g_game.c | 60 +++++++++++++++++++++++++++++++------------------- src/g_game.h | 2 +- src/k_kart.c | 1 + src/y_inter.c | 5 +++-- 6 files changed, 72 insertions(+), 32 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 50bec910..a192feda 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -370,6 +370,8 @@ consvar_t cv_kartcomeback = {"kartcomeback", "On", CV_NETVAR|CV_CHEAT|CV_CALL|CV consvar_t cv_kartencore = {"kartencore", "Off", CV_NETVAR|CV_CALL|CV_NOINIT, CV_OnOff, KartEncore_OnChange, 0, NULL, NULL, 0, 0, NULL}; static CV_PossibleValue_t kartvoterulechanges_cons_t[] = {{0, "Never"}, {1, "Sometimes"}, {2, "Frequent"}, {3, "Always"}, {0, NULL}}; consvar_t cv_kartvoterulechanges = {"kartvoterulechanges", "Frequent", CV_NETVAR, kartvoterulechanges_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +static CV_PossibleValue_t kartgametypepreference_cons_t[] = {{-1, "None"}, {GT_RACE, "Race"}, {GT_MATCH, "Battle"}, {0, NULL}}; +consvar_t cv_kartgametypepreference = {"kartgametypepreference", "None", CV_NETVAR, kartgametypepreference_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; static CV_PossibleValue_t kartspeedometer_cons_t[] = {{0, "Off"}, {1, "Kilometers"}, {2, "Miles"}, {3, "Fracunits"}, {0, NULL}}; consvar_t cv_kartspeedometer = {"kartdisplayspeed", "Off", CV_SAVE, kartspeedometer_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; // use tics in display static CV_PossibleValue_t kartvoices_cons_t[] = {{0, "Never"}, {1, "Tasteful"}, {2, "Meme"}, {0, NULL}}; @@ -2397,13 +2399,14 @@ void D_SetupVote(void) UINT8 buf[5*2]; // four UINT16 maps (at twice the width of a UINT8), and two gametypes UINT8 *p = buf; INT32 i; - UINT8 secondgt = G_SometimesGetDifferentGametype(); + UINT8 gt = (cv_kartgametypepreference.value == -1) ? gametype : cv_kartgametypepreference.value; + UINT8 secondgt = G_SometimesGetDifferentGametype(gt); INT16 votebuffer[4] = {-1,-1,-1,0}; - if (cv_kartencore.value && G_RaceGametype()) - WRITEUINT8(p, (gametype|0x80)); + if (cv_kartencore.value && gt == GT_RACE) + WRITEUINT8(p, (gt|0x80)); else - WRITEUINT8(p, gametype); + WRITEUINT8(p, gt); WRITEUINT8(p, secondgt); secondgt &= ~0x80; @@ -2413,9 +2416,9 @@ void D_SetupVote(void) if (i == 2) // sometimes a different gametype m = G_RandMap(G_TOLFlag(secondgt), prevmap, false, 0, true, votebuffer); else if (i >= 3) // unknown-random and force-unknown MAP HELL - m = G_RandMap(G_TOLFlag(gametype), prevmap, false, (i-2), (i < 4), votebuffer); + m = G_RandMap(G_TOLFlag(gt), prevmap, false, (i-2), (i < 4), votebuffer); else - m = G_RandMap(G_TOLFlag(gametype), prevmap, false, 0, true, votebuffer); + m = G_RandMap(G_TOLFlag(gt), prevmap, false, 0, true, votebuffer); if (i < 3) votebuffer[min(i, 2)] = m; // min() is a dumb workaround for gcc 4.4 array-bounds error WRITEUINT16(p, m); @@ -5136,9 +5139,17 @@ static void Got_SetupVotecmd(UINT8 **cp, INT32 playernum) return; } + // Get gametype data. gt = (UINT8)READUINT8(*cp); secondgt = (UINT8)READUINT8(*cp); + // Strip illegal Encore flag. + if (gt == (GT_MATCH|0x80)) + { + gt &= ~0x80; + } + + // Apply most data. for (i = 0; i < 4; i++) { votelevels[i][0] = (UINT16)READUINT16(*cp); @@ -5147,8 +5158,20 @@ static void Got_SetupVotecmd(UINT8 **cp, INT32 playernum) P_AllocMapHeader(votelevels[i][0]); } + // Correct third entry's gametype/Encore status. votelevels[2][1] = secondgt; + // If third entry has an illelegal Encore flag... + if (secondgt == (GT_MATCH|0x80)) + { + votelevels[2][1] &= ~0x80; + // Apply it to the second entry instead, gametype permitting! + if (gt != GT_MATCH) + { + votelevels[1][1] |= 0x80; + } + } + G_SetGamestate(GS_VOTING); Y_StartVote(); } diff --git a/src/d_netcmd.h b/src/d_netcmd.h index 1e158808..ecb5c26f 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -118,6 +118,7 @@ extern consvar_t cv_kartfrantic; extern consvar_t cv_kartcomeback; extern consvar_t cv_kartencore; extern consvar_t cv_kartvoterulechanges; +extern consvar_t cv_kartgametypepreference; extern consvar_t cv_kartspeedometer; extern consvar_t cv_kartvoices; diff --git a/src/g_game.c b/src/g_game.c index 9bd4da47..29cdf311 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3401,35 +3401,47 @@ boolean G_BattleGametype(void) // // Oh, yeah, and we sometimes flip encore mode on here too. // -INT16 G_SometimesGetDifferentGametype(void) +UINT8 G_SometimesGetDifferentGametype(UINT8 prefgametype) { - boolean encorepossible = (M_SecretUnlocked(SECRET_ENCORE) && G_RaceGametype()); + // Most of the gametype references in this condition are intentionally not prefgametype. + // This is so a server CAN continue playing a gametype if they like the taste of it. + // The encore check needs prefgametype so can't use G_RaceGametype... + boolean encorepossible = (M_SecretUnlocked(SECRET_ENCORE) + && (gametype == GT_RACE || prefgametype == GT_RACE)); + boolean encoreactual = false; + UINT8 encoremodifier = 0; + + if (encorepossible) + { + switch (cv_kartvoterulechanges.value) + { + case 3: // always + encoreactual = true; + break; + case 2: // frequent + encoreactual = M_RandomChance(FRACUNIT>>1); + break; + case 1: // sometimes + encoreactual = M_RandomChance(FRACUNIT>>2); + break; + default: + break; + } + if (encoreactual != (boolean)cv_kartencore.value) + encoremodifier = 0x80; + } if (!cv_kartvoterulechanges.value) // never - return gametype; + return (gametype|encoremodifier); if (randmapbuffer[NUMMAPS] > 0 && (encorepossible || cv_kartvoterulechanges.value != 3)) { randmapbuffer[NUMMAPS]--; - if (encorepossible) + if (cv_kartvoterulechanges.value == 3) // always { - switch (cv_kartvoterulechanges.value) - { - case 3: // always - randmapbuffer[NUMMAPS] = 0; // gotta prep this in case it isn't already set - break; - case 2: // frequent - encorepossible = M_RandomChance(FRACUNIT>>1); - break; - case 1: // sometimes - default: - encorepossible = M_RandomChance(FRACUNIT>>2); - break; - } - if (encorepossible != (boolean)cv_kartencore.value) - return (gametype|0x80); + randmapbuffer[NUMMAPS] = 0; // gotta prep this in case it isn't already set } - return gametype; + return (gametype|encoremodifier); } switch (cv_kartvoterulechanges.value) // okay, we're having a gametype change! when's the next one, luv? @@ -3447,9 +3459,11 @@ INT16 G_SometimesGetDifferentGametype(void) break; } - if (gametype == GT_MATCH) - return GT_RACE; - return GT_MATCH; + // Only this response is prefgametype-based. + // Also intentionally does not use encoremodifier! + if (prefgametype == GT_MATCH) + return (GT_RACE); + return (GT_MATCH); } // diff --git a/src/g_game.h b/src/g_game.h index 493be5d4..d77f4268 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -290,7 +290,7 @@ boolean G_GametypeUsesLives(void); boolean G_GametypeHasTeams(void); boolean G_GametypeHasSpectators(void); boolean G_BattleGametype(void); -INT16 G_SometimesGetDifferentGametype(void); +UINT8 G_SometimesGetDifferentGametype(UINT8 prefgametype); UINT8 G_GetGametypeColor(INT16 gt); boolean G_RaceGametype(void); boolean G_TagGametype(void); diff --git a/src/k_kart.c b/src/k_kart.c index a326eea6..cb0b3e12 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -575,6 +575,7 @@ void K_RegisterKartStuff(void) CV_RegisterVar(&cv_kartcomeback); CV_RegisterVar(&cv_kartencore); CV_RegisterVar(&cv_kartvoterulechanges); + CV_RegisterVar(&cv_kartgametypepreference); CV_RegisterVar(&cv_kartspeedometer); CV_RegisterVar(&cv_kartvoices); CV_RegisterVar(&cv_karteliminatelast); diff --git a/src/y_inter.c b/src/y_inter.c index a6dd2d81..e08448a2 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -1445,6 +1445,7 @@ void Y_VoteTicker(void) void Y_StartVote(void) { INT32 i = 0; + UINT8 prefgametype = (votelevels[0][1] & ~0x80); votetic = -1; @@ -1453,8 +1454,8 @@ void Y_StartVote(void) I_Error("voteendtic is dirty"); #endif - widebgpatch = W_CachePatchName(((gametype == GT_MATCH) ? "BATTLSCW" : "INTERSCW"), PU_STATIC); - bgpatch = W_CachePatchName(((gametype == GT_MATCH) ? "BATTLSCR" : "INTERSCR"), PU_STATIC); + widebgpatch = W_CachePatchName(((prefgametype == GT_MATCH) ? "BATTLSCW" : "INTERSCW"), PU_STATIC); + bgpatch = W_CachePatchName(((prefgametype == GT_MATCH) ? "BATTLSCR" : "INTERSCR"), PU_STATIC); cursor = W_CachePatchName("M_CURSOR", PU_STATIC); cursor1 = W_CachePatchName("P1CURSOR", PU_STATIC); cursor2 = W_CachePatchName("P2CURSOR", PU_STATIC);