Merge branch 'new-voting-actual' into 'master'

Chengi & Oni's voting screen

See merge request KartKrew/Kart!1142
This commit is contained in:
Oni 2023-04-11 06:34:40 +00:00
commit e02af33813
13 changed files with 1873 additions and 901 deletions

View file

@ -468,6 +468,8 @@ consvar_t cv_reducevfx = CVAR_INIT ("reducevfx", "No", CV_SAVE, CV_YesNo, NULL);
static CV_PossibleValue_t votetime_cons_t[] = {{10, "MIN"}, {3600, "MAX"}, {0, NULL}}; static CV_PossibleValue_t votetime_cons_t[] = {{10, "MIN"}, {3600, "MAX"}, {0, NULL}};
consvar_t cv_votetime = CVAR_INIT ("votetime", "20", CV_NETVAR, votetime_cons_t, NULL); consvar_t cv_votetime = CVAR_INIT ("votetime", "20", CV_NETVAR, votetime_cons_t, NULL);
consvar_t cv_botscanvote = CVAR_INIT ("botscanvote", "No", CV_CHEAT, CV_YesNo, NULL);
consvar_t cv_gravity = CVAR_INIT ("gravity", "0.8", CV_CHEAT|CV_FLOAT|CV_CALL, NULL, Gravity_OnChange); // change DEFAULT_GRAVITY if you change this consvar_t cv_gravity = CVAR_INIT ("gravity", "0.8", CV_CHEAT|CV_FLOAT|CV_CALL, NULL, Gravity_OnChange); // change DEFAULT_GRAVITY if you change this
consvar_t cv_soundtest = CVAR_INIT ("soundtest", "0", CV_CALL, NULL, SoundTest_OnChange); consvar_t cv_soundtest = CVAR_INIT ("soundtest", "0", CV_CALL, NULL, SoundTest_OnChange);
@ -2615,83 +2617,110 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pencoremode, boolean r
void D_SetupVote(void) void D_SetupVote(void)
{ {
UINT8 buf[5*2]; // four UINT16 maps (at twice the width of a UINT8), and two gametypes UINT8 buf[(VOTE_NUM_LEVELS * 2) + 2]; // four UINT16 maps (at twice the width of a UINT8), and two gametypes
UINT8 *p = buf; UINT8 *p = buf;
INT32 i; INT32 i;
UINT8 secondgt = G_SometimesGetDifferentGametype();
INT16 votebuffer[4] = {-1,-1,-1,0};
if ((cv_kartencore.value == 1) && (gametyperules & GTR_ENCORE)) UINT16 votebuffer[VOTE_NUM_LEVELS + 1];
WRITEUINT8(p, (gametype|VOTEMODIFIER_ENCORE)); memset(votebuffer, UINT16_MAX, sizeof(votebuffer));
else
WRITEUINT8(p, gametype);
WRITEUINT8(p, secondgt);
secondgt &= ~VOTEMODIFIER_ENCORE;
for (i = 0; i < 4; i++) WRITEUINT8(p, ((cv_kartencore.value == 1) && (gametyperules & GTR_ENCORE)));
WRITEUINT8(p, G_SometimesGetDifferentEncore());
for (i = 0; i < VOTE_NUM_LEVELS; i++)
{ {
UINT16 m; UINT16 m = G_RandMap(
if (i == 2) // sometimes a different gametype G_TOLFlag(gametype),
m = G_RandMap(G_TOLFlag(secondgt), prevmap, ((secondgt != gametype) ? 2 : 0), 0, true, votebuffer); prevmap, false,
else if (i >= 3) // Don't Care. Pick any of the available choices. (i < VOTE_NUM_LEVELS-1),
m = votebuffer[M_RandomRange(0, 2)]; votebuffer
else );
m = G_RandMap(G_TOLFlag(gametype), prevmap, 0, 0, true, votebuffer); votebuffer[i] = m;
if (i < 3)
votebuffer[i] = m;
WRITEUINT16(p, m); WRITEUINT16(p, m);
} }
SendNetXCmd(XD_SETUPVOTE, buf, p - buf); SendNetXCmd(XD_SETUPVOTE, buf, p - buf);
} }
void D_ModifyClientVote(UINT8 player, SINT8 voted, UINT8 splitplayer) void D_ModifyClientVote(UINT8 player, SINT8 voted)
{ {
char buf[2]; char buf[2];
char *p = buf; char *p = buf;
UINT8 sendPlayer = consoleplayer;
if (splitplayer > 0) if (player == UINT8_MAX)
player = g_localplayers[splitplayer]; {
// Special game vote (map anger, duel)
if (!server)
{
return;
}
}
if (player == UINT8_MAX)
{
// special vote
WRITEUINT8(p, UINT8_MAX);
}
else
{
INT32 i = 0;
WRITEUINT8(p, player);
for (i = 0; i <= splitscreen; i++)
{
if (g_localplayers[i] == player)
{
sendPlayer = i;
}
}
}
WRITESINT8(p, voted); WRITESINT8(p, voted);
WRITEUINT8(p, player);
SendNetXCmd(XD_MODIFYVOTE, &buf, 2); SendNetXCmdForPlayer(sendPlayer, XD_MODIFYVOTE, buf, p - buf);
} }
void D_PickVote(void) void D_PickVote(void)
{ {
char buf[2]; char buf[2];
char* p = buf; char* p = buf;
SINT8 temppicks[MAXPLAYERS]; SINT8 temppicks[VOTE_TOTAL];
SINT8 templevels[MAXPLAYERS]; SINT8 templevels[VOTE_TOTAL];
SINT8 votecompare = -1; SINT8 votecompare = VOTE_NOT_PICKED;
UINT8 numvotes = 0, key = 0; UINT8 numvotes = 0, key = 0;
INT32 i; INT32 i;
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < VOTE_TOTAL; i++)
{ {
if (!playeringame[i] || players[i].spectator) if (Y_PlayerIDCanVote(i) == false)
{
continue; continue;
if (votes[i] != -1) }
if (g_votes[i] != VOTE_NOT_PICKED)
{ {
temppicks[numvotes] = i; temppicks[numvotes] = i;
templevels[numvotes] = votes[i]; templevels[numvotes] = g_votes[i];
numvotes++; numvotes++;
if (votecompare == -1)
votecompare = votes[i]; if (votecompare == VOTE_NOT_PICKED)
{
votecompare = g_votes[i];
}
} }
} }
key = M_RandomKey(numvotes);
if (numvotes > 0) if (numvotes > 0)
{ {
key = M_RandomKey(numvotes);
WRITESINT8(p, temppicks[key]); WRITESINT8(p, temppicks[key]);
WRITESINT8(p, templevels[key]); WRITESINT8(p, templevels[key]);
} }
else else
{ {
WRITESINT8(p, -1); WRITESINT8(p, VOTE_NOT_PICKED);
WRITESINT8(p, 0); WRITESINT8(p, 0);
} }
@ -3205,7 +3234,7 @@ static void Command_RandomMap(void)
oldmapnum = -1; oldmapnum = -1;
} }
newmapnum = G_RandMap(G_TOLFlag(newgametype), oldmapnum, 0, 0, false, NULL) + 1; newmapnum = G_RandMap(G_TOLFlag(newgametype), oldmapnum, false, false, NULL) + 1;
D_MapChange(newmapnum, newgametype, newencore, newresetplayers, 0, false, false); D_MapChange(newmapnum, newgametype, newencore, newresetplayers, 0, false, false);
} }
@ -5371,75 +5400,55 @@ static void Got_ExitLevelcmd(UINT8 **cp, INT32 playernum)
static void Got_SetupVotecmd(UINT8 **cp, INT32 playernum) static void Got_SetupVotecmd(UINT8 **cp, INT32 playernum)
{ {
boolean baseEncore = false;
boolean optionalEncore = false;
INT16 tempVoteLevels[VOTE_NUM_LEVELS][2];
INT32 i; INT32 i;
UINT8 gt, secondgt;
INT16 tempvotelevels[4][2];
if (playernum != serverplayer) // admin shouldn't be able to set up vote... if (playernum != serverplayer) // admin shouldn't be able to set up vote...
{ {
CONS_Alert(CONS_WARNING, M_GetText("Illegal vote setup received from %s\n"), player_names[playernum]); CONS_Alert(CONS_WARNING, M_GetText("Illegal vote setup received from %s\n"), player_names[playernum]);
if (server) if (server)
SendKick(playernum, KICK_MSG_CON_FAIL);
return;
}
gt = (UINT8)READUINT8(*cp);
secondgt = (UINT8)READUINT8(*cp);
// Strip illegal Encore flag.
if ((gt & VOTEMODIFIER_ENCORE)
&& !(gametypes[(gt & ~VOTEMODIFIER_ENCORE)]->rules & GTR_ENCORE))
{
gt &= ~VOTEMODIFIER_ENCORE;
}
if ((gt & ~VOTEMODIFIER_ENCORE) >= numgametypes)
{
gt &= ~VOTEMODIFIER_ENCORE;
if (server)
I_Error("Got_SetupVotecmd: Internal gametype ID %d not found (numgametypes = %d)", gt, numgametypes);
CONS_Alert(CONS_WARNING, M_GetText("Vote setup with bad gametype ID %d received from %s\n"), gt, player_names[playernum]);
return;
}
if ((secondgt & ~VOTEMODIFIER_ENCORE) >= numgametypes)
{
secondgt &= ~VOTEMODIFIER_ENCORE;
if (server)
I_Error("Got_SetupVotecmd: Internal second gametype ID %d not found (numgametypes = %d)", secondgt, numgametypes);
CONS_Alert(CONS_WARNING, M_GetText("Vote setup with bad second gametype ID %d received from %s\n"), secondgt, player_names[playernum]);
return;
}
for (i = 0; i < 4; i++)
{
tempvotelevels[i][0] = (UINT16)READUINT16(*cp);
tempvotelevels[i][1] = gt;
if (tempvotelevels[i][0] < nummapheaders && mapheaderinfo[tempvotelevels[i][0]])
continue;
if (server)
I_Error("Got_SetupVotecmd: Internal map ID %d not found (nummapheaders = %d)", tempvotelevels[i][0], nummapheaders);
CONS_Alert(CONS_WARNING, M_GetText("Vote setup with bad map ID %d received from %s\n"), tempvotelevels[i][0], player_names[playernum]);
return;
}
// If third entry has an illelegal Encore flag... (illelegal!?)
if ((secondgt & VOTEMODIFIER_ENCORE)
&& !(gametypes[(secondgt & ~VOTEMODIFIER_ENCORE)]->rules & GTR_ENCORE))
{
secondgt &= ~VOTEMODIFIER_ENCORE;
// Apply it to the second entry instead, gametype permitting!
if (gametypes[gt]->rules & GTR_ENCORE)
{ {
tempvotelevels[1][1] |= VOTEMODIFIER_ENCORE; SendKick(playernum, KICK_MSG_CON_FAIL);
} }
return;
} }
// Finally, set third entry's gametype/Encore status. baseEncore = (boolean)READUINT8(*cp);
tempvotelevels[2][1] = secondgt; optionalEncore = (boolean)READUINT8(*cp);
memcpy(votelevels, tempvotelevels, sizeof(votelevels)); if (!(gametyperules & GTR_ENCORE))
{
// Strip illegal Encore flags.
baseEncore = optionalEncore = false;
}
for (i = 0; i < VOTE_NUM_LEVELS; i++)
{
tempVoteLevels[i][0] = (UINT16)READUINT16(*cp);
tempVoteLevels[i][1] = (baseEncore == true) ? VOTE_MOD_ENCORE : 0;
if (tempVoteLevels[i][0] < nummapheaders && mapheaderinfo[tempVoteLevels[i][0]])
{
continue;
}
if (server)
{
I_Error("Got_SetupVotecmd: Internal map ID %d not found (nummapheaders = %d)", tempVoteLevels[i][0], nummapheaders);
}
CONS_Alert(CONS_WARNING, M_GetText("Vote setup with bad map ID %d received from %s\n"), tempVoteLevels[i][0], player_names[playernum]);
return;
}
if (optionalEncore == true)
{
tempVoteLevels[VOTE_NUM_LEVELS - 1][1] ^= VOTE_MOD_ENCORE;
}
memcpy(g_voteLevels, tempVoteLevels, sizeof(g_voteLevels));
G_SetGamestate(GS_VOTING); G_SetGamestate(GS_VOTING);
Y_StartVote(); Y_StartVote();
@ -5447,11 +5456,48 @@ static void Got_SetupVotecmd(UINT8 **cp, INT32 playernum)
static void Got_ModifyVotecmd(UINT8 **cp, INT32 playernum) static void Got_ModifyVotecmd(UINT8 **cp, INT32 playernum)
{ {
SINT8 voted = READSINT8(*cp); UINT8 targetID = READUINT8(*cp);
UINT8 p = READUINT8(*cp); SINT8 vote = READSINT8(*cp);
(void)playernum; if (targetID == UINT8_MAX)
votes[p] = voted; {
if (playernum != serverplayer) // server-only special vote
{
goto fail;
}
targetID = VOTE_SPECIAL;
}
else if (playeringame[targetID] == true && players[targetID].bot == true)
{
if (targetID >= MAXPLAYERS
|| playernum != serverplayer)
{
goto fail;
}
}
else
{
if (targetID >= MAXPLAYERS
|| playernode[targetID] != playernode[playernum])
{
goto fail;
}
}
Y_SetPlayersVote(targetID, vote);
return;
fail:
CONS_Alert(CONS_WARNING,
M_GetText ("Illegal modify vote command received from %s\n"),
player_names[playernum]
);
if (server)
{
SendKick(playernum, KICK_MSG_CON_FAIL);
}
} }
static void Got_PickVotecmd(UINT8 **cp, INT32 playernum) static void Got_PickVotecmd(UINT8 **cp, INT32 playernum)

View file

@ -90,6 +90,7 @@ extern consvar_t cv_karteliminatelast;
extern consvar_t cv_kartusepwrlv; extern consvar_t cv_kartusepwrlv;
extern consvar_t cv_votetime; extern consvar_t cv_votetime;
extern consvar_t cv_botscanvote;
extern consvar_t cv_kartdebugitem, cv_kartdebugamount, cv_kartdebugdistribution, cv_kartdebughuddrop; extern consvar_t cv_kartdebugitem, cv_kartdebugamount, cv_kartdebugdistribution, cv_kartdebughuddrop;
extern consvar_t cv_kartdebugnodes, cv_kartdebugcolorize, cv_kartdebugdirector; extern consvar_t cv_kartdebugnodes, cv_kartdebugcolorize, cv_kartdebugdirector;
@ -240,7 +241,7 @@ void Command_Retry_f(void);
void D_GameTypeChanged(INT32 lastgametype); // not a real _OnChange function anymore void D_GameTypeChanged(INT32 lastgametype); // not a real _OnChange function anymore
void D_MapChange(INT32 pmapnum, INT32 pgametype, boolean pencoremode, boolean presetplayers, INT32 pdelay, boolean pskipprecutscene, boolean pfromlevelselect); void D_MapChange(INT32 pmapnum, INT32 pgametype, boolean pencoremode, boolean presetplayers, INT32 pdelay, boolean pskipprecutscene, boolean pfromlevelselect);
void D_SetupVote(void); void D_SetupVote(void);
void D_ModifyClientVote(UINT8 player, SINT8 voted, UINT8 splitplayer); void D_ModifyClientVote(UINT8 player, SINT8 voted);
void D_PickVote(void); void D_PickVote(void);
void ObjectPlace_OnChange(void); void ObjectPlace_OnChange(void);
boolean IsPlayerAdmin(INT32 playernum); boolean IsPlayerAdmin(INT32 playernum);

View file

@ -410,6 +410,9 @@ struct mapheader_t
cupheader_t *cup; ///< Cached cup cupheader_t *cup; ///< Cached cup
size_t justPlayed; ///< Prevent this map from showing up in votes if it was recently picked.
size_t anger; ///< No one picked this map... it's mad now.
// Titlecard information // Titlecard information
char lvlttl[22]; ///< Level name without "Zone". (21 character limit instead of 32, 21 characters can display on screen max anyway) char lvlttl[22]; ///< Level name without "Zone". (21 character limit instead of 32, 21 characters can display on screen max anyway)
char subttl[33]; ///< Subtitle for level char subttl[33]; ///< Subtitle for level
@ -488,8 +491,8 @@ extern mapheader_t** mapheaderinfo;
extern INT32 nummapheaders, mapallocsize; extern INT32 nummapheaders, mapallocsize;
// Gametypes // Gametypes
#define NUMGAMETYPEFREESLOTS (MAXGAMETYPES-GT_FIRSTFREESLOT) #define NUMGAMETYPEFREESLOTS (128)
#define MAXGAMETYPELENGTH 32 #define MAXGAMETYPELENGTH (32)
enum GameType enum GameType
{ {
@ -500,7 +503,7 @@ enum GameType
GT_TUTORIAL, GT_TUTORIAL,
GT_FIRSTFREESLOT, GT_FIRSTFREESLOT,
GT_LASTFREESLOT = 127, // Previously (GT_FIRSTFREESLOT + NUMGAMETYPEFREESLOTS - 1) - it would be necessary to rewrite VOTEMODIFIER_ENCORE to go higher than this. GT_LASTFREESLOT = GT_FIRSTFREESLOT + NUMGAMETYPEFREESLOTS - 1,
MAXGAMETYPES MAXGAMETYPES
}; };
// If you alter this list, update defaultgametypes and *gametypes in g_game.c // If you alter this list, update defaultgametypes and *gametypes in g_game.c
@ -732,9 +735,11 @@ extern boolean legitimateexit;
extern boolean comebackshowninfo; extern boolean comebackshowninfo;
extern tic_t curlap, bestlap; extern tic_t curlap, bestlap;
extern INT16 votelevels[4][2]; #define VOTE_SPECIAL (MAXPLAYERS)
extern SINT8 votes[MAXPLAYERS]; #define VOTE_TOTAL (MAXPLAYERS+1)
extern SINT8 pickedvote; extern UINT16 g_voteLevels[4][2];
extern SINT8 g_votes[VOTE_TOTAL];
extern SINT8 g_pickedVote;
// =========================== // ===========================
// Internal parameters, fixed. // Internal parameters, fixed.

View file

@ -2250,7 +2250,7 @@ void F_TitleScreenTicker(boolean run)
// prevent console spam if failed // prevent console spam if failed
demoIdleLeft = demoIdleTime; demoIdleLeft = demoIdleTime;
mapnum = G_RandMap(TOL_RACE|TOL_BATTLE, -2, 2, 0, false, NULL); mapnum = G_RandMap(TOL_RACE|TOL_BATTLE, UINT16_MAX-1, true, false, NULL);
if (mapnum == 0) // gotta have ONE if (mapnum == 0) // gotta have ONE
{ {
return; return;

View file

@ -298,9 +298,9 @@ boolean prevencoremode;
boolean franticitems; // Frantic items currently enabled? boolean franticitems; // Frantic items currently enabled?
// Voting system // Voting system
INT16 votelevels[4][2]; // Levels that were rolled by the host UINT16 g_voteLevels[4][2]; // Levels that were rolled by the host
SINT8 votes[MAXPLAYERS]; // Each player's vote SINT8 g_votes[VOTE_TOTAL]; // Each player's vote
SINT8 pickedvote; // What vote the host rolls SINT8 g_pickedVote; // What vote the host rolls
// Server-sided, synched variables // Server-sided, synched variables
tic_t wantedcalcdelay; // Time before it recalculates WANTED tic_t wantedcalcdelay; // Time before it recalculates WANTED
@ -319,23 +319,6 @@ boolean comebackshowninfo; // Have you already seen the "ATTACK OR PROTECT" mess
tic_t curlap; // Current lap time tic_t curlap; // Current lap time
tic_t bestlap; // Best lap time tic_t bestlap; // Best lap time
typedef struct
{
INT16 *mapbuffer; // Pointer to zone memory
INT32 lastnummapheaders; // Reset if nummapheaders != this
} randmaps_t;
static randmaps_t randmaps = {NULL, 0};
static void G_ResetRandMapBuffer(void)
{
INT32 i;
Z_Free(randmaps.mapbuffer);
randmaps.lastnummapheaders = nummapheaders;
randmaps.mapbuffer = Z_Malloc(randmaps.lastnummapheaders * sizeof(INT16), PU_STATIC, NULL);
for (i = 0; i < randmaps.lastnummapheaders; i++)
randmaps.mapbuffer[i] = -1;
}
typedef struct joystickvector2_s typedef struct joystickvector2_s
{ {
INT32 xaxis; INT32 xaxis;
@ -3627,32 +3610,28 @@ boolean G_GametypeHasSpectators(void)
} }
// //
// G_SometimesGetDifferentGametype // G_SometimesGetDifferentEncore
// //
// Because gametypes are no longer on the vote screen, all this does is sometimes flip encore mode. // Because gametypes are no longer on the vote screen, all this does is sometimes flip encore mode.
// However, it remains a seperate function for long-term possibility. // However, it remains a seperate function for long-term possibility.
// //
INT16 G_SometimesGetDifferentGametype(void) INT16 G_SometimesGetDifferentEncore(void)
{ {
boolean encorepossible = ((M_SecretUnlocked(SECRET_ENCORE, false) || encorescramble == 1) boolean encorepossible = ((M_SecretUnlocked(SECRET_ENCORE, false) || encorescramble == 1)
&& (gametyperules & GTR_ENCORE)); && (gametyperules & GTR_ENCORE));
UINT8 encoremodifier = 0; UINT8 encoremodifier = 0;
// -- the below is only necessary if you want to use randmaps.mapbuffer here
//if (randmaps.lastnummapheaders != nummapheaders)
//G_ResetRandMapBuffer();
// FORCE to what was scrambled on intermission? // FORCE to what was scrambled on intermission?
if (encorepossible && encorescramble != -1) if (encorepossible && encorescramble != -1)
{ {
// FORCE to what was scrambled on intermission // FORCE to what was scrambled on intermission
if ((encorescramble != 0) != (cv_kartencore.value == 1)) if ((encorescramble != 0) != (cv_kartencore.value == 1))
{ {
encoremodifier = VOTEMODIFIER_ENCORE; encoremodifier = VOTE_MOD_ENCORE;
} }
} }
return (gametype|encoremodifier); return encoremodifier;
} }
/** Get the typeoflevel flag needed to indicate support of a gametype. /** Get the typeoflevel flag needed to indicate support of a gametype.
@ -3708,14 +3687,33 @@ static INT32 TOLMaps(UINT8 pgametype)
// Find all the maps that are ok // Find all the maps that are ok
for (i = 0; i < nummapheaders; i++) for (i = 0; i < nummapheaders; i++)
{ {
if (!mapheaderinfo[i]) if (mapheaderinfo[i] == NULL)
{
continue; continue;
}
if (mapheaderinfo[i]->lumpnum == LUMPERROR) if (mapheaderinfo[i]->lumpnum == LUMPERROR)
{
continue; continue;
if (!(mapheaderinfo[i]->typeoflevel & tolflag)) }
if ((mapheaderinfo[i]->typeoflevel & tolflag) == 0)
{
continue; continue;
if (mapheaderinfo[i]->menuflags & LF2_HIDEINMENU) // Don't include Map Hell }
if (mapheaderinfo[i]->menuflags & LF2_HIDEINMENU)
{
// Don't include hidden
continue; continue;
}
if (M_MapLocked(i + 1))
{
// Don't include locked
continue;
}
num++; num++;
} }
@ -3730,168 +3728,174 @@ static INT32 TOLMaps(UINT8 pgametype)
* has those flags. * has those flags.
* \author Graue <graue@oceanbase.org> * \author Graue <graue@oceanbase.org>
*/ */
static INT16 *okmaps = NULL; static UINT16 *g_allowedMaps = NULL;
INT16 G_RandMap(UINT32 tolflags, INT16 pprevmap, UINT8 ignorebuffer, UINT8 maphell, boolean callagainsoon, INT16 *extbuffer)
#ifdef PARANOIA
static size_t g_randMapStack = 0;
#endif
UINT16 G_RandMap(UINT32 tolflags, UINT16 pprevmap, boolean ignoreBuffers, boolean callAgainSoon, UINT16 *extBuffer)
{ {
UINT32 numokmaps = 0; INT32 allowedMapsCount = 0;
INT16 ix, bufx; INT32 extBufferCount = 0;
UINT16 extbufsize = 0; UINT16 ret = 0;
boolean usehellmaps; // Only consider Hell maps in this pick INT32 i, j;
if (randmaps.lastnummapheaders != nummapheaders) #ifdef PARANOIA
G_ResetRandMapBuffer(); g_randMapStack++;
#endif
if (!okmaps) if (g_allowedMaps == NULL)
{ {
//CONS_Printf("(making okmaps)\n"); g_allowedMaps = Z_Malloc(nummapheaders * sizeof(UINT16), PU_STATIC, NULL);
okmaps = Z_Malloc(nummapheaders * sizeof(INT16), PU_STATIC, NULL);
} }
if (extbuffer != NULL) if (extBuffer != NULL)
{ {
bufx = 0; for (i = 0; extBuffer[i] != UINT16_MAX; i++)
while (extbuffer[bufx])
{ {
extbufsize++; bufx++; extBufferCount++;
} }
} }
tryagain: tryAgain:
usehellmaps = (maphell == 0 ? false : (maphell == 2 || M_RandomChance(FRACUNIT/100))); // 1% chance of Hell for (i = 0; i < nummapheaders; i++)
// Find all the maps that are ok and and put them in an array.
for (ix = 0; ix < nummapheaders; ix++)
{ {
boolean isokmap = true; if (mapheaderinfo[i] == NULL || mapheaderinfo[i]->lumpnum == LUMPERROR)
if (!mapheaderinfo[ix] || mapheaderinfo[ix]->lumpnum == LUMPERROR)
continue;
if (!(mapheaderinfo[ix]->typeoflevel & tolflags)
|| ix == pprevmap
|| M_MapLocked(ix+1)
|| (usehellmaps != (mapheaderinfo[ix]->menuflags & LF2_HIDEINMENU))) // this is bad
continue; //isokmap = false;
if (pprevmap == -2 // title demo hack
&& mapheaderinfo[ix]->ghostCount == 0)
continue;
if (!ignorebuffer)
{ {
if (extbufsize > 0) // Doesn't exist?
continue;
}
if (i == pprevmap)
{
// We were just here.
continue;
}
if ((mapheaderinfo[i]->typeoflevel & tolflags) == 0)
{
// Doesn't match our gametype.
continue;
}
if (pprevmap == UINT16_MAX-1 // title demo hack (FUCK YOU, MAKE IT A BOOL)
&& mapheaderinfo[i]->ghostCount == 0)
{
// Doesn't have any ghosts, so it's not suitable for title demos.
continue;
}
if ((mapheaderinfo[i]->menuflags & LF2_HIDEINMENU) == LF2_HIDEINMENU)
{
// Not intended to be accessed in multiplayer.
continue;
}
if (M_MapLocked(i + 1) == true)
{
// We haven't earned this one.
continue;
}
if (ignoreBuffers == false)
{
if (mapheaderinfo[i]->justPlayed > 0)
{ {
for (bufx = 0; bufx < extbufsize; bufx++) // We just played this map, don't play it again.
continue;
}
if (extBufferCount > 0)
{
boolean inExt = false;
// An optional additional buffer,
// to avoid duplicates on the voting screen.
for (j = 0; j < extBufferCount; j++)
{ {
if (extbuffer[bufx] == -1) // Rest of buffer SHOULD be empty if (extBuffer[j] >= nummapheaders)
break;
if (ix == extbuffer[bufx])
{ {
isokmap = false; // Rest of buffer SHOULD be empty.
break;
}
if (i == extBuffer[j])
{
// Map is in this other buffer, don't duplicate.
inExt = true;
break; break;
} }
} }
if (!isokmap) if (inExt == true)
continue;
}
for (bufx = 0; bufx < (maphell ? 3 : randmaps.lastnummapheaders); bufx++)
{
if (randmaps.mapbuffer[bufx] == -1) // Rest of buffer SHOULD be empty
break;
if (ix == randmaps.mapbuffer[bufx])
{ {
isokmap = false; // Didn't make it out of this buffer, so don't add this map.
break; continue;
} }
} }
if (!isokmap)
continue;
} }
okmaps[numokmaps++] = ix; // Got past the gauntlet, so we can allow this one.
g_allowedMaps[ allowedMapsCount++ ] = i;
} }
if (numokmaps == 0) // If there's no matches... (Goodbye, incredibly silly function chains :V) if (allowedMapsCount == 0)
{ {
if (!ignorebuffer) // No maps are available.
if (ignoreBuffers == false)
{ {
if (randmaps.mapbuffer[3] == -1) // Is the buffer basically empty? // Try again with ignoring the buffer before giving up.
{ ignoreBuffers = true;
ignorebuffer = 1; // This will probably only help in situations where there's very few maps, but it's folly not to at least try it goto tryAgain;
//CONS_Printf("RANDMAP - ignoring buffer\n");
goto tryagain;
}
for (bufx = 3; bufx < randmaps.lastnummapheaders; bufx++) // Let's clear all but the three most recent maps...
randmaps.mapbuffer[bufx] = -1;
//CONS_Printf("RANDMAP - emptying randmapbuffer\n");
goto tryagain;
} }
if (maphell) // Any wiggle room to loosen our restrictions here? // Nothing else actually worked. Welp!
{ // You just get whatever was added first.
//CONS_Printf("RANDMAP -maphell decrement\n"); ret = 0;
maphell--;
goto tryagain;
}
//CONS_Printf("RANDMAP - defaulting to map01\n");
ix = 0; // Sorry, none match. You get MAP01.
if (ignorebuffer == 1)
{
//CONS_Printf("(emptying randmapbuffer entirely)\n");
for (bufx = 0; bufx < randmaps.lastnummapheaders; bufx++)
randmaps.mapbuffer[bufx] = -1; // if we're having trouble finding a map we should probably clear it
}
} }
else else
{ {
//CONS_Printf("RANDMAP - %d maps available to grab\n", numokmaps); ret = g_allowedMaps[ M_RandomKey(allowedMapsCount) ];
ix = okmaps[M_RandomKey(numokmaps)];
} }
if (!callagainsoon) if (callAgainSoon == false)
{ {
//CONS_Printf("(freeing okmaps)\n"); Z_Free(g_allowedMaps);
Z_Free(okmaps); g_allowedMaps = NULL;
okmaps = NULL;
#ifdef PARANOIA
// Crash if callAgainSoon was mishandled.
I_Assert(g_randMapStack == 1);
#endif
} }
return ix; #ifdef PARANOIA
g_randMapStack--;
#endif
return ret;
} }
void G_AddMapToBuffer(INT16 map) void G_AddMapToBuffer(UINT16 map)
{ {
INT16 bufx; if (mapheaderinfo[map]->justPlayed == 0) // Started playing a new map.
INT16 refreshnum = (TOLMaps(gametype))-3;
if (refreshnum < 0)
refreshnum = 3;
if (nummapheaders != randmaps.lastnummapheaders)
{ {
G_ResetRandMapBuffer(); // Decrement every maps' justPlayed value.
} INT32 i;
else for (i = 0; i < nummapheaders; i++)
{ {
for (bufx = randmaps.lastnummapheaders-1; bufx > 0; bufx--) if (mapheaderinfo[i]->justPlayed > 0)
randmaps.mapbuffer[bufx] = randmaps.mapbuffer[bufx-1]; {
mapheaderinfo[i]->justPlayed--;
}
}
} }
randmaps.mapbuffer[0] = map; // Set our map's justPlayed value.
mapheaderinfo[map]->justPlayed = TOLMaps(gametype) - VOTE_NUM_LEVELS;
// We're getting pretty full, so lets flush this for future usage. mapheaderinfo[map]->anger = 0; // Reset voting anger now that we're playing it
if (randmaps.mapbuffer[refreshnum] != -1)
{
// Clear all but the five most recent maps.
for (bufx = 5; bufx < randmaps.lastnummapheaders; bufx++)
randmaps.mapbuffer[bufx] = -1;
//CONS_Printf("Random map buffer has been flushed.\n");
}
} }
// //
@ -4218,7 +4222,7 @@ static void G_GetNextMap(void)
} }
/* FALLTHRU */ /* FALLTHRU */
case 2: // Go to random map. case 2: // Go to random map.
nextmap = G_RandMap(G_TOLFlag(gametype), prevmap, 0, 0, false, NULL); nextmap = G_RandMap(G_TOLFlag(gametype), prevmap, false, false, NULL);
break; break;
default: default:
if (nextmap >= NEXTMAP_SPECIAL) // Loop back around if (nextmap >= NEXTMAP_SPECIAL) // Loop back around
@ -5378,8 +5382,6 @@ void G_DeferedInitNew(boolean pencoremode, INT32 map, INT32 pickedchar, UINT8 ss
G_FreeGhosts(); // TODO: do we actually need to do this? G_FreeGhosts(); // TODO: do we actually need to do this?
G_ResetRandMapBuffer();
// this leave the actual game if needed // this leave the actual game if needed
SV_StartSinglePlayerServer(gametype, false); SV_StartSinglePlayerServer(gametype, false);
@ -5508,6 +5510,8 @@ void G_InitNew(UINT8 pencoremode, INT32 map, boolean resetplayer, boolean skippr
} }
CON_LogMessage("\"\n"); CON_LogMessage("\"\n");
} }
G_AddMapToBuffer(gamemap - 1);
} }

