Merge remote-tracking branch 'remotes/origin/master' into reasonable-drawdist

This commit is contained in:
wolfs 2024-04-12 00:42:54 -05:00
commit e1998e731e
23 changed files with 267 additions and 89 deletions

View file

@ -4043,10 +4043,27 @@ static void HandleConnect(SINT8 node)
UINT8 maxplayers = min((dedicated ? MAXPLAYERS-1 : MAXPLAYERS), cv_maxconnections.value); UINT8 maxplayers = min((dedicated ? MAXPLAYERS-1 : MAXPLAYERS), cv_maxconnections.value);
UINT8 connectedplayers = 0; UINT8 connectedplayers = 0;
for (i = dedicated ? 1 : 0; i < MAXPLAYERS; i++) for (i = dedicated ? 1 : 0; i < MAXPLAYERS; i++)
if (playernode[i] != UINT8_MAX) // We use this to count players because it is affected by SV_AddWaitingPlayers when more than one client joins on the same tic, unlike playeringame and D_NumPlayers. UINT8_MAX denotes no node for that player {
// We use this to count players because it is affected by SV_AddWaitingPlayers when
// more than one client joins on the same tic, unlike playeringame and D_NumPlayers.
// UINT8_MAX denotes no node for that player.
if (playernode[i] != UINT8_MAX)
{
// Sal: This hack sucks, but it should be safe.
// playeringame is set for bots immediately; they are deterministic instead of a netxcmd.
// If a bot is added with netxcmd in the future, then the node check is still here too.
// So at worst, a theoretical netxcmd added bot will block real joiners for the time
// it takes for the command to process, but not cause any horrifying player overwriting.
if (playeringame[i] && players[i].bot)
{
continue;
}
connectedplayers++; connectedplayers++;
}
}
banrecord_t *ban = SV_GetBanByAddress(node); banrecord_t *ban = SV_GetBanByAddress(node);
if (ban == NULL) if (ban == NULL)

View file

@ -7282,13 +7282,6 @@ void KartEncore_OnChange(void)
void KartEliminateLast_OnChange(void); void KartEliminateLast_OnChange(void);
void KartEliminateLast_OnChange(void) void KartEliminateLast_OnChange(void)
{ {
#ifndef DEVELOP
if (K_CanChangeRules(false) == false)
{
CV_StealthSet(&cv_karteliminatelast, cv_karteliminatelast.defaultvalue);
}
#endif
P_CheckRacers(); P_CheckRacers();
} }

View file

@ -578,6 +578,15 @@ struct altview_t
INT32 tics; INT32 tics;
}; };
// enum for saved lap times
typedef enum
{
LAP_CUR,
LAP_BEST,
LAP_LAST,
LAP__MAX
} laptime_e;
extern altview_t titlemapcam; extern altview_t titlemapcam;
// ======================================================================== // ========================================================================
@ -897,6 +906,7 @@ struct player_t
INT16 totalring; // Total number of rings obtained for GP INT16 totalring; // Total number of rings obtained for GP
tic_t realtime; // integer replacement for leveltime tic_t realtime; // integer replacement for leveltime
tic_t laptime[LAP__MAX];
UINT8 laps; // Number of laps (optional) UINT8 laps; // Number of laps (optional)
UINT8 latestlap; UINT8 latestlap;
UINT32 lapPoints; // Points given from laps UINT32 lapPoints; // Points given from laps

View file

@ -871,7 +871,6 @@ extern boolean inDuel;
extern tic_t bombflashtimer; // Used to avoid causing seizures if multiple mines explode close to you :) extern tic_t bombflashtimer; // Used to avoid causing seizures if multiple mines explode close to you :)
extern boolean legitimateexit; extern boolean legitimateexit;
extern boolean comebackshowninfo; extern boolean comebackshowninfo;
extern tic_t curlap, bestlap;
#define VOTE_SPECIAL (MAXPLAYERS) #define VOTE_SPECIAL (MAXPLAYERS)
#define VOTE_TOTAL (MAXPLAYERS+1) #define VOTE_TOTAL (MAXPLAYERS+1)

View file

