From 7edec43d726f7fa96cdba5c0e6957f314cce9c3f Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 28 Aug 2022 23:15:45 +0100 Subject: [PATCH] Port Gametype Preference and associated changes Notably, makes the PWR-based Encore scrambling component of G_SometimesGetDifferentGametype WAY less spaghettified. --- src/d_clisrv.c | 5 ++- src/d_netcmd.c | 41 ++++++++++++++++++------ src/d_netcmd.h | 1 + src/g_game.c | 86 ++++++++++++++++++++++++++++---------------------- src/g_game.h | 3 +- src/k_kart.c | 1 + src/y_inter.c | 9 +++--- 7 files changed, 93 insertions(+), 53 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 19c45d82b..4507652d5 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -890,6 +890,9 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime) UINT8 *p; size_t mirror_length; const char *httpurl = cv_httpsource.string; + UINT8 prefgametype = (cv_kartgametypepreference.value == -1) + ? gametype + : cv_kartgametypepreference.value; netbuffer->packettype = PT_SERVERINFO; netbuffer->u.serverinfo._255 = 255; @@ -914,7 +917,7 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime) else netbuffer->u.serverinfo.refusereason = 0; - strncpy(netbuffer->u.serverinfo.gametypename, Gametype_Names[gametype], + strncpy(netbuffer->u.serverinfo.gametypename, Gametype_Names[prefgametype], sizeof netbuffer->u.serverinfo.gametypename); netbuffer->u.serverinfo.modifiedgame = (UINT8)modifiedgame; netbuffer->u.serverinfo.cheatsenabled = CV_CheatsEnabled(); diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 9b310eb66..e5f57c6ec 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -383,6 +383,8 @@ static CV_PossibleValue_t kartencore_cons_t[] = {{-1, "Auto"}, {0, "Off"}, {1, " consvar_t cv_kartencore = CVAR_INIT ("kartencore", "Auto", CV_NETVAR|CV_CALL|CV_NOINIT, kartencore_cons_t, KartEncore_OnChange); static CV_PossibleValue_t kartvoterulechanges_cons_t[] = {{0, "Never"}, {1, "Sometimes"}, {2, "Frequent"}, {3, "Always"}, {0, NULL}}; consvar_t cv_kartvoterulechanges = CVAR_INIT ("kartvoterulechanges", "Frequent", CV_NETVAR, kartvoterulechanges_cons_t, NULL); +static CV_PossibleValue_t kartgametypepreference_cons_t[] = {{-1, "None"}, {GT_RACE, "Race"}, {GT_BATTLE, "Battle"}, {0, NULL}}; +consvar_t cv_kartgametypepreference = CVAR_INIT ("kartgametypepreference", "None", CV_NETVAR, kartgametypepreference_cons_t, NULL); static CV_PossibleValue_t kartspeedometer_cons_t[] = {{0, "Off"}, {1, "Percentage"}, {2, "Kilometers"}, {3, "Miles"}, {4, "Fracunits"}, {0, NULL}}; consvar_t cv_kartspeedometer = CVAR_INIT ("kartdisplayspeed", "Percentage", CV_SAVE, kartspeedometer_cons_t, NULL); // use tics in display static CV_PossibleValue_t kartvoices_cons_t[] = {{0, "Never"}, {1, "Tasteful"}, {2, "Meme"}, {0, NULL}}; @@ -2436,27 +2438,28 @@ 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 == 1) && (gametyperules & GTR_CIRCUIT)) - WRITEUINT8(p, (gametype|0x80)); + if ((cv_kartencore.value == 1) && (gametypedefaultrules[gt] & GTR_CIRCUIT)) + WRITEUINT8(p, (gt|VOTEMODIFIER_ENCORE)); else - WRITEUINT8(p, gametype); + WRITEUINT8(p, gt); WRITEUINT8(p, secondgt); - secondgt &= ~0x80; + secondgt &= ~VOTEMODIFIER_ENCORE; for (i = 0; i < 4; i++) { UINT16 m; if (i == 2) // sometimes a different gametype m = G_RandMap(G_TOLFlag(secondgt), prevmap, ((secondgt != gametype) ? 2 : 0), 0, true, votebuffer); - else if (i >= 3) // unknown-random and force-unknown MAP HELL - m = G_RandMap(G_TOLFlag(gametype), prevmap, 0, (i-2), (i < 4), votebuffer); + else if (i >= 3) // unknown-random and formerly force-unknown MAP HELL + m = G_RandMap(G_TOLFlag(gt), prevmap, 0, (i-2), (i < 4), votebuffer); else - m = G_RandMap(G_TOLFlag(gametype), prevmap, 0, 0, true, votebuffer); + m = G_RandMap(G_TOLFlag(gt), prevmap, 0, 0, true, votebuffer); if (i < 3) - votebuffer[i] = m; // min() is a dumb workaround for gcc 4.4 array-bounds error + votebuffer[i] = m; WRITEUINT16(p, m); } @@ -4877,6 +4880,13 @@ static void Got_SetupVotecmd(UINT8 **cp, INT32 playernum) gt = (UINT8)READUINT8(*cp); secondgt = (UINT8)READUINT8(*cp); + // Strip illegal Encore flag. + if ((gt & VOTEMODIFIER_ENCORE) + && !(gametypedefaultrules[(gt & ~VOTEMODIFIER_ENCORE)] & GTR_CIRCUIT)) + { + gt &= ~VOTEMODIFIER_ENCORE; + } + for (i = 0; i < 4; i++) { votelevels[i][0] = (UINT16)READUINT16(*cp); @@ -4885,6 +4895,19 @@ static void Got_SetupVotecmd(UINT8 **cp, INT32 playernum) P_AllocMapHeader(votelevels[i][0]); } + // If third entry has an illelegal Encore flag... (illelegal!?) + if ((secondgt & VOTEMODIFIER_ENCORE) + && !(gametypedefaultrules[(secondgt & ~VOTEMODIFIER_ENCORE)] & GTR_CIRCUIT)) + { + secondgt &= ~VOTEMODIFIER_ENCORE; + // Apply it to the second entry instead, gametype permitting! + if (gametypedefaultrules[gt] & GTR_CIRCUIT) + { + votelevels[1][1] |= VOTEMODIFIER_ENCORE; + } + } + + // Finally, set third entry's gametype/Encore status. votelevels[2][1] = secondgt; G_SetGamestate(GS_VOTING); diff --git a/src/d_netcmd.h b/src/d_netcmd.h index e84342795..44e3aedcc 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -77,6 +77,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; extern consvar_t cv_kartbot; diff --git a/src/g_game.c b/src/g_game.c index 60261e368..6bdd5e028 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3260,51 +3260,53 @@ boolean G_GametypeHasSpectators(void) // // Oh, yeah, and we sometimes flip encore mode on here too. // -INT16 G_SometimesGetDifferentGametype(void) +INT16 G_SometimesGetDifferentGametype(UINT8 prefgametype) { - boolean encorepossible = ((M_SecretUnlocked(SECRET_ENCORE) || encorescramble == 1) && (gametyperules & GTR_CIRCUIT)); + // 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) || encorescramble == 1) + && ((gametyperules|gametypedefaultrules[prefgametype]) & GTR_CIRCUIT)); + UINT8 encoremodifier = 0; - if (!cv_kartvoterulechanges.value // never - && encorescramble != 1) // destroying the code for this one instance - return gametype; - - if (randmapbuffer[NUMMAPS] > 0 && (encorepossible || cv_kartvoterulechanges.value != 3)) + if (encorepossible) { - randmapbuffer[NUMMAPS]--; - if (encorepossible) + if (encorescramble != -1) { - if (encorescramble != -1) - encorepossible = (boolean)encorescramble; // FORCE to what was scrambled on intermission - else - { - 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 != (cv_kartencore.value == 1)) - return (gametype|0x80); + encorepossible = (boolean)encorescramble; // FORCE to what was scrambled on intermission } - return gametype; + else + { + switch (cv_kartvoterulechanges.value) + { + case 3: // always + encorepossible = true; + break; + case 2: // frequent + encorepossible = M_RandomChance(FRACUNIT>>1); + break; + case 1: // sometimes + encorepossible = M_RandomChance(FRACUNIT>>2); + break; + default: + break; + } + } + if (encorepossible != (cv_kartencore.value == 1)) + encoremodifier = VOTEMODIFIER_ENCORE; } - if (!cv_kartvoterulechanges.value) // never (again) - return gametype; + if (!cv_kartvoterulechanges.value) // never + return (gametype|encoremodifier); + + if (randmapbuffer[NUMMAPS] > 0 && (cv_kartvoterulechanges.value != 3)) + { + randmapbuffer[NUMMAPS]--; + return (gametype|encoremodifier); + } switch (cv_kartvoterulechanges.value) // okay, we're having a gametype change! when's the next one, luv? { - case 3: // always - randmapbuffer[NUMMAPS] = 1; // every other vote (or always if !encorepossible) - break; case 1: // sometimes randmapbuffer[NUMMAPS] = 5; // per "cup" break; @@ -3315,9 +3317,17 @@ INT16 G_SometimesGetDifferentGametype(void) break; } - if (gametype == GT_BATTLE) - return GT_RACE; - return GT_BATTLE; + // Only this response is prefgametype-based. + // todo custom gametypes + if (prefgametype == GT_BATTLE) + { + // Intentionally does not use encoremodifier! + if (cv_kartencore.value == 1) + return (GT_RACE|VOTEMODIFIER_ENCORE); + return (GT_RACE); + } + // This might appear wrong HERE, but the game will display the Encore possibility on the second voting choice instead. + return (GT_BATTLE|encoremodifier); } // diff --git a/src/g_game.h b/src/g_game.h index 52c7c7a0d..9fbbd5861 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -199,7 +199,8 @@ boolean G_IsSpecialStage(INT32 mapnum); boolean G_GametypeUsesLives(void); boolean G_GametypeHasTeams(void); boolean G_GametypeHasSpectators(void); -INT16 G_SometimesGetDifferentGametype(void); +#define VOTEMODIFIER_ENCORE 0x80 +INT16 G_SometimesGetDifferentGametype(UINT8 prefgametype); UINT8 G_GetGametypeColor(INT16 gt); void G_ExitLevel(void); void G_NextLevel(void); diff --git a/src/k_kart.c b/src/k_kart.c index f47bf3b17..11f4fc68a 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -248,6 +248,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_kartbot); diff --git a/src/y_inter.c b/src/y_inter.c index 2959853e0..807f10b4a 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -1588,6 +1588,7 @@ void Y_VoteTicker(void) void Y_StartVote(void) { INT32 i = 0; + boolean battlemode = ((votelevels[0][1] & ~VOTEMODIFIER_ENCORE) == GT_BATTLE); // todo gametyperules votetic = -1; @@ -1596,8 +1597,8 @@ void Y_StartVote(void) I_Error("voteendtic is dirty"); #endif - widebgpatch = W_CachePatchName(((gametype == GT_BATTLE) ? "BATTLSCW" : "INTERSCW"), PU_STATIC); - bgpatch = W_CachePatchName(((gametype == GT_BATTLE) ? "BATTLSCR" : "INTERSCR"), PU_STATIC); + widebgpatch = W_CachePatchName((battlemode ? "BATTLSCW" : "INTERSCW"), PU_STATIC); + bgpatch = W_CachePatchName((battlemode ? "BATTLSCR" : "INTERSCR"), PU_STATIC); cursor = W_CachePatchName("M_CURSOR", PU_STATIC); cursor1 = W_CachePatchName("P1CURSOR", PU_STATIC); cursor2 = W_CachePatchName("P2CURSOR", PU_STATIC); @@ -1631,8 +1632,8 @@ void Y_StartVote(void) lumpnum_t lumpnum; // set up the encore - levelinfo[i].encore = (votelevels[i][1] & 0x80); - votelevels[i][1] &= ~0x80; + levelinfo[i].encore = (votelevels[i][1] & VOTEMODIFIER_ENCORE); + votelevels[i][1] &= ~VOTEMODIFIER_ENCORE; // set up the levelstring if (mapheaderinfo[votelevels[i][0]]->levelflags & LF_NOZONE || !mapheaderinfo[votelevels[i][0]]->zonttl[0])