View file

@ -182,8 +182,7 @@ INT32 G_GuessGametypeByTOL(UINT32 tol);
boolean G_GametypeUsesLives(void); boolean G_GametypeUsesLives(void);
boolean G_GametypeHasTeams(void); boolean G_GametypeHasTeams(void);
boolean G_GametypeHasSpectators(void); boolean G_GametypeHasSpectators(void);
#define VOTEMODIFIER_ENCORE 0x80 INT16 G_SometimesGetDifferentEncore(void);
INT16 G_SometimesGetDifferentGametype(void);
void G_ExitLevel(void); void G_ExitLevel(void);
void G_NextLevel(void); void G_NextLevel(void);
void G_Continue(void); void G_Continue(void);
@ -256,8 +255,8 @@ FUNCMATH INT32 G_TicsToMilliseconds(tic_t tics);
UINT32 G_TOLFlag(INT32 pgametype); UINT32 G_TOLFlag(INT32 pgametype);
INT16 G_GetFirstMapOfGametype(UINT8 pgametype); INT16 G_GetFirstMapOfGametype(UINT8 pgametype);
INT16 G_RandMap(UINT32 tolflags, INT16 pprevmap, UINT8 ignorebuffer, UINT8 maphell, boolean callagainsoon, INT16 *extbuffer); UINT16 G_RandMap(UINT32 tolflags, UINT16 pprevmap, boolean ignoreBuffers, boolean callAgainSoon, UINT16 *extBuffer);
void G_AddMapToBuffer(INT16 map); void G_AddMapToBuffer(UINT16 map);
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"

