diff --git a/src/acs/environment.cpp b/src/acs/environment.cpp index c56f82d87..ad593e74b 100644 --- a/src/acs/environment.cpp +++ b/src/acs/environment.cpp @@ -198,6 +198,8 @@ void Environment::loadModule(ACSVM::Module *module) { CONS_Printf("No BEHAVIOR lump found.\n"); } + + vres_Free(vRes); } else { diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 53ed80968..f53d1f35a 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2066,7 +2066,7 @@ static void CL_ConnectToServer(void) CONS_Printf(M_GetText("Contacting the server...\n")); } - if (cv_currprofile.value == -1) + if (cv_currprofile.value == -1 && !demo.playback) { PR_ApplyProfilePretend(cv_ttlprofilen.value, 0); for (i = 1; i < cv_splitplayers.value; i++) diff --git a/src/d_main.c b/src/d_main.c index 6f1c0f6a3..38c16bc39 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -952,7 +952,7 @@ void D_ClearState(void) memset(displayplayers, 0, sizeof(displayplayers)); memset(g_localplayers, 0, sizeof g_localplayers); consoleplayer = 0; - //demosequence = -1; + demo.title = false; G_SetGametype(GT_RACE); // SRB2kart paused = false; @@ -968,6 +968,7 @@ void D_ClearState(void) tutorialmode = false; G_SetGamestate(GS_NULL); + wipegamestate = GS_NULL; } // @@ -975,7 +976,9 @@ void D_ClearState(void) // void D_StartTitle(void) { - S_StopMusic(); + if (!demo.title) + S_StopMusic(); + D_ClearState(); F_StartTitleScreen(); M_ClearMenus(false); diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 2522ed4f4..8ca9286d1 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -4894,7 +4894,7 @@ void AltTitle_OnChange(void) if (!M_SecretUnlocked(SECRET_ALTTITLE, true)) { CONS_Printf(M_GetText("You haven't earned this yet.\n")); - CV_StealthSetValue(&cv_itemfinder, 0); + CV_StealthSetValue(&cv_alttitle, 0); return; } } @@ -5784,8 +5784,15 @@ void Command_ExitGame_f(void) if (!modeattacking) { - D_ClearState(); - M_StartControlPanel(); + if (restoreMenu == NULL) + { + D_StartTitle(); + } + else + { + D_ClearState(); + M_StartControlPanel(); + } } } diff --git a/src/deh_soc.c b/src/deh_soc.c index 853c7f182..4a5a6a5fd 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -2185,19 +2185,13 @@ void reademblemdata(MYFILE *f, INT32 num) } while (!myfeof(f)); // Default sprite and color definitions for lazy people like me - if (!emblemlocations[num-1].sprite) switch (emblemlocations[num-1].type) + if (!emblemlocations[num-1].sprite) { - case ET_TIME: - emblemlocations[num-1].sprite = 'B'; break; - default: - emblemlocations[num-1].sprite = 'A'; break; + emblemlocations[num-1].sprite = 'A'; } - if (!emblemlocations[num-1].color) switch (emblemlocations[num-1].type) + if (!emblemlocations[num-1].color) { - case ET_TIME: //case ET_NTIME: - emblemlocations[num-1].color = SKINCOLOR_GREY; break; - default: - emblemlocations[num-1].color = SKINCOLOR_GOLD; break; + emblemlocations[num-1].color = SKINCOLOR_GOLD; } Z_Free(s); diff --git a/src/doomstat.h b/src/doomstat.h index 39b5a73da..9a5b2f893 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -360,6 +360,14 @@ extern cupheader_t *kartcupheaders; // Start of cup linked list extern UINT16 numkartcupheaders; #define MAXMAPLUMPNAME 64 // includes \0, for cleaner savedata +#define MAXSTAFF 3 + +struct staffbrief_t +{ + char name[16]; + tic_t time; + tic_t lap; +}; /** Map header information. */ @@ -374,6 +382,10 @@ struct mapheader_t void *encoreLump; ///< Lump data for the Encore Mode remap. void *tweakLump; ///< Lump data for the palette tweak remap. + // Staff Ghost information + UINT8 ghostCount; ///< Count of valid staff ghosts + staffbrief_t *ghostBrief[MAXSTAFF]; ///< Mallocated array of names for each staff ghost + UINT8 mapvisited; ///< A set of flags that says what we've done in the map. recorddata_t *mainrecord; ///< Stores best time attack data diff --git a/src/f_finale.c b/src/f_finale.c index dd053b558..37a50cb3a 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2194,25 +2194,20 @@ void F_TitleScreenTicker(boolean run) return; } -#ifdef STAFFGHOSTS // is it time? if (!(--demoIdleLeft)) { - //static boolean use_netreplay = false; - - char dname[9]; - char *dname2 = dname; - lumpnum_t l; - const char *mapname; + char dname[MAXMAPLUMPNAME+1+8+1]; + UINT16 mapnum; UINT8 numstaff; + static boolean use_netreplay = false; - //@TODO uncomment this when this goes into vanilla - /*if ((use_netreplay = !use_netreplay))*/ + if ((use_netreplay = !use_netreplay)) { - numstaff = 1; - while ((l = W_CheckNumForName(va("TDEMO%03u", numstaff))) != LUMPERROR) + lumpnum_t l = LUMPERROR; + numstaff = 0; + while (numstaff < 99 && (l = W_CheckNumForName(va("TDEMO%03u", numstaff))) != LUMPERROR) numstaff++; - numstaff--; if (numstaff) { @@ -2225,42 +2220,23 @@ void F_TitleScreenTicker(boolean run) // prevent console spam if failed demoIdleLeft = demoIdleTime; - if ((l = W_CheckNumForName("MAP01S01")) == LUMPERROR) // gotta have ONE + mapnum = G_RandMap(TOL_RACE|TOL_BATTLE, -2, 2, 0, false, NULL); + if (mapnum == 0) // gotta have ONE { - F_StartIntro(); return; } - mapname = G_BuildMapName(G_RandMap(TOL_RACE, -2, 0, 0, false, NULL)+1); - - numstaff = 1; - while (numstaff < 99 && (l = W_CheckNumForLongName(va("%sS%02u",mapname,numstaff+1))) != LUMPERROR) - numstaff++; - - numstaff = M_RandomKey(numstaff)+1; + numstaff = M_RandomKey(mapheaderinfo[mapnum]->ghostCount)+1; // Setup demo name - dname2 = Z_StrDup(va("%sS%02u", mapname, numstaff)); - - /*if ((l = W_CheckNumForName(dname)) == LUMPERROR) -- we KNOW it exists now - { - CONS_Alert(CONS_ERROR, M_GetText("Demo lump \"%s\" doesn't exist\n"), dname); - F_StartIntro(); - return; - }*/ + sprintf(dname, "%s/GHOST_%u", mapheaderinfo[mapnum]->lumpname, numstaff); loadreplay: - demo.title = demo.fromtitle = true; + demo.title = true; demo.ignorefiles = true; demo.loadfiles = false; - G_DoPlayDemo(dname2); - - if (dname2 != dname) - { - Z_Free(dname2); - } + G_DoPlayDemo(dname); } -#endif //#ifdef STAFFGHOSTS } void F_TitleDemoTicker(void) diff --git a/src/g_demo.c b/src/g_demo.c index 286a4e965..e95daa2b5 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -2987,6 +2987,7 @@ void G_DoPlayDemo(char *defdemoname) { snprintf(msg, 1024, M_GetText("Failed to read file '%s'.\n"), defdemoname); CONS_Alert(CONS_ERROR, "%s", msg); + Z_Free(pdemoname); gameaction = ga_nothing; M_StartMessage(msg, NULL, MM_NOTHING); return; @@ -2995,18 +2996,68 @@ void G_DoPlayDemo(char *defdemoname) // load demo resource from WAD else { - if ((l = W_CheckNumForName(defdemoname)) == LUMPERROR) + if (n == defdemoname) { - snprintf(msg, 1024, M_GetText("Failed to read lump '%s'.\n"), defdemoname); - CONS_Alert(CONS_ERROR, "%s", msg); - gameaction = ga_nothing; - M_StartMessage(msg, NULL, MM_NOTHING); - return; - } + // Raw lump. + if ((l = W_CheckNumForName(defdemoname)) == LUMPERROR) + { + snprintf(msg, 1024, M_GetText("Failed to read lump '%s'.\n"), defdemoname); + CONS_Alert(CONS_ERROR, "%s", msg); + Z_Free(pdemoname); + gameaction = ga_nothing; + M_StartMessage(msg, NULL, MM_NOTHING); + return; + } - P_SaveBufferFromLump(&demobuf, l); + P_SaveBufferFromLump(&demobuf, l); + } + else + { + // vres GHOST_%u + virtres_t *vRes; + virtlump_t *vLump; + UINT16 mapnum; + size_t step = 0; + + step = 0; + while (defdemoname+step < n-1) + { + mapname[step] = defdemoname[step]; + step++; + } + mapname[step] = '\0'; + + mapnum = G_MapNumber(mapname); + if (mapnum >= nummapheaders || mapheaderinfo[mapnum]->lumpnum == LUMPERROR) + { + snprintf(msg, 1024, M_GetText("Failed to read virtlump '%s (couldn't find map %s)'.\n"), defdemoname, mapname); + CONS_Alert(CONS_ERROR, "%s", msg); + Z_Free(pdemoname); + gameaction = ga_nothing; + M_StartMessage(msg, NULL, MM_NOTHING); + return; + } + + vRes = vres_GetMap(mapheaderinfo[mapnum]->lumpnum); + vLump = vres_Find(vRes, pdemoname); + + if (vLump == NULL) + { + snprintf(msg, 1024, M_GetText("Failed to read virtlump '%s (couldn't find lump %s in %s)'.\n"), defdemoname, pdemoname, mapname); + CONS_Alert(CONS_ERROR, "%s", msg); + Z_Free(pdemoname); + gameaction = ga_nothing; + M_StartMessage(msg, NULL, MM_NOTHING); + return; + } + + P_SaveBufferAlloc(&demobuf, vLump->size); + memcpy(demobuf.buffer, vLump->data, vLump->size); + + vres_Free(vRes); + } #if defined(SKIPERRORS) && !defined(DEVELOP) - skiperrors = true; // SRB2Kart: Don't print warnings for staff ghosts, since they'll inevitably happen when we make bugfixes/changes... + skiperrors = true; // RR: Don't print warnings for staff ghosts, since they'll inevitably happen when we make bugfixes/changes... #endif } } @@ -3022,7 +3073,6 @@ void G_DoPlayDemo(char *defdemoname) Z_Free(pdemoname); Z_Free(demobuf.buffer); demo.playback = false; - demo.title = false; return; } demobuf.p += 12; // DEMOHEADER @@ -3042,7 +3092,6 @@ void G_DoPlayDemo(char *defdemoname) Z_Free(pdemoname); Z_Free(demobuf.buffer); demo.playback = false; - demo.title = false; return; } @@ -3060,7 +3109,6 @@ void G_DoPlayDemo(char *defdemoname) Z_Free(pdemoname); Z_Free(demobuf.buffer); demo.playback = false; - demo.title = false; return; } demobuf.p += 4; // "PLAY" @@ -3080,7 +3128,6 @@ void G_DoPlayDemo(char *defdemoname) Z_Free(pdemoname); Z_Free(demobuf.buffer); demo.playback = false; - demo.title = false; return; } G_SetGametype(i); @@ -3138,7 +3185,6 @@ void G_DoPlayDemo(char *defdemoname) Z_Free(pdemoname); Z_Free(demobuf.buffer); demo.playback = false; - demo.title = false; return; } } @@ -3153,7 +3199,6 @@ void G_DoPlayDemo(char *defdemoname) Z_Free(pdemoname); Z_Free(demobuf.buffer); demo.playback = false; - demo.title = false; return; } @@ -3189,7 +3234,6 @@ void G_DoPlayDemo(char *defdemoname) Z_Free(pdemoname); Z_Free(demobuf.buffer); demo.playback = false; - demo.title = false; return; } @@ -3207,7 +3251,6 @@ void G_DoPlayDemo(char *defdemoname) Z_Free(pdemoname); Z_Free(demobuf.buffer); demo.playback = false; - demo.title = false; return; } @@ -3262,7 +3305,6 @@ void G_DoPlayDemo(char *defdemoname) Z_Free(pdemoname); Z_Free(demobuf.buffer); demo.playback = false; - demo.title = false; return; } } @@ -3280,7 +3322,6 @@ void G_DoPlayDemo(char *defdemoname) Z_Free(pdemoname); Z_Free(demobuf.buffer); demo.playback = false; - demo.title = false; return; } @@ -3429,14 +3470,13 @@ void G_DoPlayDemo(char *defdemoname) demo.deferstart = true; } -void G_AddGhost(char *defdemoname) +void G_AddGhost(UINT8 *buffer, char *defdemoname) { INT32 i; - lumpnum_t l; - char name[17],color[MAXCOLORNAME+1],*n,*pdemoname,md5[16]; + char name[17], color[MAXCOLORNAME+1], md5[16]; demoghost *gh; UINT8 flags; - UINT8 *buffer,*p; + UINT8 *p; mapthing_t *mthing; UINT16 count, ghostversion; skin_t *ghskin = &skins[0]; @@ -3446,41 +3486,12 @@ void G_AddGhost(char *defdemoname) name[16] = '\0'; color[16] = '\0'; - n = defdemoname+strlen(defdemoname); - while (*n != '/' && *n != '\\' && n != defdemoname) - n--; - if (n != defdemoname) - n++; - pdemoname = ZZ_Alloc(strlen(n)+1); - strcpy(pdemoname,n); - - // Internal if no extension, external if one exists - if (FIL_CheckExtension(defdemoname)) - { - //FIL_DefaultExtension(defdemoname, ".lmp"); - if (!FIL_ReadFileTag(defdemoname, &buffer, PU_LEVEL)) - { - CONS_Alert(CONS_ERROR, M_GetText("Failed to read file '%s'.\n"), defdemoname); - Z_Free(pdemoname); - return; - } - p = buffer; - } - // load demo resource from WAD - else if ((l = W_CheckNumForName(defdemoname)) == LUMPERROR) - { - CONS_Alert(CONS_ERROR, M_GetText("Failed to read lump '%s'.\n"), defdemoname); - Z_Free(pdemoname); - return; - } - else // it's an internal demo - buffer = p = W_CacheLumpNum(l, PU_LEVEL); + p = buffer; // read demo header if (memcmp(p, DEMOHEADER, 12)) { - CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Not a SRB2 replay.\n"), pdemoname); - Z_Free(pdemoname); + CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Not a SRB2 replay.\n"), defdemoname); Z_Free(buffer); return; } p += 12; // DEMOHEADER @@ -3495,8 +3506,7 @@ void G_AddGhost(char *defdemoname) break; // too old, cannot support. default: - CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Demo version incompatible.\n"), pdemoname); - Z_Free(pdemoname); + CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Demo version incompatible.\n"), defdemoname); Z_Free(buffer); return; } @@ -3507,16 +3517,14 @@ void G_AddGhost(char *defdemoname) for (gh = ghosts; gh; gh = gh->next) if (!memcmp(md5, gh->checksum, 16)) // another ghost in the game already has this checksum? { // Don't add another one, then! - CONS_Debug(DBG_SETUP, "Rejecting duplicate ghost %s (MD5 was matched)\n", pdemoname); - Z_Free(pdemoname); + CONS_Debug(DBG_SETUP, "Rejecting duplicate ghost %s (MD5 was matched)\n", defdemoname); Z_Free(buffer); return; } if (memcmp(p, "PLAY", 4)) { - CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Demo format unacceptable.\n"), pdemoname); - Z_Free(pdemoname); + CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Demo format unacceptable.\n"), defdemoname); Z_Free(buffer); return; } p += 4; // "PLAY" @@ -3528,16 +3536,14 @@ void G_AddGhost(char *defdemoname) flags = READUINT8(p); if (!(flags & DF_GHOST)) { - CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: No ghost data in this demo.\n"), pdemoname); - Z_Free(pdemoname); + CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: No ghost data in this demo.\n"), defdemoname); Z_Free(buffer); return; } if (flags & DF_LUAVARS) // can't be arsed to add support for grinding away ported lua material { - CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Replay data contains luavars, cannot continue.\n"), pdemoname); - Z_Free(pdemoname); + CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Replay data contains luavars, cannot continue.\n"), defdemoname); Z_Free(buffer); return; } @@ -3549,8 +3555,7 @@ void G_AddGhost(char *defdemoname) skinlist = G_LoadDemoSkins(&p, &worknumskins, true); if (!skinlist) { - CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Replay data has invalid skin list, cannot continue.\n"), pdemoname); - Z_Free(pdemoname); + CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Replay data has invalid skin list, cannot continue.\n"), defdemoname); Z_Free(buffer); return; } @@ -3578,9 +3583,8 @@ void G_AddGhost(char *defdemoname) if (*p == DEMOMARKER) { - CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Replay is empty.\n"), pdemoname); + CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Replay is empty.\n"), defdemoname); Z_Free(skinlist); - Z_Free(pdemoname); Z_Free(buffer); return; } @@ -3591,9 +3595,8 @@ void G_AddGhost(char *defdemoname) i = READUINT8(p); if ((i & (DEMO_SPECTATOR|DEMO_BOT)) != 0) { - CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Invalid player slot (spectator/bot)\n"), pdemoname); + CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Invalid player slot (spectator/bot)\n"), defdemoname); Z_Free(skinlist); - Z_Free(pdemoname); Z_Free(buffer); return; } @@ -3624,9 +3627,8 @@ void G_AddGhost(char *defdemoname) if (READUINT8(p) != 0xFF) { - CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Invalid player slot (bad terminator)\n"), pdemoname); + CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Invalid player slot (bad terminator)\n"), defdemoname); Z_Free(skinlist); - Z_Free(pdemoname); Z_Free(buffer); return; } @@ -3693,8 +3695,7 @@ void G_AddGhost(char *defdemoname) } gh->oldmo.color = gh->mo->color; - CONS_Printf(M_GetText("Added ghost %s from %s\n"), name, pdemoname); - Z_Free(pdemoname); + CONS_Printf(M_GetText("Added ghost %s from %s\n"), name, defdemoname); } // Clean up all ghosts @@ -3711,14 +3712,17 @@ void G_FreeGhosts(void) } // A simplified version of G_AddGhost... -void G_UpdateStaffGhostName(lumpnum_t l) +staffbrief_t *G_GetStaffGhostBrief(UINT8 *buffer) { - UINT8 *buffer,*p; + UINT8 *p = buffer; UINT16 ghostversion; UINT8 flags; INT32 i; + staffbrief_t temp; + staffbrief_t *ret = NULL; - buffer = p = W_CacheLumpNum(l, PU_CACHE); + temp.name[0] = '\0'; + temp.time = temp.lap = UINT32_MAX; // read demo header if (memcmp(p, DEMOHEADER, 12)) @@ -3766,9 +3770,9 @@ void G_UpdateStaffGhostName(lumpnum_t l) G_SkipDemoSkins(&p); if (flags & ATTACKING_TIME) - p += 4; + temp.time = READUINT32(p); if (flags & ATTACKING_LAP) - p += 4; + temp.lap = READUINT32(p); for (i = 0; i < PRNUMCLASS; i++) { @@ -3781,7 +3785,7 @@ void G_UpdateStaffGhostName(lumpnum_t l) ghostversion = READUINT16(p); while (ghostversion--) { - p += 2; + SKIPSTRING(p); SKIPSTRING(p); p++; // stealth } @@ -3789,13 +3793,18 @@ void G_UpdateStaffGhostName(lumpnum_t l) // Assert first player is in and then read name if (READUINT8(p) != 0) goto fail; - M_Memcpy(dummystaffname, p,16); - dummystaffname[16] = '\0'; + if (READUINT8(p) & (DEMO_SPECTATOR|DEMO_BOT)) + goto fail; + + M_Memcpy(temp.name, p, 16); + + ret = Z_Malloc(sizeof(staffbrief_t), PU_STATIC, NULL); + if (ret) + M_Memcpy(ret, &temp, sizeof(staffbrief_t)); // Ok, no longer any reason to care, bye fail: - Z_Free(buffer); - return; + return ret; } // @@ -4009,7 +4018,6 @@ void G_StopDemo(void) Z_Free(demobuf.buffer); demobuf.buffer = NULL; demo.playback = false; - demo.title = false; demo.timing = false; singletics = false; diff --git a/src/g_demo.h b/src/g_demo.h index a8c3f573c..4b4195e2d 100644 --- a/src/g_demo.h +++ b/src/g_demo.h @@ -47,7 +47,6 @@ struct demovars_s { boolean rewinding; // Rewind in progress boolean loadfiles, ignorefiles; // Demo file loading options - boolean fromtitle; // SRB2Kart: Don't stop the music boolean inreplayhut; // Go back to replayhut after demos boolean quitafterplaying; // quit after playing a demo from cmdline boolean deferstart; // don't start playing demo right away @@ -184,8 +183,8 @@ extern demoghost *ghosts; void G_DeferedPlayDemo(const char *demo); void G_DoPlayDemo(char *defdemoname); void G_TimeDemo(const char *name); -void G_AddGhost(char *defdemoname); -void G_UpdateStaffGhostName(lumpnum_t l); +void G_AddGhost(UINT8 *buffer, char *defdemoname); +staffbrief_t *G_GetStaffGhostBrief(UINT8 *buffer); void G_FreeGhosts(void); void G_DoneLevelLoad(void); diff --git a/src/g_game.c b/src/g_game.c index 972f449e1..0e723c9dd 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -465,11 +465,6 @@ void G_ClearRecords(void) Z_Free(mapheaderinfo[i]->mainrecord); mapheaderinfo[i]->mainrecord = NULL; } - /*if (nightsrecords[i]) - { - Z_Free(nightsrecords[i]); - nightsrecords[i] = NULL; - }*/ } } @@ -495,31 +490,133 @@ tic_t G_GetBestLap(INT16 map) } */ -// -// G_UpdateRecordReplays -// -// Update replay files/data, etc. for Record Attack -// -static void G_UpdateRecordReplays(void) +struct stickermedalinfo stickermedalinfo; + +void G_UpdateTimeStickerMedals(UINT16 map, boolean showownrecord) +{ + emblem_t *emblem = M_GetLevelEmblems(map+1); + boolean gonnadrawtime = false; + + memset(&stickermedalinfo, 0, sizeof(stickermedalinfo)); + stickermedalinfo.timetoreach = UINT32_MAX; + + while (emblem != NULL) + { + UINT8 i = 0; + + switch (emblem->type) + { + case ET_TIME: + { + break; + } + default: + goto bademblem; + } + + if (!gamedata->collected[(emblem-emblemlocations)] && gonnadrawtime) + break; + + // Simpler than having two checks + if (stickermedalinfo.visiblecount == MAXMEDALVISIBLECOUNT) + stickermedalinfo.visiblecount--; + + // Shuffle along, so [0] is the "main focus" + for (i = stickermedalinfo.visiblecount; i > 0; i--) + { + stickermedalinfo.emblems[i] = stickermedalinfo.emblems[i-1]; + } + stickermedalinfo.emblems[0] = emblem; + stickermedalinfo.visiblecount++; + + if (!gamedata->collected[(emblem-emblemlocations)] || Playing()) + gonnadrawtime = true; + +bademblem: + emblem = M_GetLevelEmblems(-1); + } + + if (stickermedalinfo.visiblecount > 0) + { + if (emblem != NULL && emblem != stickermedalinfo.emblems[0]) + { + // Regenerate the entire array if this is unlocked + stickermedalinfo.regenemblem = emblem; + } + emblem = stickermedalinfo.emblems[0]; + + if (gonnadrawtime) + { + if (emblem->tag > 0) + { + if (emblem->tag > mapheaderinfo[map]->ghostCount + || mapheaderinfo[map]->ghostBrief[emblem->tag-1] == NULL) + snprintf(stickermedalinfo.targettext, 9, "Invalid"); + else if (mapheaderinfo[map]->ghostBrief[emblem->tag-1]->time == UINT32_MAX) + snprintf(stickermedalinfo.targettext, 9, "DNF"); + else + stickermedalinfo.timetoreach = mapheaderinfo[map]->ghostBrief[emblem->tag-1]->time; + } + else + stickermedalinfo.timetoreach = emblem->var; + } + } + + if (!gonnadrawtime && showownrecord) + { + stickermedalinfo.timetoreach = G_GetBestTime(map); + } + + if (stickermedalinfo.timetoreach != UINT32_MAX) + { + snprintf(stickermedalinfo.targettext, 9, "%i'%02i\"%02i", + G_TicsToMinutes(stickermedalinfo.timetoreach, false), + G_TicsToSeconds(stickermedalinfo.timetoreach), + G_TicsToCentiseconds(stickermedalinfo.timetoreach)); + } +} + +void G_TickTimeStickerMedals(void) +{ + if (stickermedalinfo.jitter) + stickermedalinfo.jitter--; + + if (players[consoleplayer].realtime > stickermedalinfo.timetoreach) + { + if (stickermedalinfo.norecord == false) + { + S_StartSound(NULL, sfx_s3k72); //sfx_s26d); -- you STOLE fizzy lifting drinks + stickermedalinfo.norecord = true; + stickermedalinfo.jitter = 4; + } + } + else + { + stickermedalinfo.norecord = false; + } +} + +// +// G_UpdateRecords +// +// Update time attack records +// +void G_UpdateRecords(void) { - char *gpath; - char lastdemo[256], bestdemo[256]; UINT8 earnedEmblems; // Record new best time if (!mapheaderinfo[gamemap-1]->mainrecord) G_AllocMainRecordData(gamemap-1); - if (players[consoleplayer].pflags & PF_NOCONTEST) - { - players[consoleplayer].realtime = UINT32_MAX; - } - if (modeattacking & ATTACKING_TIME) { - if (((mapheaderinfo[gamemap-1]->mainrecord->time == 0) || (players[consoleplayer].realtime < mapheaderinfo[gamemap-1]->mainrecord->time)) - && (players[consoleplayer].realtime < UINT32_MAX)) // DNF - mapheaderinfo[gamemap-1]->mainrecord->time = players[consoleplayer].realtime; + tic_t time = players[consoleplayer].realtime; + if (players[consoleplayer].pflags & PF_NOCONTEST) + time = UINT32_MAX; + if (((mapheaderinfo[gamemap-1]->mainrecord->time == 0) || (time < mapheaderinfo[gamemap-1]->mainrecord->time)) + && (time < UINT32_MAX)) // DNF + mapheaderinfo[gamemap-1]->mainrecord->time = time; } else { @@ -536,6 +633,38 @@ static void G_UpdateRecordReplays(void) mapheaderinfo[gamemap-1]->mainrecord->lap = 0; } + // Check emblems when level data is updated + if ((earnedEmblems = M_CheckLevelEmblems())) + { + if (stickermedalinfo.regenemblem != NULL + && gamedata->collected[(stickermedalinfo.regenemblem-emblemlocations)]) + { + G_UpdateTimeStickerMedals(gamemap-1, false); + } + + stickermedalinfo.jitter = 4*earnedEmblems; + S_StartSound(NULL, sfx_ncitem); + } + + M_UpdateUnlockablesAndExtraEmblems(true); + G_SaveGameData(); +} + +// +// G_UpdateRecordReplays +// +// Update replay files/data, etc. for Record Attack +// +static void G_UpdateRecordReplays(void) +{ + char *gpath; + char lastdemo[256], bestdemo[256]; + + if (players[consoleplayer].pflags & PF_NOCONTEST) + { + players[consoleplayer].realtime = UINT32_MAX; + } + // Save demo! bestdemo[255] = '\0'; lastdemo[255] = '\0'; @@ -590,13 +719,6 @@ static void G_UpdateRecordReplays(void) Z_Free(gpath); } - - // Check emblems when level data is updated - if ((earnedEmblems = M_CheckLevelEmblems())) - CONS_Printf(M_GetText("\x82" "Earned %hu medal%s for Record Attack records.\n"), (UINT16)earnedEmblems, earnedEmblems > 1 ? "s" : ""); - - M_UpdateUnlockablesAndExtraEmblems(true); - G_SaveGameData(); } // for consistency among messages: this modifies the game and removes savemoddata. @@ -1339,7 +1461,7 @@ void G_DoLoadLevel(boolean resetplayer) if (wipegamestate == GS_LEVEL) wipegamestate = -1; // force a wipe - if (cv_currprofile.value == -1) + if (cv_currprofile.value == -1 && !demo.playback) { PR_ApplyProfilePretend(cv_ttlprofilen.value, 0); for (i = 1; i < cv_splitplayers.value; i++) @@ -3441,6 +3563,10 @@ tryagain: || (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) @@ -3475,16 +3601,6 @@ tryagain: continue; } -#ifdef STAFFGHOSTS - if (pprevmap == -2) // title demo hack - { - lumpnum_t l; - // TODO: Use map header to determine lump name - if ((l = W_CheckNumForLongName(va("%sS01",G_BuildMapName(ix+1)))) == LUMPERROR) - continue; - } -#endif //#ifdef STAFFGHOSTS - okmaps[numokmaps++] = ix; } diff --git a/src/g_game.h b/src/g_game.h index de60bee49..856df5e13 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -201,6 +201,22 @@ void G_UseContinue(void); void G_AfterIntermission(void); void G_EndGame(void); // moved from y_inter.c/h and renamed +#define MAXMEDALVISIBLECOUNT 3 +extern struct stickermedalinfo +{ + UINT8 visiblecount; + UINT8 jitter; + boolean norecord; + tic_t timetoreach; + emblem_t *emblems[MAXMEDALVISIBLECOUNT]; + emblem_t *regenemblem; + char targettext[9]; +} stickermedalinfo; + +void G_UpdateTimeStickerMedals(UINT16 map, boolean showownrecord); +void G_TickTimeStickerMedals(void); +void G_UpdateRecords(void); + void G_Ticker(boolean run); boolean G_Responder(event_t *ev); diff --git a/src/k_hud.c b/src/k_hud.c index a527c87e3..951c2456b 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -1466,7 +1466,7 @@ static void K_drawKartItem(void) } } -void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UINT8 mode) +void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, UINT8 mode) { // TIME_X = BASEVIDWIDTH-124; // 196 // TIME_Y = 6; // 6 @@ -1550,77 +1550,60 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UI V_DrawKartString(TX+84, TY+3-jitter, splitflags, va("%d", worktime%10)); } - if (emblemmap && (modeattacking || (mode == 1)) && !demo.playback) // emblem time! + // Medal data! + if ((modeattacking || (mode == 1)) + && !demo.playback) { INT32 workx = TX + 96, worky = TY+18; - SINT8 curemb = 0; - patch_t *emblempic[3] = {NULL, NULL, NULL}; - UINT8 *emblemcol[3] = {NULL, NULL, NULL}; + UINT8 i = stickermedalinfo.visiblecount; - emblem_t *emblem = M_GetLevelEmblems(emblemmap); - while (emblem) + if (stickermedalinfo.targettext[0] != '\0') { - char targettext[9]; - - switch (emblem->type) + if (!mode) { - case ET_TIME: - { - static boolean canplaysound = true; - tic_t timetoreach = emblem->var; + if (stickermedalinfo.jitter) + { + jitter = stickermedalinfo.jitter+3; + if (jitter & 2) + workx += jitter/4; + else + workx -= jitter/4; + } - if (gamedata->collected[(emblem-emblemlocations)]) - { - emblempic[curemb] = W_CachePatchName(M_GetEmblemPatch(emblem, false), PU_CACHE); - emblemcol[curemb] = R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(emblem), GTC_CACHE); - if (++curemb == 3) - break; - goto bademblem; - } - - snprintf(targettext, 9, "%i'%02i\"%02i", - G_TicsToMinutes(timetoreach, false), - G_TicsToSeconds(timetoreach), - G_TicsToCentiseconds(timetoreach)); - - if (!mode) - { - if (stplyr->realtime > timetoreach) - { - splitflags = (splitflags &~ V_HUDTRANS)|V_HUDTRANSHALF; - if (canplaysound) - { - S_StartSound(NULL, sfx_s3k72); //sfx_s26d); -- you STOLE fizzy lifting drinks - canplaysound = false; - } - } - else if (!canplaysound) - canplaysound = true; - } - - targettext[8] = 0; - } - break; - default: - goto bademblem; + if (stickermedalinfo.norecord == true) + { + splitflags = (splitflags &~ V_HUDTRANS)|V_HUDTRANSHALF; + } } - V_DrawRightAlignedString(workx, worky, splitflags|V_6WIDTHSPACE, targettext); - workx -= 67; - V_DrawSmallScaledPatch(workx + 4, worky, splitflags, W_CachePatchName("NEEDIT", PU_CACHE)); - - break; - -bademblem: - emblem = M_GetLevelEmblems(-1); + workx -= V_ThinStringWidth(stickermedalinfo.targettext, splitflags|V_6WIDTHSPACE); + V_DrawThinString(workx, worky, splitflags|V_6WIDTHSPACE, stickermedalinfo.targettext); } + workx -= (6 + (i*5)); + if (!mode) splitflags = (splitflags &~ V_HUDTRANSHALF)|V_HUDTRANS; - while (curemb--) + while (i > 0) { - workx -= 12; - V_DrawSmallMappedPatch(workx + 4, worky, splitflags, emblempic[curemb], emblemcol[curemb]); + i--; + + if (gamedata->collected[(stickermedalinfo.emblems[i]-emblemlocations)]) + { + V_DrawSmallMappedPatch(workx, worky, splitflags, + W_CachePatchName(M_GetEmblemPatch(stickermedalinfo.emblems[i], false), PU_CACHE), + R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(stickermedalinfo.emblems[i]), GTC_CACHE) + ); + } + else + { + V_DrawSmallMappedPatch(workx, worky, splitflags, + W_CachePatchName("NEEDIT", PU_CACHE), + NULL + ); + } + + workx += 6; } } } @@ -5054,7 +5037,7 @@ void K_drawKartHUD(void) { // Draw the timestamp if (LUA_HudEnabled(hud_time)) - K_drawKartTimestamp(stplyr->realtime, TIME_X, TIME_Y, gamemap, 0); + K_drawKartTimestamp(stplyr->realtime, TIME_X, TIME_Y, 0); islonesome = K_drawKartPositionFaces(); } @@ -5063,17 +5046,17 @@ void K_drawKartHUD(void) { if (demo.title) // Draw title logo instead in demo.titles { - INT32 x = BASEVIDWIDTH - 32, y = 128, snapflags = V_SNAPTOBOTTOM|V_SNAPTORIGHT; + INT32 x = BASEVIDWIDTH - 8, y = BASEVIDHEIGHT-8, snapflags = V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_SLIDEIN; + patch_t *pat = W_CachePatchName((cv_alttitle.value ? "MTSJUMPR1" : "MTSBUMPR1"), PU_CACHE); if (r_splitscreen == 3) { - x = BASEVIDWIDTH/2 + 10; - y = BASEVIDHEIGHT/2 - 30; + x = BASEVIDWIDTH/2; + y = BASEVIDHEIGHT/2; snapflags = 0; } - V_DrawTinyScaledPatch(x-54, y, snapflags|V_SLIDEIN, W_CachePatchName("TTKBANNR", PU_CACHE)); - V_DrawTinyScaledPatch(x-54, y+25, snapflags|V_SLIDEIN, W_CachePatchName("TTKART", PU_CACHE)); + V_DrawScaledPatch(x-(SHORT(pat->width)), y-(SHORT(pat->height)), snapflags, pat); } else { diff --git a/src/k_hud.h b/src/k_hud.h index 7960c0aba..982cc76f5 100644 --- a/src/k_hud.h +++ b/src/k_hud.h @@ -40,7 +40,7 @@ const char *K_GetItemPatch(UINT8 item, boolean tiny); void K_LoadKartHUDGraphics(void); void K_drawKartHUD(void); void K_drawKartFreePlay(void); -void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UINT8 mode); +void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, UINT8 mode); void K_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, INT32 whiteplayer, INT32 hilicol); void K_DrawMapThumbnail(INT32 x, INT32 y, INT32 width, UINT32 flags, UINT16 map, UINT8 *colormap); void K_DrawLikeMapThumbnail(INT32 x, INT32 y, INT32 width, UINT32 flags, patch_t *patch, UINT8 *colormap); diff --git a/src/k_menu.h b/src/k_menu.h index de53864b1..b1b699fbc 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -469,7 +469,6 @@ void Moviemode_option_Onchange(void); extern menu_t *currentMenu; extern menu_t *restoreMenu; -extern char dummystaffname[22]; extern consvar_t cv_dummystaff; extern INT16 itemOn; // menu item skull is on, Hack by Tails 09-18-2002 @@ -576,7 +575,7 @@ boolean M_MenuButtonPressed(UINT8 pid, UINT32 bt); boolean M_MenuButtonHeld(UINT8 pid, UINT32 bt); boolean M_ChangeStringCvar(INT32 choice); - +void M_ChangeCvarDirect(INT32 choice, consvar_t *cv); boolean M_NextOpt(void); boolean M_PrevOpt(void); diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 20c51b412..0963909b7 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -2240,7 +2240,6 @@ void M_DrawTimeAttack(void) INT32 w; patch_t *minimap = NULL; UINT8 i; - consvar_t *cv; M_DrawLevelSelectBlock(0, 2, map, true, false); @@ -2267,7 +2266,7 @@ void M_DrawTimeAttack(void) && (mapheaderinfo[map]->numlaps != 1)) { V_DrawRightAlignedString(rightedge-12, timeheight, highlightflags, "BEST LAP:"); - K_drawKartTimestamp(laprec, 162+t, timeheight+6, 0, 2); + K_drawKartTimestamp(laprec, 162+t, timeheight+6, 2); timeheight += 30; } else @@ -2276,7 +2275,7 @@ void M_DrawTimeAttack(void) } V_DrawRightAlignedString(rightedge-12, timeheight, highlightflags, "BEST TIME:"); - K_drawKartTimestamp(timerec, 162+t, timeheight+6, map, 1); + K_drawKartTimestamp(timerec, 162+t, timeheight+6, 1); } else opty = 80; @@ -2303,19 +2302,56 @@ void M_DrawTimeAttack(void) opty += 10; // Cvar specific handling - - if (currentMenu->menuitems[i].status & IT_CVAR) { - cv = currentMenu->menuitems[i].itemaction.cvar; + const char *str = NULL; + INT32 optflags = f; + boolean drawarrows = (i == itemOn); - w = V_StringWidth(cv->string, 0); - V_DrawString(leftedge, opty, f, cv->string); - if (i == itemOn) + if ((currentMenu->menuitems[i].status & IT_TYPE) == IT_ARROWS) { - V_DrawCharacter(leftedge - 10 - (skullAnimCounter/5), opty, '\x1C' | f, false); // left arrow - V_DrawCharacter(leftedge + w + 2+ (skullAnimCounter/5), opty, '\x1D' | f, false); // right arrow + // Currently assumes M_HandleStaffReplay + if (mapheaderinfo[levellist.choosemap]->ghostCount <= 1) + drawarrows = false; + + optflags |= V_ALLOWLOWERCASE; + if (mapheaderinfo[levellist.choosemap] == NULL) + str = "Invalid map"; + else if (cv_dummystaff.value > mapheaderinfo[levellist.choosemap]->ghostCount) + str = va("%u - Invalid ID", cv_dummystaff.value+1); + else if (mapheaderinfo[levellist.choosemap]->ghostBrief[cv_dummystaff.value] == NULL) + str = va("%u - Invalid brief", cv_dummystaff.value+1); + else + { + const char *th = "th"; + if (cv_dummystaff.value+1 == 1) + th = "st"; + else if (cv_dummystaff.value+1 == 2) + th = "nd"; + else if (cv_dummystaff.value+1 == 3) + th = "rd"; + str = va("%u%s - %s", + cv_dummystaff.value+1, + th, + mapheaderinfo[levellist.choosemap]->ghostBrief[cv_dummystaff.value]->name + ); + } + } + else if ((currentMenu->menuitems[i].status & IT_TYPE) == IT_CVAR) + { + str = currentMenu->menuitems[i].itemaction.cvar->string; + } + + if (str) + { + w = V_StringWidth(str, optflags); + V_DrawString(leftedge+12, opty, optflags, str); + if (drawarrows) + { + V_DrawCharacter(leftedge+12 - 10 - (skullAnimCounter/5), opty, '\x1C' | f, false); // left arrow + V_DrawCharacter(leftedge+12 + w + 2+ (skullAnimCounter/5), opty, '\x1D' | f, false); // right arrow + } + opty += 10; } - opty += 10; } break; diff --git a/src/k_menufunc.c b/src/k_menufunc.c index 7fd1adc61..eb0add401 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -37,8 +37,6 @@ boolean fromlevelselect = false; menu_t *currentMenu = &MAIN_ProfilesDef; menu_t *restoreMenu = NULL; -char dummystaffname[22]; - INT16 itemOn = 0; // menu item skull is on, Hack by Tails 09-18-2002 INT16 skullAnimCounter = 8; // skull animation counter struct menutransition_s menutransition; // Menu transition properties @@ -77,7 +75,7 @@ consvar_t cv_tutorialprompt = CVAR_INIT ("tutorialprompt", "On", CV_SAVE, CV_OnO static CV_PossibleValue_t dummyteam_cons_t[] = {{0, "Spectator"}, {1, "Red"}, {2, "Blue"}, {0, NULL}}; static CV_PossibleValue_t dummyspectate_cons_t[] = {{0, "Spectator"}, {1, "Playing"}, {0, NULL}}; static CV_PossibleValue_t dummyscramble_cons_t[] = {{0, "Random"}, {1, "Points"}, {0, NULL}}; -static CV_PossibleValue_t dummystaff_cons_t[] = {{0, "MIN"}, {100, "MAX"}, {0, NULL}}; +static CV_PossibleValue_t dummystaff_cons_t[] = {{0, "MIN"}, {MAXSTAFF-1, "MAX"}, {0, NULL}}; static consvar_t cv_dummyteam = CVAR_INIT ("dummyteam", "Spectator", CV_HIDDEN, dummyteam_cons_t, NULL); //static cv_dummyspectate = CVAR_INITconsvar_t ("dummyspectate", "Spectator", CV_HIDDEN, dummyspectate_cons_t, NULL); @@ -92,39 +90,15 @@ consvar_t cv_dummyspectate = CVAR_INIT ("dummyspectate", "Spectator", CV_HIDDEN, static void Dummystaff_OnChange(void) { -#ifdef STAFFGHOSTS - lumpnum_t l; + if (mapheaderinfo[levellist.choosemap] == NULL || mapheaderinfo[levellist.choosemap]->ghostCount <= 0) + return; - dummystaffname[0] = '\0'; - - if ((l = W_CheckNumForName(va("%sS01",G_BuildMapName(cv_nextmap.value)))) == LUMPERROR) + dummystaff_cons_t[1].value = mapheaderinfo[levellist.choosemap]->ghostCount-1; + if (cv_dummystaff.value > dummystaff_cons_t[1].value) { CV_StealthSetValue(&cv_dummystaff, 0); return; } - else - { - char *temp = dummystaffname; - UINT8 numstaff = 1; - while (numstaff < 99 && (l = W_CheckNumForName(va("%sS%02u",G_BuildMapName(cv_nextmap.value),numstaff+1))) != LUMPERROR) - numstaff++; - - if (cv_dummystaff.value < 1) - CV_StealthSetValue(&cv_dummystaff, numstaff); - else if (cv_dummystaff.value > numstaff) - CV_StealthSetValue(&cv_dummystaff, 1); - - if ((l = W_CheckNumForName(va("%sS%02u",G_BuildMapName(cv_nextmap.value), cv_dummystaff.value))) == LUMPERROR) - return; // shouldn't happen but might as well check... - - G_UpdateStaffGhostName(l); - - while (*temp) - temp++; - - sprintf(temp, " - %d", cv_dummystaff.value); - } -#endif //#ifdef STAFFGHOSTS } @@ -132,10 +106,8 @@ static void Dummystaff_OnChange(void) // BASIC MENU HANDLING // ========================================================================= -static void M_ChangeCvar(INT32 choice) +void M_ChangeCvarDirect(INT32 choice, consvar_t *cv) { - consvar_t *cv = currentMenu->menuitems[itemOn].itemaction.cvar; - // Backspace sets values to default value if (choice == -1) { @@ -143,7 +115,7 @@ static void M_ChangeCvar(INT32 choice) return; } - choice = (choice<<1) - 1; + choice = (choice == 0 ? -1 : 1); if (((currentMenu->menuitems[itemOn].status & IT_CVARTYPE) == IT_CV_SLIDER) || ((currentMenu->menuitems[itemOn].status & IT_CVARTYPE) == IT_CV_INVISSLIDER) @@ -170,6 +142,11 @@ static void M_ChangeCvar(INT32 choice) } } +static void M_ChangeCvar(INT32 choice) +{ + M_ChangeCvarDirect(choice, currentMenu->menuitems[itemOn].itemaction.cvar); +} + boolean M_NextOpt(void) { INT16 oldItemOn = itemOn; // prevent infinite loop @@ -466,7 +443,7 @@ void M_StartControlPanel(void) } // intro might call this repeatedly - if (menuactive && gamestate != GS_NULL) + if (mapchangepending || (menuactive && gamestate != GS_NULL)) { CON_ToggleOff(); // move away console return; @@ -939,7 +916,7 @@ static void M_HandleMenuInput(void) { case IT_CVAR: case IT_ARROWS: - routine(1); // right arrow + routine(2); // usually right arrow break; case IT_CALL: routine(itemOn); @@ -965,19 +942,17 @@ static void M_HandleMenuInput(void) if (routine && ((currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_ARROWS || (currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_CVAR)) { - consvar_t *cv = currentMenu->menuitems[itemOn].itemaction.cvar; + /*consvar_t *cv = currentMenu->menuitems[itemOn].itemaction.cvar; // Make these CVar options? if (cv == &cv_chooseskin || cv == &cv_dummystaff - /* || cv == &cv_nextmap || cv == &cv_newgametype - */ ) { return; - } + }*/ S_StartSound(NULL, sfx_s3k5b); diff --git a/src/m_cond.c b/src/m_cond.c index d93ff8d55..4f0a9126a 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -949,6 +949,7 @@ UINT8 M_CheckLevelEmblems(void) { INT32 i; INT32 valToReach; + INT16 tag; INT16 levelnum; UINT8 res; UINT8 somethingUnlocked = 0; @@ -968,11 +969,23 @@ UINT8 M_CheckLevelEmblems(void) levelnum = checkLevel; valToReach = emblemlocations[i].var; + tag = emblemlocations[i].tag; switch (emblemlocations[i].type) { case ET_TIME: // Requires time on map <= x - res = (G_GetBestTime(levelnum) <= (unsigned)valToReach); + if (tag > 0) + { + if (tag > mapheaderinfo[checkLevel]->ghostCount + || mapheaderinfo[checkLevel]->ghostBrief[tag-1] == NULL) + continue; + + res = (G_GetBestTime(levelnum) <= mapheaderinfo[checkLevel]->ghostBrief[tag-1]->time); + } + else + { + res = (G_GetBestTime(levelnum) <= (unsigned)valToReach); + } break; default: // unreachable but shuts the compiler up. continue; @@ -998,7 +1011,7 @@ UINT8 M_CompletionEmblems(void) // Bah! Duplication sucks, but it's for a separa { INT32 checkLevel; - if (emblemlocations[i].type < ET_TIME || gamedata->collected[i]) + if (emblemlocations[i].type != ET_MAP || gamedata->collected[i]) continue; checkLevel = M_EmblemMapNum(&emblemlocations[i]); diff --git a/src/menus/play-local-race-time-attack.c b/src/menus/play-local-race-time-attack.c index 244b720b2..054681792 100644 --- a/src/menus/play-local-race-time-attack.c +++ b/src/menus/play-local-race-time-attack.c @@ -56,7 +56,7 @@ menuitem_t PLAY_TAReplay[] = {IT_HEADERTEXT|IT_HEADER, "", NULL, NULL, {NULL}, 0, 0}, {IT_STRING | IT_CALL, "Replay Last", NULL, NULL, {.routine = M_ReplayTimeAttack}, 0, 0}, {IT_STRING | IT_CALL, "Replay Guest", NULL, NULL, {.routine = M_ReplayTimeAttack}, 0, 0}, - {IT_STRING | IT_CALL, "Replay Staff", NULL, NULL, {.routine = M_HandleStaffReplay}, 0, 0}, + {IT_STRING | IT_ARROWS, "Replay Staff", NULL, NULL, {.routine = M_HandleStaffReplay}, 0, 0}, {IT_HEADERTEXT|IT_HEADER, "", NULL, NULL, {NULL}, 0, 0}, {IT_STRING | IT_SUBMENU, "Back", NULL, NULL, {.submenu = &PLAY_TimeAttackDef}, 0, 0}, @@ -178,6 +178,7 @@ void M_PrepareTimeAttack(INT32 choice) { (void) choice; + // Gametype guess if (levellist.guessgt != MAXGAMETYPES) { levellist.newgametype = levellist.guessgt; @@ -189,6 +190,10 @@ void M_PrepareTimeAttack(INT32 choice) } } + // Time-sticker Medals + G_UpdateTimeStickerMedals(levellist.choosemap, false); + + // Menu options { // see also p_setup.c's P_LoadRecordGhosts char *gpath = Z_StrDup(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(levellist.choosemap+1))); @@ -197,8 +202,6 @@ void M_PrepareTimeAttack(INT32 choice) if (!gpath) return; - CV_StealthSetValue(&cv_dummystaff, 0); - active = false; PLAY_TimeAttack[ta_guest].status = IT_DISABLED; PLAY_TimeAttack[ta_replay].status = IT_DISABLED; @@ -257,16 +260,13 @@ void M_PrepareTimeAttack(INT32 choice) PLAY_TAReplay[tareplay_staff].status = PLAY_TAGhosts[taghost_staff].status = IT_DISABLED; -#ifdef STAFFGHOSTS - CV_SetValue(&cv_dummystaff, 1); - if (cv_dummystaff.value) + if (mapheaderinfo[levellist.choosemap]->ghostCount > 0) { - PLAY_TAReplay[tareplay_staff].status = IT_STRING|IT_KEYHANDLER; + PLAY_TAReplay[tareplay_staff].status = IT_STRING|IT_ARROWS; PLAY_TAGhosts[taghost_staff].status = IT_STRING|IT_CVAR; - CV_StealthSetValue(&cv_dummystaff, 1); + CV_SetValue(&cv_dummystaff, 0); active |= 1|4; } -#endif //#ifdef STAFFGHOSTS if (active & 1) PLAY_TimeAttack[ta_replay].status = IT_STRING|IT_SUBMENU; @@ -287,8 +287,19 @@ void M_PrepareTimeAttack(INT32 choice) void M_HandleStaffReplay(INT32 choice) { - // @TODO: - (void) choice; + if (choice == 2) + { + restoreMenu = &PLAY_TimeAttackDef; + + M_ClearMenus(true); + demo.loadfiles = false; + demo.ignorefiles = true; // Just assume that record attack replays have the files needed + + G_DoPlayDemo(va("%s/GHOST_%u", mapheaderinfo[levellist.choosemap]->lumpname, cv_dummystaff.value+1)); + return; + } + + M_ChangeCvarDirect(choice, &cv_dummystaff); } void M_ReplayTimeAttack(INT32 choice) @@ -457,4 +468,6 @@ void M_StartTimeAttack(INT32 choice) M_ClearMenus(true); D_MapChange(levellist.choosemap+1, levellist.newgametype, (cv_dummygpencore.value == 1), 1, 1, false, false); + + G_UpdateTimeStickerMedals(levellist.choosemap, true); } diff --git a/src/menus/transient/pause-replay.c b/src/menus/transient/pause-replay.c index 037889f4f..5a7c45826 100644 --- a/src/menus/transient/pause-replay.c +++ b/src/menus/transient/pause-replay.c @@ -50,15 +50,13 @@ menu_t PAUSE_PlaybackMenuDef = { void M_EndModeAttackRun(void) { - boolean dotitle = demo.title; - G_CheckDemoStatus(); // Cancel recording Command_ExitGame_f(); // Clear a bunch of state modeattacking = ATTACKING_NONE; // Kept until now because of Command_ExitGame_f - if (dotitle) + if (demo.title == true) { D_StartTitle(); } @@ -210,7 +208,14 @@ void M_PlaybackSetViews(INT32 choice) } else if (r_splitscreen) { - r_splitscreen--; + if (choice == 0) + { + r_splitscreen--; + } + else + { + r_splitscreen = 0; + } R_ExecuteSetViewSize(); } } diff --git a/src/p_setup.c b/src/p_setup.c index 9b99bc01b..2d4e2d54d 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -471,6 +471,7 @@ void P_AllocMapHeader(INT16 i) mapheaderinfo[i]->lumpname = NULL; mapheaderinfo[i]->thumbnailPic = NULL; mapheaderinfo[i]->minimapPic = NULL; + mapheaderinfo[i]->ghostCount = 0; mapheaderinfo[i]->cup = NULL; mapheaderinfo[i]->mainrecord = NULL; mapheaderinfo[i]->flickies = NULL; @@ -6909,8 +6910,6 @@ static boolean P_LoadMapFromFile(void) spawnsectors[i].tags.tags = memcpy(Z_Malloc(sectors[i].tags.count*sizeof(mtag_t), PU_LEVEL, NULL), sectors[i].tags.tags, sectors[i].tags.count*sizeof(mtag_t)); P_MakeMapMD5(curmapvirt, &mapmd5); - - vres_Free(curmapvirt); return true; } @@ -7139,6 +7138,23 @@ static void P_ResetSpawnpoints(void) skyboxviewpnts[i] = skyboxcenterpnts[i] = NULL; } +static void P_TryAddExternalGhost(char *defdemoname) +{ + UINT8 *buffer = NULL; + + if (FIL_FileExists(defdemoname)) + { + if (FIL_ReadFileTag(defdemoname, &buffer, PU_LEVEL)) + { + G_AddGhost(buffer, defdemoname); + } + else + { + CONS_Alert(CONS_ERROR, M_GetText("Failed to read file '%s'.\n"), defdemoname); + } + } +} + static void P_LoadRecordGhosts(void) { // see also /menus/play-local-race-time-attack.c's M_PrepareTimeAttack @@ -7157,8 +7173,7 @@ static void P_LoadRecordGhosts(void) if (cv_ghost_besttime.value == 1 && players[consoleplayer].skin != i) continue; - if (FIL_FileExists(va("%s-%s-time-best.lmp", gpath, skins[i].name))) - G_AddGhost(va("%s-%s-time-best.lmp", gpath, skins[i].name)); + P_TryAddExternalGhost(va("%s-%s-time-best.lmp", gpath, skins[i].name)); } } } @@ -7173,8 +7188,7 @@ static void P_LoadRecordGhosts(void) if (cv_ghost_bestlap.value == 1 && players[consoleplayer].skin != i) continue; - if (FIL_FileExists(va("%s-%s-lap-best.lmp", gpath, skins[i].name))) - G_AddGhost(va("%s-%s-lap-best.lmp", gpath, skins[i].name)); + P_TryAddExternalGhost(va("%s-%s-lap-best.lmp", gpath, skins[i].name)); } } } @@ -7187,29 +7201,35 @@ static void P_LoadRecordGhosts(void) if (cv_ghost_last.value == 1 && players[consoleplayer].skin != i) continue; - if (FIL_FileExists(va("%s-%s-last.lmp", gpath, skins[i].name))) - G_AddGhost(va("%s-%s-last.lmp", gpath, skins[i].name)); + P_TryAddExternalGhost(va("%s-%s-last.lmp", gpath, skins[i].name)); } } // Guest ghost - if (cv_ghost_guest.value && FIL_FileExists(va("%s-guest.lmp", gpath))) - G_AddGhost(va("%s-guest.lmp", gpath)); + if (cv_ghost_guest.value) + P_TryAddExternalGhost(va("%s-guest.lmp", gpath)); -#ifdef STAFFGHOSTS // Staff Attack ghosts if (cv_ghost_staff.value) { - lumpnum_t l; - UINT8 j = 1; - // TODO: Use vres for lumps - while (j <= 99 && (l = W_CheckNumForLongName(va("%sS%02u",G_BuildMapName(gamemap),j))) != LUMPERROR) + char *defdemoname; + virtlump_t *vLump; + UINT8 *buffer = NULL; + + for (i = mapheaderinfo[gamemap-1]->ghostCount; i > 0; i--) { - G_AddGhost(va("%sS%02u",G_BuildMapName(gamemap),j)); - j++; + defdemoname = va("GHOST_%u", i); + vLump = vres_Find(curmapvirt, defdemoname); + if (vLump == NULL) + { + CONS_Alert(CONS_ERROR, M_GetText("Failed to read virtlump '%s'.\n"), defdemoname); + continue; + } + buffer = Z_Malloc(vLump->size, PU_LEVEL, NULL); + memcpy(buffer, vLump->data, vLump->size); + G_AddGhost(buffer, defdemoname); } } -#endif //#ifdef STAFFGHOSTS Z_Free(gpath); } @@ -7803,6 +7823,10 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) if (!fromnetsave) P_InitGametype(); + // Now safe to free. + vres_Free(curmapvirt); + curmapvirt = NULL; + if (!reloadinggamestate) { P_InitCamera(); @@ -8020,11 +8044,13 @@ INT16 wadnamemap = 0; // gamemap based UINT8 P_InitMapData(boolean existingmapheaders) { UINT8 ret = 0; - INT32 i; + INT32 i, j; lumpnum_t maplump; virtres_t *virtmap; - virtlump_t *minimap, *thumbnailPic; + virtlump_t *minimap, *thumbnailPic, *ghost; char *name; + char buffer[9]; + sprintf(buffer, "GHOST_x"); for (i = 0; i < nummapheaders; ++i) { @@ -8036,7 +8062,6 @@ UINT8 P_InitMapData(boolean existingmapheaders) if (maplump != LUMPERROR || mapheaderinfo[i]->lumpnum != LUMPERROR) { cupheader_t *cup = kartcupheaders; - INT32 j; while (cup) { @@ -8118,16 +8143,46 @@ UINT8 P_InitMapData(boolean existingmapheaders) } // Now apply the new ones! - if (thumbnailPic) + if (thumbnailPic != NULL) { mapheaderinfo[i]->thumbnailPic = vres_GetPatch(thumbnailPic, PU_STATIC); } - if (minimap) + if (minimap != NULL) { mapheaderinfo[i]->minimapPic = vres_GetPatch(minimap, PU_STATIC); } + // Staff ghosts. + // The trouble with staff ghosts is that they're too large to cache. + // So we store extra information about them, and load later. + while (mapheaderinfo[i]->ghostCount > 0) + { + mapheaderinfo[i]->ghostCount--; + + Z_Free(mapheaderinfo[i]->ghostBrief[mapheaderinfo[i]->ghostCount]); + mapheaderinfo[i]->ghostBrief[mapheaderinfo[i]->ghostCount] = NULL; + } + + while (mapheaderinfo[i]->ghostCount < MAXSTAFF) + { + buffer[6] = '1' + mapheaderinfo[i]->ghostCount; + + ghost = vres_Find(virtmap, buffer); + if (ghost == NULL) + break; + + mapheaderinfo[i]->ghostBrief[mapheaderinfo[i]->ghostCount] = G_GetStaffGhostBrief(ghost->data); + if (mapheaderinfo[i]->ghostBrief[mapheaderinfo[i]->ghostCount] == NULL) + break; + /*CONS_Printf("name is %s, time is %d, lap is %d\n", + mapheaderinfo[i]->ghostBrief[mapheaderinfo[i]->ghostCount]->name, + mapheaderinfo[i]->ghostBrief[mapheaderinfo[i]->ghostCount]->time/TICRATE, + mapheaderinfo[i]->ghostBrief[mapheaderinfo[i]->ghostCount]->lap/TICRATE);*/ + + mapheaderinfo[i]->ghostCount++; + } + vres_Free(virtmap); } } diff --git a/src/p_tick.c b/src/p_tick.c index b3576424d..7973f7972 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -766,7 +766,11 @@ void P_Ticker(boolean run) } if (modeattacking) + { G_GhostTicker(); + if (!demo.playback) + G_TickTimeStickerMedals(); + } if (mapreset > 1 && --mapreset <= 1 diff --git a/src/p_user.c b/src/p_user.c index f3c7c49c9..078f6e5ad 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1367,6 +1367,9 @@ void P_DoPlayerExit(player_t *player) } } + if (modeattacking) + G_UpdateRecords(); + player->karthud[khud_cardanimation] = 0; // srb2kart: reset battle animation if (player == &players[consoleplayer]) diff --git a/src/s_sound.c b/src/s_sound.c index aedcaee15..e146e5dd6 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -1761,6 +1761,10 @@ UINT32 S_GetMusicLoopPoint(void) boolean S_SetMusicPosition(UINT32 position) { + if (demo.rewinding // Don't mess with music while rewinding! + || demo.title) // SRB2Kart: Demos don't interrupt title screen music + return false; + return I_SetSongPosition(position); } @@ -1962,7 +1966,13 @@ boolean S_RecallMusic(UINT16 status, boolean fromfirst) UINT32 newpos = 0; boolean mapmuschanged = false; musicstack_t *result; - musicstack_t *entry = Z_Calloc(sizeof (*result), PU_MUSIC, NULL); + musicstack_t *entry; + + if (demo.rewinding // Don't mess with music while rewinding! + || demo.title) // SRB2Kart: Demos don't interrupt title screen music + return false; + + entry = Z_Calloc(sizeof (*result), PU_MUSIC, NULL); if (status) result = S_GetMusicStackEntry(status, fromfirst, -1); @@ -2387,6 +2397,10 @@ void S_StopFadingMusic(void) boolean S_FadeMusicFromVolume(UINT8 target_volume, INT16 source_volume, UINT32 ms) { + if (demo.rewinding // Don't mess with music while rewinding! + || demo.title) // SRB2Kart: Demos don't interrupt title screen music + return false; + if (source_volume < 0) return I_FadeSong(target_volume, ms, NULL); else @@ -2395,6 +2409,10 @@ boolean S_FadeMusicFromVolume(UINT8 target_volume, INT16 source_volume, UINT32 m boolean S_FadeOutStopMusic(UINT32 ms) { + if (demo.rewinding // Don't mess with music while rewinding! + || demo.title) // SRB2Kart: Demos don't interrupt title screen music + return false; + return I_FadeSong(0, ms, &S_StopMusic); } diff --git a/src/typedef.h b/src/typedef.h index f33ee2f3b..a38b018a0 100644 --- a/src/typedef.h +++ b/src/typedef.h @@ -113,6 +113,7 @@ TYPEDEF (textprompt_t); TYPEDEF (mappoint_t); TYPEDEF (customoption_t); TYPEDEF (gametype_t); +TYPEDEF (staffbrief_t); TYPEDEF (mapheader_t); TYPEDEF (tolinfo_t); TYPEDEF (cupheader_t);