@ -147,6 +147,7 @@ boolean modifiedgame = false; // Set if homebrew PWAD stuff has been added.
boolean majormods = false; // Set if Lua/Gameplay SOC/replacement map has been added. boolean majormods = false; // Set if Lua/Gameplay SOC/replacement map has been added.
boolean savemoddata = false; boolean savemoddata = false;
boolean usedCheats = false; // Set when a "cheats on" is ever used. boolean usedCheats = false; // Set when a "cheats on" is ever used.
boolean usedTourney = false; // Entered the "Tournament Mode" cheat.
UINT8 paused; UINT8 paused;
UINT8 modeattacking = ATTACKING_NONE; UINT8 modeattacking = ATTACKING_NONE;
boolean imcontinuing = false; boolean imcontinuing = false;
@ -322,8 +323,6 @@ boolean inDuel; // Boolean, keeps track of if it is a 1v1
tic_t bombflashtimer = 0; // Cooldown before another FlashPal can be intialized by a bomb exploding near a displayplayer. Avoids seizures. tic_t bombflashtimer = 0; // Cooldown before another FlashPal can be intialized by a bomb exploding near a displayplayer. Avoids seizures.
boolean legitimateexit; // Did this client actually finish the match? boolean legitimateexit; // Did this client actually finish the match?
boolean comebackshowninfo; // Have you already seen the "ATTACK OR PROTECT" message? boolean comebackshowninfo; // Have you already seen the "ATTACK OR PROTECT" message?
tic_t curlap; // Current lap time
tic_t bestlap; // Best lap time
boolean precache = true; // if true, load all graphics at start boolean precache = true; // if true, load all graphics at start
@ -344,14 +343,10 @@ void G_ClearRecords(void)
{ {
UINT16 i; UINT16 i;
for (i = 0; i < numskins; i++)
{
memset(&skins[i].records, 0, sizeof(skins[i].records));
}
for (i = 0; i < nummapheaders; i++) for (i = 0; i < nummapheaders; i++)
{ {
memset(&mapheaderinfo[i]->records, 0, sizeof(recorddata_t)); memset(&mapheaderinfo[i]->records.timeattack, 0, sizeof(recordtimes_t));
memset(&mapheaderinfo[i]->records.spbattack, 0, sizeof(recordtimes_t));
} }
cupheader_t *cup; cupheader_t *cup;
@ -360,14 +355,11 @@ void G_ClearRecords(void)
memset(&cup->windata, 0, sizeof(cup->windata)); memset(&cup->windata, 0, sizeof(cup->windata));
} }
unloaded_skin_t *unloadedskin, *nextunloadedskin = NULL; // TODO: Technically, these should only remove time attack records here.
for (unloadedskin = unloadedskins; unloadedskin; unloadedskin = nextunloadedskin) // But I'm out of juice for dev (+ literally, just finished some OJ).
{ // The stats need to be cleared in M_ClearStats, and I guess there's
nextunloadedskin = unloadedskin->next; // no perfect place to wipe mapvisited because it's not actually part of
Z_Free(unloadedskin); // basegame progression... so here's fine for launch. ~toast 100424
}
unloadedskins = NULL;
unloaded_mapheader_t *unloadedmap, *nextunloadedmap = NULL; unloaded_mapheader_t *unloadedmap, *nextunloadedmap = NULL;
for (unloadedmap = unloadedmapheaders; unloadedmap; unloadedmap = nextunloadedmap) for (unloadedmap = unloadedmapheaders; unloadedmap; unloadedmap = nextunloadedmap)
{ {
@ -561,8 +553,8 @@ void G_UpdateRecords(void)
if (modeattacking & ATTACKING_LAP) if (modeattacking & ATTACKING_LAP)
{ {
if ((record->lap == 0) || (bestlap < record->lap)) if ((record->lap == 0) || (players[consoleplayer].laptime[LAP_BEST] < record->lap))
record->lap = bestlap; record->lap = players[consoleplayer].laptime[LAP_BEST];
} }
// Check emblems when level data is updated // Check emblems when level data is updated
@ -606,7 +598,7 @@ static void G_UpdateRecordReplays(void)
// Save demo! // Save demo!
bestdemo[255] = '\0'; bestdemo[255] = '\0';
lastdemo[255] = '\0'; lastdemo[255] = '\0';
G_SetDemoTime(players[consoleplayer].realtime, bestlap); G_SetDemoTime(players[consoleplayer].realtime, players[consoleplayer].laptime[LAP_BEST]);
G_CheckDemoStatus(); G_CheckDemoStatus();
gpath = va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s", gpath = va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s",
@ -2179,6 +2171,10 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
level_tally_t tally; level_tally_t tally;
boolean tallyactive; boolean tallyactive;
tic_t laptime[LAP__MAX];
INT32 i;
// This needs to be first, to permit it to wipe extra information // This needs to be first, to permit it to wipe extra information
jointime = players[player].jointime; jointime = players[player].jointime;
if (jointime <= 1) if (jointime <= 1)
@ -2206,6 +2202,11 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
kartspeed = skins[players[player].skin].kartspeed; kartspeed = skins[players[player].skin].kartspeed;
kartweight = skins[players[player].skin].kartweight; kartweight = skins[players[player].skin].kartweight;
charflags = skins[players[player].skin].flags; charflags = skins[players[player].skin].flags;
for (i = 0; i < LAP__MAX; i++)
{
laptime[i] = 0;
}
} }
else else
{ {
@ -2218,6 +2219,11 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
kartweight = players[player].kartweight; kartweight = players[player].kartweight;
charflags = (skinflags & SF_IRONMAN) ? skinflags : players[player].charflags; charflags = (skinflags & SF_IRONMAN) ? skinflags : players[player].charflags;
for (i = 0; i < LAP__MAX; i++)
{
laptime[i] = players[player].laptime[i];
}
} }
lastfakeskin = players[player].lastfakeskin; lastfakeskin = players[player].lastfakeskin;
@ -2456,6 +2462,11 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
p->lapPoints = lapPoints; p->lapPoints = lapPoints;
p->totalring = totalring; p->totalring = totalring;
for (i = 0; i < LAP__MAX; i++)
{
p->laptime[i] = laptime[i];
}
p->bot = bot; p->bot = bot;
p->botvars.difficulty = botdifficulty; p->botvars.difficulty = botdifficulty;
p->rings = rings; p->rings = rings;
@ -2519,8 +2530,6 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
// Check to make sure their color didn't change somehow... // Check to make sure their color didn't change somehow...
if (G_GametypeHasTeams()) if (G_GametypeHasTeams())
{ {
UINT8 i;
if (p->ctfteam == 1 && p->skincolor != skincolor_redteam) if (p->ctfteam == 1 && p->skincolor != skincolor_redteam)
{ {
for (i = 0; i <= splitscreen; i++) for (i = 0; i <= splitscreen; i++)

View file

@ -84,6 +84,8 @@ extern tic_t timeinmap; // Ticker for time spent in level (used for levelcard di
extern INT32 pausedelay; extern INT32 pausedelay;
extern boolean pausebreakkey; extern boolean pausebreakkey;
extern boolean usedTourney;
extern boolean promptactive; extern boolean promptactive;
extern consvar_t cv_tutorialprompt; extern consvar_t cv_tutorialprompt;

View file

@ -60,7 +60,7 @@ INT32 K_StartingBumperCount(void)
if (tutorialchallenge == TUTORIALSKIP_INPROGRESS) if (tutorialchallenge == TUTORIALSKIP_INPROGRESS)
return 0; return 0;
if (battleprisons || K_CheckBossIntro()) if (battleprisons || K_CheckBossIntro() || !K_CanChangeRules(true))
{ {
if (grandprixinfo.gp) if (grandprixinfo.gp)
{ {

View file

@ -1889,7 +1889,7 @@ tic_t K_TranslateTimer(tic_t drawtime, UINT8 mode, INT32 *return_jitter)
{ {
INT32 jitter = 0; INT32 jitter = 0;
if (!mode) if (!mode && drawtime != UINT32_MAX)
{ {
if (timelimitintics > 0) if (timelimitintics > 0)
{ {
@ -1948,7 +1948,6 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT32 splitflags, U
// TIME_X = BASEVIDWIDTH-124; // 196 // TIME_X = BASEVIDWIDTH-124; // 196
// TIME_Y = 6; // 6 // TIME_Y = 6; // 6
tic_t worktime;
INT32 jitter = 0; INT32 jitter = 0;
drawtime = K_TranslateTimer(drawtime, mode, &jitter); drawtime = K_TranslateTimer(drawtime, mode, &jitter);
@ -1957,7 +1956,19 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT32 splitflags, U
TX += 33; TX += 33;
worktime = drawtime/(60*TICRATE); if (drawtime == UINT32_MAX)
;
else if (mode && !drawtime)
{
// apostrophe location _'__ __
V_DrawTimerString(TX+24, TY+3, splitflags, va("'"));
// quotation mark location _ __"__
V_DrawTimerString(TX+60, TY+3, splitflags, va("\""));
}
else
{
tic_t worktime = drawtime/(60*TICRATE);
if (worktime >= 100) if (worktime >= 100)
{ {
@ -1966,10 +1977,6 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT32 splitflags, U
drawtime = (100*(60*TICRATE))-1; drawtime = (100*(60*TICRATE))-1;
} }
if (mode && !drawtime)
V_DrawTimerString(TX, TY+3, splitflags, "--'--\"--");
else
{
// minutes time 00 __ __ // minutes time 00 __ __
V_DrawTimerString(TX, TY+3+jitter, splitflags, va("%d", worktime/10)); V_DrawTimerString(TX, TY+3+jitter, splitflags, va("%d", worktime/10));
V_DrawTimerString(TX+12, TY+3-jitter, splitflags, va("%d", worktime%10)); V_DrawTimerString(TX+12, TY+3-jitter, splitflags, va("%d", worktime%10));
@ -6089,7 +6096,26 @@ void K_drawKartHUD(void)
{ {
bool ta = modeattacking && !demo.playback; bool ta = modeattacking && !demo.playback;
INT32 flags = V_HUDTRANS|V_SLIDEIN|V_SNAPTOTOP|V_SNAPTORIGHT; INT32 flags = V_HUDTRANS|V_SLIDEIN|V_SNAPTOTOP|V_SNAPTORIGHT;
K_drawKartTimestamp(stplyr->realtime, TIME_X, TIME_Y + (ta ? 2 : 0), flags, 0);
tic_t realtime = stplyr->realtime;
if (stplyr->karthud[khud_lapanimation]
&& !stplyr->exiting
&& stplyr->laptime[LAP_LAST] != 0
&& stplyr->laptime[LAP_LAST] != UINT32_MAX)
{
if ((stplyr->karthud[khud_lapanimation] / 5) & 1)
{
realtime = stplyr->laptime[LAP_LAST];
}
else
{
realtime = UINT32_MAX;
}
}
K_drawKartTimestamp(realtime, TIME_X, TIME_Y + (ta ? 2 : 0), flags, 0);
if (modeattacking) if (modeattacking)
{ {
if (ta) if (ta)

View file

@ -72,6 +72,16 @@
// comeback is Battle Mode's karma comeback, also bool // comeback is Battle Mode's karma comeback, also bool
// mapreset is set when enough players fill an empty server // mapreset is set when enough players fill an empty server
boolean K_ThunderDome(void)
{
if (K_CanChangeRules(true))
{
return (boolean)cv_thunderdome.value;
}
return false;
}
// lat: used for when the player is in some weird state where it wouldn't be wise for it to be overwritten by another object that does similarly wacky shit. // lat: used for when the player is in some weird state where it wouldn't be wise for it to be overwritten by another object that does similarly wacky shit.
boolean K_isPlayerInSpecialState(player_t *p) boolean K_isPlayerInSpecialState(player_t *p)
{ {
@ -12181,7 +12191,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
if (player->ringboxdelay == 0) if (player->ringboxdelay == 0)
{ {
UINT32 award = 5*player->ringboxaward + 10; UINT32 award = 5*player->ringboxaward + 10;
if (!cv_thunderdome.value) if (!K_ThunderDome())
award = 3 * award / 2; award = 3 * award / 2;
if (modeattacking & ATTACKING_SPB) if (modeattacking & ATTACKING_SPB)
@ -13559,6 +13569,7 @@ void K_CheckSpectateStatus(boolean considermapreset)
{ {
UINT8 respawnlist[MAXPLAYERS]; UINT8 respawnlist[MAXPLAYERS];
UINT8 i, j, numingame = 0, numjoiners = 0; UINT8 i, j, numingame = 0, numjoiners = 0;
UINT8 numhumans = 0, numbots = 0;
// Maintain spectate wait timer // Maintain spectate wait timer
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
@ -13571,6 +13582,16 @@ void K_CheckSpectateStatus(boolean considermapreset)
if (!players[i].spectator) if (!players[i].spectator)
{ {
numingame++; numingame++;
if (players[i].bot)
{
numbots++;
}
else
{
numhumans++;
}
players[i].spectatewait = 0; players[i].spectatewait = 0;
players[i].spectatorReentry = 0; players[i].spectatorReentry = 0;
continue; continue;
@ -13600,7 +13621,7 @@ void K_CheckSpectateStatus(boolean considermapreset)
return; return;
// DON'T allow if you've hit the in-game player cap // DON'T allow if you've hit the in-game player cap
if (cv_maxplayers.value && numingame >= cv_maxplayers.value) if (cv_maxplayers.value && numhumans >= cv_maxplayers.value)
return; return;
// Get the number of players in game, and the players to be de-spectated. // Get the number of players in game, and the players to be de-spectated.
@ -13684,25 +13705,56 @@ void K_CheckSpectateStatus(boolean considermapreset)
} }
} }
const UINT8 previngame = numingame;
INT16 removeBotID = MAXPLAYERS - 1;
// Finally, we can de-spectate everyone! // Finally, we can de-spectate everyone!
for (i = 0; i < numjoiners; i++) for (i = 0; i < numjoiners; i++)
{ {
//CONS_Printf("player %s is joining on tic %d\n", player_names[respawnlist[i]], leveltime);
P_SpectatorJoinGame(&players[respawnlist[i]]);
// Hit the in-game player cap while adding people? // Hit the in-game player cap while adding people?
if (cv_maxplayers.value && numingame+i >= cv_maxplayers.value) if (cv_maxplayers.value && numingame >= cv_maxplayers.value)
{
if (numbots > 0)
{
// Find a bot to kill to make room
while (removeBotID >= 0)
{
if (playeringame[removeBotID] && players[removeBotID].bot)
{
//CONS_Printf("bot %s kicked to make room on tic %d\n", player_names[removeBotID], leveltime);
CL_RemovePlayer(removeBotID, KR_LEAVE);
numbots--;
numingame--;
break; break;
} }
removeBotID--;
}
if (removeBotID < 0)
{
break;
}
}
else
{
break;
}
}
//CONS_Printf("player %s is joining on tic %d\n", player_names[respawnlist[i]], leveltime);
P_SpectatorJoinGame(&players[respawnlist[i]]);
numhumans++;
numingame++;
}
if (considermapreset == false) if (considermapreset == false)
return; return;
// Reset the match when 2P joins 1P, DUEL mode // Reset the match when 2P joins 1P, DUEL mode
// Reset the match when 3P joins 1P and 2P, DUEL mode must be disabled // Reset the match when 3P joins 1P and 2P, DUEL mode must be disabled
extern consvar_t cv_debugnewchallenger; extern consvar_t cv_debugnewchallenger;
if (i > 0 && !mapreset && gamestate == GS_LEVEL && (numingame < 3 && numingame+i >= 2) && !cv_debugnewchallenger.value) if (i > 0 && !mapreset && gamestate == GS_LEVEL && (previngame < 3 && numingame >= 2) && !cv_debugnewchallenger.value)
{ {
Music_Play("comeon"); // COME ON Music_Play("comeon"); // COME ON
mapreset = 3*TICRATE; // Even though only the server uses this for game logic, set for everyone for HUD mapreset = 3*TICRATE; // Even though only the server uses this for game logic, set for everyone for HUD

View file

@ -274,6 +274,8 @@ void K_MakeObjectReappear(mobj_t *mo);
void K_BumperInflate(player_t *player); void K_BumperInflate(player_t *player);
boolean K_ThunderDome(void);
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"
#endif #endif

View file

@ -478,7 +478,6 @@ typedef enum
{ {
gopt_spacer0 = 0, gopt_spacer0 = 0,
gopt_gamespeed, gopt_gamespeed,
gopt_baselapcount,
gopt_frantic, gopt_frantic,
gopt_encore, gopt_encore,
gopt_exitcountdown, gopt_exitcountdown,

View file

@ -640,12 +640,15 @@ void podiumData_s::Draw(void)
if (emeraldNum == 0) if (emeraldNum == 0)
{ {
emeraldPatch = static_cast<patch_t*>( W_CachePatchName("K_BLNA", PU_CACHE) ); // Prize -- todo, currently using fake Emerald
emeraldColor = SKINCOLOR_GOLD;
} }
else else
{ {
emeraldColor = static_cast<skincolornum_t>( SKINCOLOR_CHAOSEMERALD1 + ((emeraldNum - 1) % 7) ); emeraldColor = static_cast<skincolornum_t>( SKINCOLOR_CHAOSEMERALD1 + ((emeraldNum - 1) % 7) );
}
{
std::string emeraldName; std::string emeraldName;
if (emeraldNum > 7) if (emeraldNum > 7)
{ {
@ -853,12 +856,15 @@ void podiumData_s::Draw(void)
if (emeraldNum == 0) if (emeraldNum == 0)
{ {
emeraldOverlay = static_cast<patch_t*>( W_CachePatchName("KBLNC0", PU_CACHE) ); // Prize -- todo, currently using fake Emerald
emeraldColor = SKINCOLOR_GOLD;
} }
else else
{ {
emeraldColor = static_cast<skincolornum_t>( SKINCOLOR_CHAOSEMERALD1 + ((emeraldNum - 1) % 7) ); emeraldColor = static_cast<skincolornum_t>( SKINCOLOR_CHAOSEMERALD1 + ((emeraldNum - 1) % 7) );
}
{
if (emeraldNum > 7) if (emeraldNum > 7)
{ {
emeraldOverlay = static_cast<patch_t*>( W_CachePatchName("SEMRA0", PU_CACHE) ); emeraldOverlay = static_cast<patch_t*>( W_CachePatchName("SEMRA0", PU_CACHE) );

View file

@ -650,7 +650,8 @@ void M_ClearConditionSet(UINT16 set)
// Clear ALL secrets. // Clear ALL secrets.
void M_ClearStats(void) void M_ClearStats(void)
{ {
UINT8 i; UINT16 i;
gamedata->totalplaytime = 0; gamedata->totalplaytime = 0;
gamedata->totalnetgametime = 0; gamedata->totalnetgametime = 0;
gamedata->timeattackingtotaltime = 0; gamedata->timeattackingtotaltime = 0;
@ -678,6 +679,54 @@ void M_ClearStats(void)
gamedata->musicstate = GDMUSIC_NONE; gamedata->musicstate = GDMUSIC_NONE;
gamedata->importprofilewins = false; gamedata->importprofilewins = false;
// Skins only store stats, not progression metrics. Good to clear entirely here.
for (i = 0; i < numskins; i++)
{
memset(&skins[i].records, 0, sizeof(skins[i].records));
}
unloaded_skin_t *unloadedskin, *nextunloadedskin = NULL;
for (unloadedskin = unloadedskins; unloadedskin; unloadedskin = nextunloadedskin)
{
nextunloadedskin = unloadedskin->next;
Z_Free(unloadedskin);
}
unloadedskins = NULL;
// We retain exclusively the most important stuff from maps.
UINT8 restoremapvisited;
recordtimes_t restoretimeattack;
recordtimes_t restorespbattack;
for (i = 0; i < nummapheaders; i++)
{
restoremapvisited = mapheaderinfo[i]->records.mapvisited;
restoretimeattack = mapheaderinfo[i]->records.timeattack;
restorespbattack = mapheaderinfo[i]->records.spbattack;
memset(&mapheaderinfo[i]->records, 0, sizeof(recorddata_t));
mapheaderinfo[i]->records.mapvisited = restoremapvisited;
mapheaderinfo[i]->records.timeattack = restoretimeattack;
mapheaderinfo[i]->records.spbattack = restorespbattack;
}
unloaded_mapheader_t *unloadedmap;
for (unloadedmap = unloadedmapheaders; unloadedmap; unloadedmap = unloadedmap->next)
{
restoremapvisited = unloadedmap->records.mapvisited;
restoretimeattack = unloadedmap->records.timeattack;
restorespbattack = unloadedmap->records.spbattack;
memset(&unloadedmap->records, 0, sizeof(recorddata_t));
unloadedmap->records.mapvisited = restoremapvisited;
unloadedmap->records.timeattack = restoretimeattack;
unloadedmap->records.spbattack = restorespbattack;
}
} }
void M_ClearSecrets(void) void M_ClearSecrets(void)
@ -707,6 +756,8 @@ void M_ClearSecrets(void)
if (!mapheaderinfo[i]) if (!mapheaderinfo[i])
continue; continue;
mapheaderinfo[i]->records.mapvisited = 0;
mapheaderinfo[i]->cache_spraycan = UINT16_MAX; mapheaderinfo[i]->cache_spraycan = UINT16_MAX;
mapheaderinfo[i]->cache_maplock = MAXUNLOCKABLES; mapheaderinfo[i]->cache_maplock = MAXUNLOCKABLES;
@ -2972,6 +3023,11 @@ char *M_BuildConditionSetString(UINT16 unlockid)
} }
} }
if (usedTourney && unlockables[unlockid].conditionset == 55 && gamedata->unlocked[unlockid] == false)
{
strcpy(message, "Power shrouds this challenge in darkness... (Return here without Tournament Mode!)\0");
}
// Finally, do a clean wordwrap! // Finally, do a clean wordwrap!
return V_ScaledWordWrap( return V_ScaledWordWrap(
DESCRIPTIONWIDTH << FRACBITS, DESCRIPTIONWIDTH << FRACBITS,

View file

@ -110,6 +110,8 @@ void f_tournament()
{ {
if (!unlockables[i].conditionset) if (!unlockables[i].conditionset)
continue; continue;
if (unlockables[i].conditionset == 55)
continue;
if (gamedata->unlocked[i]) if (gamedata->unlocked[i])
continue; continue;
@ -146,10 +148,12 @@ void f_tournament()
S_StartSound(0, sfx_kc42); S_StartSound(0, sfx_kc42);
text = M_GetText( text = M_GetText(
"All challenges temporarily unlocked.\n" "Unlocked\x83 almost\x80 everything.\n"
"Saving is disabled - the game will\n" "Saving is disabled - the game will\n"
"return to normal on next launch.\n" "return to normal on next launch.\n"
); );
usedTourney = true;
} }
else else
{ {
@ -158,18 +162,20 @@ void f_tournament()
if (usedCheats) if (usedCheats)
{ {
text = M_GetText( text = M_GetText(
"This is the correct password, but\n" "This is the correct password,\n"
"you already have every challenge\n" "but there's nothing to unlock\n"
"unlocked, so nothing has changed.\n" "right now -- nothing has changed.\n"
); );
} }
else else
{ {
text = M_GetText( text = M_GetText(
"This is the correct password, but\n" "This is the correct password, but\n"
"you already have every challenge\n" "there's nothing to unlock right\n"
"unlocked, so saving is still allowed!\n" "now, so saving is still allowed!\n"
); );
usedTourney = true;
} }
} }
@ -308,7 +314,7 @@ try_password_e M_TryPassword(const char *password, boolean conditions)
add_job(pw.hash_.data(), &pw); add_job(pw.hash_.data(), &pw);
// Only consider challenges passwords as needed. // Only consider challenges passwords as needed.
if (conditions) if (conditions && !usedTourney)
iter_conditions([&](condition_t* cn) { add_job((const UINT8*)cn->stringvar, cn); }); iter_conditions([&](condition_t* cn) { add_job((const UINT8*)cn->stringvar, cn); });
try_password_e return_code = M_PW_INVALID; try_password_e return_code = M_PW_INVALID;

View file

@ -847,7 +847,7 @@ boolean M_ChallengesInputs(INT32 ch)
{ {
M_ChallengesTutorial(CCTUTORIAL_MAJORSKIP); M_ChallengesTutorial(CCTUTORIAL_MAJORSKIP);
} }
else if (M_CanKeyHiliTile()) else if (M_CanKeyHiliTile() && !usedTourney)
{ {
challengesmenu.chaokeyhold = 1; challengesmenu.chaokeyhold = 1;
} }

View file

@ -21,9 +21,6 @@ menuitem_t OPTIONS_Gameplay[] =
{IT_STRING | IT_CVAR, "Game Speed", "Gear for the next map.", {IT_STRING | IT_CVAR, "Game Speed", "Gear for the next map.",
NULL, {.cvar = &cv_kartspeed}, 0, 0}, NULL, {.cvar = &cv_kartspeed}, 0, 0},
{IT_STRING | IT_CVAR, "Base Lap Count", "How many laps must be completed per race.",
NULL, {.cvar = &cv_numlaps}, 0, 0},
{IT_STRING | IT_CVAR, "Frantic Items", "Make item odds crazier with more powerful items!", {IT_STRING | IT_CVAR, "Frantic Items", "Make item odds crazier with more powerful items!",
NULL, {.cvar = &cv_kartfrantic}, 0, 0}, NULL, {.cvar = &cv_kartfrantic}, 0, 0},

View file

@ -19,6 +19,7 @@
#include "../k_battle.h" #include "../k_battle.h"
#include "../m_random.h" #include "../m_random.h"
#include "../k_specialstage.h" // specialstageinfo #include "../k_specialstage.h" // specialstageinfo
#include "../k_kart.h"
#define FLOAT_HEIGHT ( 12 * FRACUNIT ) #define FLOAT_HEIGHT ( 12 * FRACUNIT )
#define FLOAT_TIME ( 2 * TICRATE ) #define FLOAT_TIME ( 2 * TICRATE )
@ -122,7 +123,7 @@ void Obj_RandomItemVisuals(mobj_t *mobj)
// the player's cleared out a good portion of the map. // the player's cleared out a good portion of the map.
// //
// Then extraval1 starts ticking up and triggers the transformation from Ringbox to Random Item. // Then extraval1 starts ticking up and triggers the transformation from Ringbox to Random Item.
if (mobj->fuse == 0 && !(mobj->flags & MF_NOCLIPTHING) && !(mobj->flags2 & MF2_BOSSDEAD) && !cv_thunderdome.value if (mobj->fuse == 0 && !(mobj->flags & MF_NOCLIPTHING) && !(mobj->flags2 & MF2_BOSSDEAD) && !K_ThunderDome()
&& (modeattacking == ATTACKING_NONE || !!(modeattacking & ATTACKING_SPB) || specialstageinfo.valid)) // Time Attacking in Special is a fucked-looking exception && (modeattacking == ATTACKING_NONE || !!(modeattacking & ATTACKING_SPB) || specialstageinfo.valid)) // Time Attacking in Special is a fucked-looking exception
{ {
mobj->extravalue1++; mobj->extravalue1++;

View file

@ -1244,9 +1244,10 @@ static mobj_t *InitSpecialUFO(waypoint_t *start)
} }
else else
{ {
// Prize -- todo, currently using standard Emerald // Prize -- todo, currently using fake Emerald
P_SetMobjState(emerald, S_CHAOSEMERALD1); P_SetMobjState(emerald, S_CHAOSEMERALD1);
P_SetMobjState(overlay, S_CHAOSEMERALD_UNDER); P_SetMobjState(overlay, S_CHAOSEMERALD_UNDER);
emerald->color = SKINCOLOR_GOLD;
} }
P_SetTarget(&emerald->target, ufo); P_SetTarget(&emerald->target, ufo);

View file

@ -1525,7 +1525,7 @@ boolean P_CheckRacers(void)
{ {
const boolean griefed = (spectateGriefed > 0); const boolean griefed = (spectateGriefed > 0);
boolean eliminateLast = cv_karteliminatelast.value; boolean eliminateLast = (!K_CanChangeRules(true) || (cv_karteliminatelast.value != 0));
boolean allHumansDone = true; boolean allHumansDone = true;
//boolean allBotsDone = true; //boolean allBotsDone = true;

View file

@ -274,6 +274,10 @@ static void P_NetArchivePlayers(savebuffer_t *save)
WRITEINT16(save->p, players[i].totalring); WRITEINT16(save->p, players[i].totalring);
WRITEUINT32(save->p, players[i].realtime); WRITEUINT32(save->p, players[i].realtime);
for (j = 0; j < LAP__MAX; j++)
{
WRITEUINT32(save->p, players[i].laptime[j]);
}
WRITEUINT8(save->p, players[i].laps); WRITEUINT8(save->p, players[i].laps);
WRITEUINT8(save->p, players[i].latestlap); WRITEUINT8(save->p, players[i].latestlap);
WRITEUINT32(save->p, players[i].lapPoints); WRITEUINT32(save->p, players[i].lapPoints);
@ -910,6 +914,10 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
players[i].totalring = READINT16(save->p); // Total number of rings obtained for GP players[i].totalring = READINT16(save->p); // Total number of rings obtained for GP
players[i].realtime = READUINT32(save->p); // integer replacement for leveltime players[i].realtime = READUINT32(save->p); // integer replacement for leveltime
for (j = 0; j < LAP__MAX; j++)
{
players[i].laptime[j] = READUINT32(save->p);
}
players[i].laps = READUINT8(save->p); // Number of laps (optional) players[i].laps = READUINT8(save->p); // Number of laps (optional)
players[i].latestlap = READUINT8(save->p); players[i].latestlap = READUINT8(save->p);
players[i].lapPoints = READUINT32(save->p); players[i].lapPoints = READUINT32(save->p);

View file

@ -7675,7 +7675,6 @@ static void P_InitLevelSettings(void)
} }
racecountdown = exitcountdown = musiccountdown = exitfadestarted = 0; racecountdown = exitcountdown = musiccountdown = exitfadestarted = 0;
curlap = bestlap = 0; // SRB2Kart
g_exit.losing = false; g_exit.losing = false;
g_exit.retry = false; g_exit.retry = false;

View file

@ -2094,15 +2094,13 @@ static void K_HandleLapIncrement(player_t *player)
if (player->laps > 1) if (player->laps > 1)
{ {
// save best lap for record attack // save best lap for record attack
if (modeattacking && player == &players[consoleplayer]) if (player->laptime[LAP_CUR] < player->laptime[LAP_BEST] || player->laptime[LAP_BEST] == 0)
{ {
if (curlap < bestlap || bestlap == 0) player->laptime[LAP_BEST] = player->laptime[LAP_CUR];
{
bestlap = curlap;
} }
curlap = 0; player->laptime[LAP_LAST] = player->laptime[LAP_CUR];
} player->laptime[LAP_CUR] = 0;
// Update power levels for this lap. // Update power levels for this lap.
K_UpdatePowerLevels(player, player->laps, false); K_UpdatePowerLevels(player, player->laps, false);
@ -2223,7 +2221,7 @@ static void K_HandleLapDecrement(player_t *player)
player->cheatchecknum = numcheatchecks; player->cheatchecknum = numcheatchecks;
player->laps--; player->laps--;
K_UpdateAllPlayerPositions(); K_UpdateAllPlayerPositions();
curlap = UINT32_MAX; player->laptime[LAP_CUR] = UINT32_MAX;
} }
} }
} }

View file

@ -4322,19 +4322,16 @@ void P_PlayerThink(player_t *player)
if (leveltime >= starttime) if (leveltime >= starttime)
{ {
player->realtime = leveltime - starttime; player->realtime = leveltime - starttime;
if (player == &players[consoleplayer])
{
if (player->spectator) if (player->spectator)
curlap = 0; player->laptime[LAP_CUR] = 0;
else if (curlap != UINT32_MAX) else if (player->laptime[LAP_CUR] != UINT32_MAX)
curlap++; // This is too complicated to sync to realtime, just sorta hope for the best :V player->laptime[LAP_CUR]++; // This is too complicated to sync to realtime, just sorta hope for the best :V
}
} }
else else
{ {
player->realtime = 0; player->realtime = 0;
if (player == &players[consoleplayer]) player->laptime[LAP_CUR] = 0;
curlap = 0;
} }
} }