From 86b4f9361001ea1b6ba7c2d0966932e4fd11473c Mon Sep 17 00:00:00 2001 From: spherallic Date: Wed, 2 Mar 2022 23:47:15 +0100 Subject: [PATCH] Allow obtaining ring, time & grade emblems in regular SP gameplay. --- src/d_netcmd.c | 2 +- src/d_player.h | 3 +- src/g_game.c | 354 ++++++++++++++++++++++++++------------------ src/g_game.h | 3 +- src/lua_playerlib.c | 8 + src/m_cond.c | 2 +- src/m_cond.h | 2 +- src/p_saveg.c | 61 ++++++-- src/p_setup.c | 2 +- src/p_user.c | 12 +- 10 files changed, 279 insertions(+), 170 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 90078f062..52790b2ce 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2339,7 +2339,7 @@ static void Got_Clearscores(UINT8 **cp, INT32 playernum) } for (i = 0; i < MAXPLAYERS; i++) - players[i].score = 0; + players[i].score = players[i].recordscore = 0; CONS_Printf(M_GetText("Scores have been reset by the server.\n")); } diff --git a/src/d_player.h b/src/d_player.h index f407c29e9..7ad5b9f81 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -453,7 +453,8 @@ typedef struct player_s INT32 skin; UINT32 availabilities; - UINT32 score; // player score + UINT32 score; // player score (total) + UINT32 recordscore; // player score (per life / map) fixed_t dashspeed; // dashing speed fixed_t normalspeed; // Normal ground diff --git a/src/g_game.c b/src/g_game.c index 571756503..81942f462 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -519,140 +519,154 @@ UINT8 G_GetBestNightsGrade(INT16 map, UINT8 mare, gamedata_t *data) } // For easy adding of NiGHTS records -void G_AddTempNightsRecords(UINT32 pscore, tic_t ptime, UINT8 mare) +void G_AddTempNightsRecords(player_t *player, UINT32 pscore, tic_t ptime, UINT8 mare) { - ntemprecords.score[mare] = pscore; - ntemprecords.grade[mare] = P_GetGrade(pscore, gamemap, mare - 1); - ntemprecords.time[mare] = ptime; + const UINT8 playerID = player - players; + + I_Assert(player != NULL); + + ntemprecords[playerID].score[mare] = pscore; + ntemprecords[playerID].grade[mare] = P_GetGrade(pscore, gamemap, mare - 1); + ntemprecords[playerID].time[mare] = ptime; // Update nummares // Note that mare "0" is overall, mare "1" is the first real mare - if (ntemprecords.nummares < mare) - ntemprecords.nummares = mare; + if (ntemprecords[playerID].nummares < mare) + ntemprecords[playerID].nummares = mare; } // -// G_UpdateRecordReplays +// G_SetMainRecords // // Update replay files/data, etc. for Record Attack // See G_SetNightsRecords for NiGHTS Attack. // -static void G_UpdateRecordReplays(gamedata_t *data) +static void G_SetMainRecords(gamedata_t *data, player_t *player) { - const size_t glen = strlen(srb2home)+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1; - char *gpath; - char lastdemo[256], bestdemo[256]; UINT8 earnedEmblems; + I_Assert(player != NULL); + // Record new best time if (!data->mainrecords[gamemap-1]) G_AllocMainRecordData(gamemap-1, data); - if (players[consoleplayer].score > data->mainrecords[gamemap-1]->score) - data->mainrecords[gamemap-1]->score = players[consoleplayer].score; + if (player->recordscore > data->mainrecords[gamemap-1]->score) + data->mainrecords[gamemap-1]->score = player->recordscore; - if ((data->mainrecords[gamemap-1]->time == 0) || (players[consoleplayer].realtime < data->mainrecords[gamemap-1]->time)) - data->mainrecords[gamemap-1]->time = players[consoleplayer].realtime; + if ((data->mainrecords[gamemap-1]->time == 0) || (player->realtime < data->mainrecords[gamemap-1]->time)) + data->mainrecords[gamemap-1]->time = player->realtime; - if ((UINT16)(players[consoleplayer].rings) > data->mainrecords[gamemap-1]->rings) - data->mainrecords[gamemap-1]->rings = (UINT16)(players[consoleplayer].rings); + if ((UINT16)(player->rings) > data->mainrecords[gamemap-1]->rings) + data->mainrecords[gamemap-1]->rings = (UINT16)(player->rings); - // Save demo! - bestdemo[255] = '\0'; - lastdemo[255] = '\0'; - G_SetDemoTime(players[consoleplayer].realtime, players[consoleplayer].score, (UINT16)(players[consoleplayer].rings)); - G_CheckDemoStatus(); - - I_mkdir(va("%s"PATHSEP"replay", srb2home), 0755); - I_mkdir(va("%s"PATHSEP"replay"PATHSEP"%s", srb2home, timeattackfolder), 0755); - - if ((gpath = malloc(glen)) == NULL) - I_Error("Out of memory for replay filepath\n"); - - sprintf(gpath,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap)); - snprintf(lastdemo, 255, "%s-%s-last.lmp", gpath, skins[cv_chooseskin.value-1].name); - - if (FIL_FileExists(lastdemo)) + if (modeattacking) { - UINT8 *buf; - size_t len = FIL_ReadFile(lastdemo, &buf); + const size_t glen = strlen(srb2home)+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1; + char *gpath; + char lastdemo[256], bestdemo[256]; - snprintf(bestdemo, 255, "%s-%s-time-best.lmp", gpath, skins[cv_chooseskin.value-1].name); - if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & 1) - { // Better time, save this demo. - if (FIL_FileExists(bestdemo)) - remove(bestdemo); - FIL_WriteFile(bestdemo, buf, len); - CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW RECORD TIME!"), M_GetText("Saved replay as"), bestdemo); + // Save demo! + bestdemo[255] = '\0'; + lastdemo[255] = '\0'; + G_SetDemoTime(player->realtime, player->recordscore, (UINT16)(player->rings)); + G_CheckDemoStatus(); + + I_mkdir(va("%s"PATHSEP"replay", srb2home), 0755); + I_mkdir(va("%s"PATHSEP"replay"PATHSEP"%s", srb2home, timeattackfolder), 0755); + + if ((gpath = malloc(glen)) == NULL) + I_Error("Out of memory for replay filepath\n"); + + sprintf(gpath,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap)); + snprintf(lastdemo, 255, "%s-%s-last.lmp", gpath, skins[cv_chooseskin.value-1].name); + + if (FIL_FileExists(lastdemo)) + { + UINT8 *buf; + size_t len = FIL_ReadFile(lastdemo, &buf); + + snprintf(bestdemo, 255, "%s-%s-time-best.lmp", gpath, skins[cv_chooseskin.value-1].name); + if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & 1) + { // Better time, save this demo. + if (FIL_FileExists(bestdemo)) + remove(bestdemo); + FIL_WriteFile(bestdemo, buf, len); + CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW RECORD TIME!"), M_GetText("Saved replay as"), bestdemo); + } + + snprintf(bestdemo, 255, "%s-%s-score-best.lmp", gpath, skins[cv_chooseskin.value-1].name); + if (!FIL_FileExists(bestdemo) || (G_CmpDemoTime(bestdemo, lastdemo) & (1<<1))) + { // Better score, save this demo. + if (FIL_FileExists(bestdemo)) + remove(bestdemo); + FIL_WriteFile(bestdemo, buf, len); + CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW HIGH SCORE!"), M_GetText("Saved replay as"), bestdemo); + } + + snprintf(bestdemo, 255, "%s-%s-rings-best.lmp", gpath, skins[cv_chooseskin.value-1].name); + if (!FIL_FileExists(bestdemo) || (G_CmpDemoTime(bestdemo, lastdemo) & (1<<2))) + { // Better rings, save this demo. + if (FIL_FileExists(bestdemo)) + remove(bestdemo); + FIL_WriteFile(bestdemo, buf, len); + CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW MOST RINGS!"), M_GetText("Saved replay as"), bestdemo); + } + + //CONS_Printf("%s '%s'\n", M_GetText("Saved replay as"), lastdemo); + + Z_Free(buf); } - - snprintf(bestdemo, 255, "%s-%s-score-best.lmp", gpath, skins[cv_chooseskin.value-1].name); - if (!FIL_FileExists(bestdemo) || (G_CmpDemoTime(bestdemo, lastdemo) & (1<<1))) - { // Better score, save this demo. - if (FIL_FileExists(bestdemo)) - remove(bestdemo); - FIL_WriteFile(bestdemo, buf, len); - CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW HIGH SCORE!"), M_GetText("Saved replay as"), bestdemo); - } - - snprintf(bestdemo, 255, "%s-%s-rings-best.lmp", gpath, skins[cv_chooseskin.value-1].name); - if (!FIL_FileExists(bestdemo) || (G_CmpDemoTime(bestdemo, lastdemo) & (1<<2))) - { // Better rings, save this demo. - if (FIL_FileExists(bestdemo)) - remove(bestdemo); - FIL_WriteFile(bestdemo, buf, len); - CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW MOST RINGS!"), M_GetText("Saved replay as"), bestdemo); - } - - //CONS_Printf("%s '%s'\n", M_GetText("Saved replay as"), lastdemo); - - Z_Free(buf); + free(gpath); } - free(gpath); // Check emblems when level data is updated if ((earnedEmblems = M_CheckLevelEmblems(data))) + { CONS_Printf(M_GetText("\x82" "Earned %hu emblem%s for Record Attack records.\n"), (UINT16)earnedEmblems, earnedEmblems > 1 ? "s" : ""); + } // Update timeattack menu's replay availability. Nextmap_OnChange(); } -void G_SetNightsRecords(gamedata_t *data) +static void G_SetNightsRecords(gamedata_t *data, player_t *player) { - INT32 i; + nightsdata_t *const ntemprecord = &ntemprecords[player - players]; UINT32 totalscore = 0; tic_t totaltime = 0; + INT32 i; + UINT8 earnedEmblems; - const size_t glen = strlen(srb2home)+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1; - char *gpath; - char lastdemo[256], bestdemo[256]; - - if (!ntemprecords.nummares) + if (!ntemprecord->nummares) + { return; + } // Set overall { UINT8 totalrank = 0, realrank = 0; - for (i = 1; i <= ntemprecords.nummares; ++i) + for (i = 1; i <= ntemprecord->nummares; ++i) { - totalscore += ntemprecords.score[i]; - totalrank += ntemprecords.grade[i]; - totaltime += ntemprecords.time[i]; + totalscore += ntemprecord->score[i]; + totalrank += ntemprecord->grade[i]; + totaltime += ntemprecord->time[i]; } // Determine overall grade - realrank = (UINT8)((FixedDiv((fixed_t)totalrank << FRACBITS, ntemprecords.nummares << FRACBITS) + (FRACUNIT/2)) >> FRACBITS); + realrank = (UINT8)((FixedDiv((fixed_t)totalrank << FRACBITS, ntemprecord->nummares << FRACBITS) + (FRACUNIT/2)) >> FRACBITS); // You need ALL rainbow As to get a rainbow A overall - if (realrank == GRADE_S && (totalrank / ntemprecords.nummares) != GRADE_S) + if (realrank == GRADE_S && (totalrank / ntemprecord->nummares) != GRADE_S) + { realrank = GRADE_A; + } - ntemprecords.score[0] = totalscore; - ntemprecords.grade[0] = realrank; - ntemprecords.time[0] = totaltime; + ntemprecord->score[0] = totalscore; + ntemprecord->grade[0] = realrank; + ntemprecord->time[0] = totaltime; } // Now take all temp records and put them in the actual records @@ -660,71 +674,85 @@ void G_SetNightsRecords(gamedata_t *data) nightsdata_t *maprecords; if (!data->nightsrecords[gamemap-1]) + { G_AllocNightsRecordData(gamemap-1, data); + } + maprecords = data->nightsrecords[gamemap-1]; - if (maprecords->nummares != ntemprecords.nummares) - maprecords->nummares = ntemprecords.nummares; - - for (i = 0; i < ntemprecords.nummares + 1; ++i) + if (maprecords->nummares != ntemprecord->nummares) { - if (maprecords->score[i] < ntemprecords.score[i]) - maprecords->score[i] = ntemprecords.score[i]; - if (maprecords->grade[i] < ntemprecords.grade[i]) - maprecords->grade[i] = ntemprecords.grade[i]; - if (!maprecords->time[i] || maprecords->time[i] > ntemprecords.time[i]) - maprecords->time[i] = ntemprecords.time[i]; + maprecords->nummares = ntemprecord->nummares; + } + + for (i = 0; i < ntemprecord->nummares + 1; ++i) + { + if (maprecords->score[i] < ntemprecord->score[i]) + maprecords->score[i] = ntemprecord->score[i]; + if (maprecords->grade[i] < ntemprecord->grade[i]) + maprecords->grade[i] = ntemprecord->grade[i]; + if (!maprecords->time[i] || maprecords->time[i] > ntemprecord->time[i]) + maprecords->time[i] = ntemprecord->time[i]; } } - memset(&ntemprecords, 0, sizeof(nightsdata_t)); + memset(&ntemprecords[player - players], 0, sizeof(nightsdata_t)); - // Save demo! - bestdemo[255] = '\0'; - lastdemo[255] = '\0'; - G_SetDemoTime(totaltime, totalscore, 0); - G_CheckDemoStatus(); - - I_mkdir(va("%s"PATHSEP"replay", srb2home), 0755); - I_mkdir(va("%s"PATHSEP"replay"PATHSEP"%s", srb2home, timeattackfolder), 0755); - - if ((gpath = malloc(glen)) == NULL) - I_Error("Out of memory for replay filepath\n"); - - sprintf(gpath,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap)); - snprintf(lastdemo, 255, "%s-%s-last.lmp", gpath, skins[cv_chooseskin.value-1].name); - - if (FIL_FileExists(lastdemo)) + if (modeattacking) { - UINT8 *buf; - size_t len = FIL_ReadFile(lastdemo, &buf); + const size_t glen = strlen(srb2home)+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1; + char *gpath; + char lastdemo[256], bestdemo[256]; - snprintf(bestdemo, 255, "%s-%s-time-best.lmp", gpath, skins[cv_chooseskin.value-1].name);; - if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & 1) - { // Better time, save this demo. - if (FIL_FileExists(bestdemo)) - remove(bestdemo); - FIL_WriteFile(bestdemo, buf, len); - CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW RECORD TIME!"), M_GetText("Saved replay as"), bestdemo); + // Save demo! + bestdemo[255] = '\0'; + lastdemo[255] = '\0'; + G_SetDemoTime(totaltime, totalscore, 0); + G_CheckDemoStatus(); + + I_mkdir(va("%s"PATHSEP"replay", srb2home), 0755); + I_mkdir(va("%s"PATHSEP"replay"PATHSEP"%s", srb2home, timeattackfolder), 0755); + + if ((gpath = malloc(glen)) == NULL) + I_Error("Out of memory for replay filepath\n"); + + sprintf(gpath,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap)); + snprintf(lastdemo, 255, "%s-%s-last.lmp", gpath, skins[cv_chooseskin.value-1].name); + + if (FIL_FileExists(lastdemo)) + { + UINT8 *buf; + size_t len = FIL_ReadFile(lastdemo, &buf); + + snprintf(bestdemo, 255, "%s-%s-time-best.lmp", gpath, skins[cv_chooseskin.value-1].name);; + if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & 1) + { // Better time, save this demo. + if (FIL_FileExists(bestdemo)) + remove(bestdemo); + FIL_WriteFile(bestdemo, buf, len); + CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW RECORD TIME!"), M_GetText("Saved replay as"), bestdemo); + } + + snprintf(bestdemo, 255, "%s-%s-score-best.lmp", gpath, skins[cv_chooseskin.value-1].name); + if (!FIL_FileExists(bestdemo) || (G_CmpDemoTime(bestdemo, lastdemo) & (1<<1))) + { // Better score, save this demo. + if (FIL_FileExists(bestdemo)) + remove(bestdemo); + FIL_WriteFile(bestdemo, buf, len); + CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW HIGH SCORE!"), M_GetText("Saved replay as"), bestdemo); + } + + //CONS_Printf("%s '%s'\n", M_GetText("Saved replay as"), lastdemo); + + Z_Free(buf); } - - snprintf(bestdemo, 255, "%s-%s-score-best.lmp", gpath, skins[cv_chooseskin.value-1].name); - if (!FIL_FileExists(bestdemo) || (G_CmpDemoTime(bestdemo, lastdemo) & (1<<1))) - { // Better score, save this demo. - if (FIL_FileExists(bestdemo)) - remove(bestdemo); - FIL_WriteFile(bestdemo, buf, len); - CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW HIGH SCORE!"), M_GetText("Saved replay as"), bestdemo); - } - - //CONS_Printf("%s '%s'\n", M_GetText("Saved replay as"), lastdemo); - - Z_Free(buf); + free(gpath); } - free(gpath); if ((earnedEmblems = M_CheckLevelEmblems(data))) + { CONS_Printf(M_GetText("\x82" "Earned %hu emblem%s for NiGHTS records.\n"), (UINT16)earnedEmblems, earnedEmblems > 1 ? "s" : ""); + } // If the mare count changed, this will update the score display Nextmap_OnChange(); @@ -2287,7 +2315,7 @@ void G_Ticker(boolean run) p->lives = startinglivesbalance[0]; p->continues = 1; - p->score = 0; + p->score = p->recordscore = 0; // The latter two should clear by themselves, but just in case p->pflags &= ~(PF_TAGIT|PF_GAMETYPEOVER|PF_FULLSTASIS); @@ -2490,6 +2518,7 @@ static inline void G_PlayerFinishLevel(INT32 player) memset(p->powers, 0, sizeof (p->powers)); p->ringweapons = 0; + p->recordscore = 0; p->mo->flags2 &= ~MF2_SHADOW; // cancel invisibility P_FlashPal(p, 0, 0); // Resets @@ -2513,6 +2542,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) { player_t *p; INT32 score; + INT32 recordscore; INT32 lives; INT32 continues; fixed_t camerascale; @@ -3165,6 +3195,7 @@ void G_DoReborn(INT32 playernum) { if (!playeringame[i]) continue; + players[i].recordscore = 0; players[i].starpostscale = 0; players[i].starpostangle = 0; players[i].starposttime = 0; @@ -3844,15 +3875,16 @@ static INT16 RandMap(UINT32 tolflags, INT16 pprevmap) // // G_UpdateVisited // -static void G_UpdateVisited(gamedata_t *data, boolean silent) +static void G_UpdateVisited(gamedata_t *data, player_t *player, boolean silent) { - boolean spec = G_IsSpecialStage(gamemap); // Update visitation flags? if (!demoplayback && G_CoopGametype() // Campaign mode && !stagefailed) // Did not fail the stage { UINT8 earnedEmblems; + UINT16 totalrings = 0; + INT32 i; // Update visitation flags data->mapvisited[gamemap-1] |= MV_BEATEN; @@ -3861,36 +3893,62 @@ static void G_UpdateVisited(gamedata_t *data, boolean silent) if (ultimatemode) data->mapvisited[gamemap-1] |= MV_ULTIMATE; + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + { + continue; + } + + totalrings += players[i].rings; + } + // may seem incorrect but IS possible in what the main game uses as mp special stages, and nummaprings will be -1 in NiGHTS - if (nummaprings > 0 && players[consoleplayer].rings >= nummaprings) + if (nummaprings > 0 && totalrings >= nummaprings) { data->mapvisited[gamemap-1] |= MV_PERFECT; if (modeattacking) data->mapvisited[gamemap-1] |= MV_PERFECTRA; } - if (!spec) + if (!G_IsSpecialStage(gamemap)) { // not available to special stages because they can only really be done in one order in an unmodified game, so impossible for first six and trivial for seventh if (ALL7EMERALDS(emeralds)) data->mapvisited[gamemap-1] |= MV_ALLEMERALDS; } + if ((earnedEmblems = M_CompletionEmblems(data)) && !silent) + { + CONS_Printf(M_GetText("\x82" "Earned %hu emblem%s for level completion.\n"), (UINT16)earnedEmblems, earnedEmblems > 1 ? "s" : ""); + } + if (silent) { - if (modeattacking) - M_CheckLevelEmblems(data); + M_CheckLevelEmblems(data); } else { - if (modeattacking == ATTACKING_RECORD) - G_UpdateRecordReplays(data); - else if (modeattacking == ATTACKING_NIGHTS) - G_SetNightsRecords(data); + if (mapheaderinfo[gamemap-1]->menuflags & LF2_RECORDATTACK) + G_SetMainRecords(data, player); + else if (mapheaderinfo[gamemap-1]->menuflags & LF2_NIGHTSATTACK) + G_SetNightsRecords(data, player); } + } +} - if ((earnedEmblems = M_CompletionEmblems(data)) && !silent) - CONS_Printf(M_GetText("\x82" "Earned %hu emblem%s for level completion.\n"), (UINT16)earnedEmblems, earnedEmblems > 1 ? "s" : ""); +static void G_UpdateAllVisited(void) +{ + // Update server + G_UpdateVisited(serverGamedata, &players[serverplayer], true); + + // Update client + G_UpdateVisited(clientGamedata, &players[consoleplayer], false); + + if (splitscreen) + { + // Allow P2 to get emblems too, why not :) + G_UpdateVisited(clientGamedata, &players[secondarydisplayplayer], false); } } @@ -3914,6 +3972,9 @@ static boolean CanSaveLevel(INT32 mapnum) static void G_HandleSaveLevel(void) { + // Update records & emblems + G_UpdateAllVisited(); + // do this before running the intermission or custom cutscene, mostly for the sake of marathon mode but it also massively reduces redundant file save events in f_finale.c if (nextmap >= 1100-1) { @@ -4092,8 +4153,6 @@ static void G_DoCompleted(void) if ((skipstats && !modeattacking) || (modeattacking && stagefailed) || (intertype == int_none)) { - G_UpdateVisited(serverGamedata, true); - G_UpdateVisited(clientGamedata, false); G_HandleSaveLevel(); G_AfterIntermission(); } @@ -4102,8 +4161,6 @@ static void G_DoCompleted(void) G_SetGamestate(GS_INTERMISSION); Y_StartIntermission(); Y_LoadIntermissionData(); - G_UpdateVisited(serverGamedata, true); - G_UpdateVisited(clientGamedata, false); G_HandleSaveLevel(); } } @@ -4992,6 +5049,7 @@ void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer, boolean players[i].playerstate = PST_REBORN; players[i].starpostscale = players[i].starpostangle = players[i].starpostnum = players[i].starposttime = 0; players[i].starpostx = players[i].starposty = players[i].starpostz = 0; + players[i].recordscore = 0; if (netgame || multiplayer) { diff --git a/src/g_game.h b/src/g_game.h index 6cda7ca9c..a8c285f79 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -260,8 +260,7 @@ UINT32 G_GetBestNightsScore(INT16 map, UINT8 mare, gamedata_t *data); tic_t G_GetBestNightsTime(INT16 map, UINT8 mare, gamedata_t *data); UINT8 G_GetBestNightsGrade(INT16 map, UINT8 mare, gamedata_t *data); -void G_AddTempNightsRecords(UINT32 pscore, tic_t ptime, UINT8 mare); -void G_SetNightsRecords(gamedata_t *data); +void G_AddTempNightsRecords(player_t *player, UINT32 pscore, tic_t ptime, UINT8 mare); FUNCMATH INT32 G_TicsToHours(tic_t tics); FUNCMATH INT32 G_TicsToMinutes(tic_t tics, boolean full); diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index c056be463..055acfd80 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -114,6 +114,7 @@ enum player_e player_skin, player_availabilities, player_score, + player_recordscore, player_dashspeed, player_normalspeed, player_runspeed, @@ -260,6 +261,7 @@ static const char *const player_opt[] = { "skin", "availabilities", "score", + "recordscore", "dashspeed", "normalspeed", "runspeed", @@ -495,6 +497,9 @@ static int player_get(lua_State *L) case player_score: lua_pushinteger(L, plr->score); break; + case player_recordscore: + lua_pushinteger(L, plr->recordscore); + break; case player_dashspeed: lua_pushfixed(L, plr->dashspeed); break; @@ -957,6 +962,9 @@ static int player_set(lua_State *L) case player_score: plr->score = (UINT32)luaL_checkinteger(L, 3); break; + case player_recordscore: + plr->recordscore = (UINT32)luaL_checkinteger(L, 3); + break; case player_dashspeed: plr->dashspeed = luaL_checkfixed(L, 3); break; diff --git a/src/m_cond.c b/src/m_cond.c index a54988f67..b21778c69 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -45,7 +45,7 @@ INT32 numemblems = 0; INT32 numextraemblems = 0; // Temporary holding place for nights data for the current map -nightsdata_t ntemprecords; +nightsdata_t ntemprecords[MAXPLAYERS]; // Create a new gamedata_t, for start-up gamedata_t *M_NewGameDataStruct(void) diff --git a/src/m_cond.h b/src/m_cond.h index 95c3e1ebe..2be8d564b 100644 --- a/src/m_cond.h +++ b/src/m_cond.h @@ -181,7 +181,7 @@ typedef struct #define MV_MAX 63 // used in gamedata check, update whenever MV's are added // Temporary holding place for nights data for the current map -extern nightsdata_t ntemprecords; +extern nightsdata_t ntemprecords[MAXPLAYERS]; // GAMEDATA STRUCTURE // Everything that would get saved in gamedata.dat diff --git a/src/p_saveg.c b/src/p_saveg.c index 8eac91105..3565d0125 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -179,6 +179,7 @@ static void P_NetArchivePlayers(void) WRITEINT32(save_p, players[i].skin); WRITEUINT32(save_p, players[i].availabilities); WRITEUINT32(save_p, players[i].score); + WRITEUINT32(save_p, players[i].recordscore); WRITEFIXED(save_p, players[i].dashspeed); WRITESINT8(save_p, players[i].lives); WRITESINT8(save_p, players[i].continues); @@ -407,6 +408,7 @@ static void P_NetUnArchivePlayers(void) players[i].skin = READINT32(save_p); players[i].availabilities = READUINT32(save_p); players[i].score = READUINT32(save_p); + players[i].recordscore = READUINT32(save_p); players[i].dashspeed = READFIXED(save_p); // dashing speed players[i].lives = READSINT8(save_p); players[i].continues = READSINT8(save_p); // continues that player has acquired @@ -4342,8 +4344,6 @@ static void P_NetArchiveMisc(boolean resending) WRITEUINT32(save_p, hidetime); - WRITEUINT32(save_p, unlocktriggers); - // Is it paused? if (paused) WRITEUINT8(save_p, 0x2f); @@ -4442,8 +4442,6 @@ static inline boolean P_NetUnArchiveMisc(boolean reloading) hidetime = READUINT32(save_p); - unlocktriggers = READUINT32(save_p); - // Is it paused? if (READUINT8(save_p) == 0x2f) paused = true; @@ -4451,7 +4449,6 @@ static inline boolean P_NetUnArchiveMisc(boolean reloading) return true; } - static inline void P_NetArchiveEmblems(void) { gamedata_t *data = serverGamedata; @@ -4550,6 +4547,27 @@ static inline void P_NetArchiveEmblems(void) WRITEUINT32(save_p, data->nightsrecords[i]->time[curmare]); } } + + // Mid-map stuff + WRITEUINT32(save_p, unlocktriggers); + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!ntemprecords[i].nummares) + { + WRITEUINT8(save_p, 0); + continue; + } + + WRITEUINT8(save_p, ntemprecords[i].nummares); + + for (curmare = 0; curmare < (ntemprecords[i].nummares + 1); ++curmare) + { + WRITEUINT32(save_p, ntemprecords[i].score[curmare]); + WRITEUINT8(save_p, ntemprecords[i].grade[curmare]); + WRITEUINT32(save_p, ntemprecords[i].time[curmare]); + } + } } static inline void P_NetUnArchiveEmblems(void) @@ -4569,9 +4587,9 @@ static inline void P_NetUnArchiveEmblems(void) savemoddata = (boolean)READUINT8(save_p); // this one is actually necessary because savemoddata stays false otherwise for some reason. if (numemblems != READINT32(save_p)) - I_Error("numemblems mismatch"); + I_Error("Bad $$$.sav dearchiving Emblems (numemblems mismatch)"); if (numextraemblems != READINT32(save_p)) - I_Error("numextraemblems mismatch"); + I_Error("Bad $$$.sav dearchiving Emblems (numextraemblems mismatch)"); // This shouldn't happen, but if something really fucked up happens and you transfer // the SERVER player's gamedata over your own CLIENT gamedata, @@ -4590,7 +4608,7 @@ static inline void P_NetUnArchiveEmblems(void) // TODO put another cipher on these things? meh, I don't care... for (i = 0; i < NUMMAPS; i++) if ((data->mapvisited[i] = READUINT8(save_p)) > MV_MAX) - I_Error("Bad $$$.sav dearchiving Emblems"); + I_Error("Bad $$$.sav dearchiving Emblems (invalid visit flags)"); // To save space, use one bit per collected/achieved/unlocked flag for (i = 0; i < MAXEMBLEMS;) @@ -4634,7 +4652,7 @@ static inline void P_NetUnArchiveEmblems(void) recrings = READUINT16(save_p); if (recrings > 10000 || recscore > MAXSCORE) - I_Error("Bad $$$.sav dearchiving Emblems"); + I_Error("Bad $$$.sav dearchiving Emblems (invalid score)"); if (recscore || rectime || recrings) { @@ -4661,12 +4679,35 @@ static inline void P_NetUnArchiveEmblems(void) if (data->nightsrecords[i]->grade[curmare] > GRADE_S) { - I_Error("Bad $$$.sav dearchiving Emblems"); + I_Error("Bad $$$.sav dearchiving Emblems (invalid grade)"); } } data->nightsrecords[i]->nummares = recmares; } + + // Mid-map stuff + unlocktriggers = READUINT32(save_p); + + for (i = 0; i < MAXPLAYERS; ++i) + { + if ((recmares = READUINT8(save_p)) == 0) + continue; + + for (curmare = 0; curmare < (recmares+1); ++curmare) + { + ntemprecords[i].score[curmare] = READUINT32(save_p); + ntemprecords[i].grade[curmare] = READUINT8(save_p); + ntemprecords[i].time[curmare] = (tic_t)READUINT32(save_p); + + if (ntemprecords[i].grade[curmare] > GRADE_S) + { + I_Error("Bad $$$.sav dearchiving Emblems (invalid temp grade)"); + } + } + + ntemprecords[i].nummares = recmares; + } } static inline void P_ArchiveLuabanksAndConsistency(void) diff --git a/src/p_setup.c b/src/p_setup.c index bfb70751d..051853017 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -6985,7 +6985,7 @@ static void P_InitLevelSettings(void) stagefailed = G_IsSpecialStage(gamemap); // Reset temporary record data - memset(&ntemprecords, 0, sizeof(nightsdata_t)); + memset(&ntemprecords, 0, sizeof(ntemprecords)); // earthquake camera memset(&quake,0,sizeof(struct quake)); diff --git a/src/p_user.c b/src/p_user.c index b89552673..a0de50b8f 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -882,8 +882,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime) } // Add score to leaderboards now - if (!(netgame||multiplayer) && P_IsLocalPlayer(&players[i])) - G_AddTempNightsRecords(players[i].marescore, leveltime - player->marebegunat, players[i].mare + 1); + G_AddTempNightsRecords(player, players[i].marescore, leveltime - player->marebegunat, players[i].mare + 1); // transfer scores anyway players[i].totalmarescore += players[i].marescore; @@ -909,8 +908,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime) player->finishedrings = (INT16)(player->rings); // Add score to temp leaderboards - if (!(netgame||multiplayer) && P_IsLocalPlayer(player)) - G_AddTempNightsRecords(player->marescore, leveltime - player->marebegunat, (UINT8)(oldmare + 1)); + G_AddTempNightsRecords(player, player->marescore, leveltime - player->marebegunat, (UINT8)(oldmare + 1)); // Starting a new mare, transfer scores player->totalmarescore += player->marescore; @@ -1440,6 +1438,10 @@ void P_AddPlayerScore(player_t *player, UINT32 amount) if (player->score > MAXSCORE) player->score = MAXSCORE; + player->recordscore += amount; + if (player->recordscore > MAXSCORE) + player->recordscore = MAXSCORE; + // check for extra lives every 50000 pts if (!ultimatemode && !modeattacking && player->score > oldscore && player->score % 50000 < amount && (gametyperules & GTR_LIVES)) { @@ -11732,7 +11734,7 @@ void P_PlayerThink(player_t *player) if (player->spectator) { if (!(gametyperules & GTR_CAMPAIGN)) - player->score = 0; + player->score = player->recordscore = 0; } else if ((netgame || multiplayer) && player->lives <= 0 && !G_CoopGametype()) {