View file

@ -342,6 +342,7 @@ void K_RegisterKartStuff(void)
CV_RegisterVar(&cv_karteliminatelast); CV_RegisterVar(&cv_karteliminatelast);
CV_RegisterVar(&cv_kartusepwrlv); CV_RegisterVar(&cv_kartusepwrlv);
CV_RegisterVar(&cv_votetime); CV_RegisterVar(&cv_votetime);
CV_RegisterVar(&cv_botscanvote);
CV_RegisterVar(&cv_kartdebugitem); CV_RegisterVar(&cv_kartdebugitem);
CV_RegisterVar(&cv_kartdebugamount); CV_RegisterVar(&cv_kartdebugamount);

View file

@ -5282,7 +5282,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
static UINT16 encoremapcache = NEXTMAP_INVALID; static UINT16 encoremapcache = NEXTMAP_INVALID;
if (encoremapcache > nummapheaders) if (encoremapcache > nummapheaders)
{ {
encoremapcache = G_RandMap(G_TOLFlag(GT_RACE), -1, 2, 0, false, NULL); encoremapcache = G_RandMap(G_TOLFlag(GT_RACE), UINT16_MAX, true, false, NULL);
} }
specialmap = encoremapcache; specialmap = encoremapcache;
break; break;
@ -5292,7 +5292,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
static UINT16 tamapcache = NEXTMAP_INVALID; static UINT16 tamapcache = NEXTMAP_INVALID;
if (tamapcache > nummapheaders) if (tamapcache > nummapheaders)
{ {
tamapcache = G_RandMap(G_TOLFlag(GT_RACE), -1, 2, 0, false, NULL); tamapcache = G_RandMap(G_TOLFlag(GT_RACE), UINT16_MAX, true, false, NULL);
} }
specialmap = tamapcache; specialmap = tamapcache;
break; break;
@ -5302,7 +5302,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
static UINT16 btcmapcache = NEXTMAP_INVALID; static UINT16 btcmapcache = NEXTMAP_INVALID;
if (btcmapcache > nummapheaders) if (btcmapcache > nummapheaders)
{ {
btcmapcache = G_RandMap(G_TOLFlag(GT_BATTLE), -1, 2, 0, false, NULL); btcmapcache = G_RandMap(G_TOLFlag(GT_BATTLE), UINT16_MAX, true, false, NULL);
} }
specialmap = btcmapcache; specialmap = btcmapcache;
break; break;
@ -5312,7 +5312,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
static UINT16 sscmapcache = NEXTMAP_INVALID; static UINT16 sscmapcache = NEXTMAP_INVALID;
if (sscmapcache > nummapheaders) if (sscmapcache > nummapheaders)
{ {
sscmapcache = G_RandMap(G_TOLFlag(GT_SPECIAL), -1, 2, 0, false, NULL); sscmapcache = G_RandMap(G_TOLFlag(GT_SPECIAL), UINT16_MAX, true, false, NULL);
} }
specialmap = sscmapcache; specialmap = sscmapcache;
break; break;
@ -5322,7 +5322,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
static UINT16 spbmapcache = NEXTMAP_INVALID; static UINT16 spbmapcache = NEXTMAP_INVALID;
if (spbmapcache > nummapheaders) if (spbmapcache > nummapheaders)
{ {
spbmapcache = G_RandMap(G_TOLFlag(GT_RACE), -1, 2, 0, false, NULL); spbmapcache = G_RandMap(G_TOLFlag(GT_RACE), UINT16_MAX, true, false, NULL);
} }
specialmap = spbmapcache; specialmap = spbmapcache;
break; break;
@ -5332,7 +5332,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
static UINT16 hardmapcache = NEXTMAP_INVALID; static UINT16 hardmapcache = NEXTMAP_INVALID;
if (hardmapcache > nummapheaders) if (hardmapcache > nummapheaders)
{ {
hardmapcache = G_RandMap(G_TOLFlag(GT_RACE), -1, 2, 0, false, NULL); hardmapcache = G_RandMap(G_TOLFlag(GT_RACE), UINT16_MAX, true, false, NULL);
} }
specialmap = hardmapcache; specialmap = hardmapcache;
break; break;
@ -5342,7 +5342,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
static UINT16 mastermapcache = NEXTMAP_INVALID; static UINT16 mastermapcache = NEXTMAP_INVALID;
if (mastermapcache > nummapheaders) if (mastermapcache > nummapheaders)
{ {
mastermapcache = G_RandMap(G_TOLFlag(GT_RACE), -1, 2, 0, false, NULL); mastermapcache = G_RandMap(G_TOLFlag(GT_RACE), UINT16_MAX, true, false, NULL);
} }
specialmap = mastermapcache; specialmap = mastermapcache;
break; break;

File diff suppressed because it is too large Load diff

View file

@ -19,6 +19,14 @@
extern "C" { extern "C" {
#endif #endif
#define VOTE_NUM_LEVELS (4)
#define VOTE_NOT_PICKED (-1)
#define VOTE_MOD_ENCORE (0x01)
boolean Y_PlayerIDCanVote(const UINT8 playerId);
void Y_SetPlayersVote(const UINT8 playerId, SINT8 vote);
void Y_VoteDrawer(void); void Y_VoteDrawer(void);
void Y_VoteTicker(void); void Y_VoteTicker(void);
void Y_StartVote(void); void Y_StartVote(void);

View file

@ -4997,16 +4997,18 @@ static void P_NetArchiveMisc(savebuffer_t *save, boolean resending)
WRITEINT16(save->p, lastmap); WRITEINT16(save->p, lastmap);
WRITEUINT16(save->p, bossdisabled); WRITEUINT16(save->p, bossdisabled);
for (i = 0; i < 4; i++) for (i = 0; i < VOTE_NUM_LEVELS; i++)
{ {
WRITEINT16(save->p, votelevels[i][0]); WRITEUINT16(save->p, g_voteLevels[i][0]);
WRITEINT16(save->p, votelevels[i][1]); WRITEUINT16(save->p, g_voteLevels[i][1]);
} }
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < VOTE_TOTAL; i++)
WRITESINT8(save->p, votes[i]); {
WRITESINT8(save->p, g_votes[i]);
}
WRITESINT8(save->p, pickedvote); WRITESINT8(save->p, g_pickedVote);
WRITEUINT16(save->p, emeralds); WRITEUINT16(save->p, emeralds);
{ {
@ -5169,16 +5171,18 @@ static inline boolean P_NetUnArchiveMisc(savebuffer_t *save, boolean reloading)
lastmap = READINT16(save->p); lastmap = READINT16(save->p);
bossdisabled = READUINT16(save->p); bossdisabled = READUINT16(save->p);
for (i = 0; i < 4; i++) for (i = 0; i < VOTE_NUM_LEVELS; i++)
{ {
votelevels[i][0] = READINT16(save->p); g_voteLevels[i][0] = READUINT16(save->p);
votelevels[i][1] = READINT16(save->p); g_voteLevels[i][1] = READUINT16(save->p);
} }
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < VOTE_TOTAL; i++)
votes[i] = READSINT8(save->p); {
g_votes[i] = READSINT8(save->p);
}
pickedvote = READSINT8(save->p); g_pickedVote = READSINT8(save->p);
emeralds = READUINT16(save->p); emeralds = READUINT16(save->p);
{ {

View file

@ -429,6 +429,9 @@ static void P_ClearSingleMapHeaderInfo(INT16 num)
Z_Free(mapheaderinfo[num]->mainrecord); Z_Free(mapheaderinfo[num]->mainrecord);
mapheaderinfo[num]->mainrecord = NULL; mapheaderinfo[num]->mainrecord = NULL;
mapheaderinfo[num]->justPlayed = 0;
mapheaderinfo[num]->anger = 0;
mapheaderinfo[num]->customopts = NULL; mapheaderinfo[num]->customopts = NULL;
mapheaderinfo[num]->numCustomOptions = 0; mapheaderinfo[num]->numCustomOptions = 0;
} }
@ -8042,8 +8045,6 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
G_SaveGameData(); G_SaveGameData();
} }
G_AddMapToBuffer(gamemap-1);
P_MapEnd(); // tm.thing is no longer needed from this point onwards P_MapEnd(); // tm.thing is no longer needed from this point onwards
// Took me 3 hours to figure out why my progression kept on getting overwritten with the titlemap... // Took me 3 hours to figure out why my progression kept on getting overwritten with the titlemap...

View file

@ -1307,7 +1307,7 @@ void V_DrawFadeFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c, UINT16 color, U
h *= dupy; h *= dupy;
// Center it if necessary // Center it if necessary
// adjustxy V_AdjustXYWithSnap(&x, &y, c, dupx, dupy);
} }
if (x >= vid.width || y >= vid.height) if (x >= vid.width || y >= vid.height)