From 845fe12b526f89f7800b48b7f4ab847956241448 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 30 Nov 2022 13:19:21 +0000 Subject: [PATCH] Conversion to using gamedata_t A small piece of (STJr/SRB2!1756). Due to how RR currently handles time attack records and how it WILL handle unlocks, it's not currently feasible to split everything such that you can have two independent gamedata_t... but what's done so far is certainly more sane and less dependent on global variables Other minor refactors: - M_UpdateUnlockablesAndExtraEmblems and M_SilentUpdateUnlockablesAndEmblems are now one function with a boolean for loudness - Unlock prints are currently living in the console, since the cecho stuff was a little broken --- src/d_main.c | 2 + src/doomstat.h | 7 --- src/f_finale.c | 33 ++-------- src/g_game.c | 66 +++++++++---------- src/k_hud.c | 2 +- src/k_menudraw.c | 6 +- src/k_menufunc.c | 8 +-- src/k_pwrlv.c | 4 +- src/m_cheat.c | 8 +-- src/m_cond.c | 160 +++++++++++++++++++++++------------------------ src/m_cond.h | 41 +++++++++--- src/m_random.c | 4 +- src/p_inter.c | 4 +- src/p_mobj.c | 2 +- src/p_setup.c | 2 +- src/p_spec.c | 4 +- src/p_tick.c | 3 +- src/r_skins.c | 4 +- 18 files changed, 174 insertions(+), 186 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index af438e1b4..de93741ba 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1377,6 +1377,8 @@ void D_SRB2Main(void) Z_Init(); CON_SetLoadingProgress(LOADED_ZINIT); + M_NewGameDataStruct(); + // Do this up here so that WADs loaded through the command line can use ExecCfg COM_Init(); diff --git a/src/doomstat.h b/src/doomstat.h index 3338e9b76..55644bfb2 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -186,8 +186,6 @@ extern INT32 postimgparam[MAXSPLITSCREENPLAYERS]; extern INT32 viewwindowx, viewwindowy; extern INT32 viewwidth, scaledviewwidth; -extern boolean gamedataloaded; - // Player taking events, and displaying. extern INT32 consoleplayer; extern INT32 displayplayers[MAXSPLITSCREENPLAYERS]; @@ -538,9 +536,6 @@ typedef struct extern tolinfo_t TYPEOFLEVEL[NUMTOLNAMES]; extern UINT32 lastcustomtol; -extern tic_t totalplaytime; -extern UINT32 matchesplayed; - extern UINT8 stagefailed; // Emeralds stored as bits to throw savegame hackers off. @@ -682,8 +677,6 @@ extern INT16 votelevels[4][2]; extern SINT8 votes[MAXPLAYERS]; extern SINT8 pickedvote; -extern UINT32 timesBeaten; // # of times the game has been beaten. - // =========================== // Internal parameters, fixed. // =========================== diff --git a/src/f_finale.c b/src/f_finale.c index ca5b44fb3..fb11ee3f2 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -866,7 +866,7 @@ boolean F_CreditResponder(event_t *event) return false; } - /*if (!(timesBeaten) && !(netgame || multiplayer) && !cht_debug) + /*if (!(gamedata->timesBeaten) && !(netgame || multiplayer) && !cht_debug) return false;*/ if (key != KEY_ESCAPE && key != KEY_ENTER && key != KEY_BACKSPACE) @@ -1024,31 +1024,6 @@ void F_GameEvaluationDrawer(void) V_DrawCreditString((BASEVIDWIDTH - V_CreditStringWidth(endingtext))<<(FRACBITS-1), (BASEVIDHEIGHT-100)<<(FRACBITS-1), 0, endingtext); -#if 0 // the following looks like hot garbage the more unlockables we add, and we now have a lot of unlockables - if (finalecount >= 5*TICRATE) - { - V_DrawString(8, 16, V_YELLOWMAP, "Unlocked:"); - - if (!usedCheats) - { - INT32 startcoord = 32; - - for (i = 0; i < MAXUNLOCKABLES; i++) - { - if (unlockables[i].conditionset && unlockables[i].conditionset < MAXCONDITIONSETS - && unlockables[i].type && !unlockables[i].nocecho) - { - if (unlockables[i].unlocked) - V_DrawString(8, startcoord, 0, unlockables[i].name); - startcoord += 8; - } - } - } - else - V_DrawString(8, 96, V_YELLOWMAP, "Cheated games\ncan't unlock\nextras!"); - } -#endif - if (marathonmode) { const char *rtatext, *cuttext; @@ -1101,9 +1076,9 @@ void F_GameEvaluationTicker(void) { if (!usedCheats) { - ++timesBeaten; + ++gamedata->timesBeaten; - if (M_UpdateUnlockablesAndExtraEmblems()) + if (M_UpdateUnlockablesAndExtraEmblems(true)) S_StartSound(NULL, sfx_s3k68); G_SaveGameData(); @@ -1611,7 +1586,7 @@ void F_EndingDrawer(void) //colset(linkmap, 164, 165, 169); -- the ideal purple colour to represent a clicked in-game link, but not worth it just for a soundtest-controlled secret V_DrawCenteredString(BASEVIDWIDTH/2, 8, V_ALLOWLOWERCASE|(trans<'|(trans<= STOPPINGPOINT-TICRATE) ? V_PURPLEMAP : V_BLUEMAP)|(trans<"); + V_DrawString(40, ((finalecount == STOPPINGPOINT-(20+TICRATE)) ? 1 : 0)+BASEVIDHEIGHT-16, ((gamedata->timesBeaten || finalecount >= STOPPINGPOINT-TICRATE) ? V_PURPLEMAP : V_BLUEMAP)|(trans<"); } if (finalecount > STOPPINGPOINT-(20+(2*TICRATE))) diff --git a/src/g_game.c b/src/g_game.c index bebaa11b0..fcdc4b628 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -189,7 +189,8 @@ struct quake quake; // Map Header Information mapheader_t** mapheaderinfo = {NULL}; -INT32 nummapheaders, mapallocsize = 0; +INT32 nummapheaders = 0; +INT32 mapallocsize = 0; // Kart cup definitions cupheader_t *kartcupheaders = NULL; @@ -208,10 +209,6 @@ UINT32 tokenlist; // List of tokens collected boolean gottoken; // Did you get a token? Used for end of act INT32 tokenbits; // Used for setting token bits -tic_t totalplaytime; -UINT32 matchesplayed; // SRB2Kart -boolean gamedataloaded = false; - // Temporary holding place for nights data for the current map //nightsdata_t ntemprecords; @@ -340,9 +337,6 @@ static void G_ResetRandMapBuffer(void) //intentionally not resetting randmaps.counttogametype here } -// Grading -UINT32 timesBeaten; - typedef struct joystickvector2_s { INT32 xaxis; @@ -600,7 +594,7 @@ static void G_UpdateRecordReplays(void) if ((earnedEmblems = M_CheckLevelEmblems())) CONS_Printf(M_GetText("\x82" "Earned %hu medal%s for Record Attack records.\n"), (UINT16)earnedEmblems, earnedEmblems > 1 ? "s" : ""); - if (M_UpdateUnlockablesAndExtraEmblems()) + if (M_UpdateUnlockablesAndExtraEmblems(true)) S_StartSound(NULL, sfx_ncitem); // SRB2Kart - save here so you NEVER lose your earned times/medals. @@ -2194,8 +2188,8 @@ static inline void G_PlayerFinishLevel(INT32 player) { if (legitimateexit && !demo.playback && !mapreset) // (yes you're allowed to unlock stuff this way when the game is modified) { - matchesplayed++; - if (M_UpdateUnlockablesAndExtraEmblems()) + gamedata->matchesplayed++; + if (M_UpdateUnlockablesAndExtraEmblems(true)) S_StartSound(NULL, sfx_ncitem); G_SaveGameData(); } @@ -3691,7 +3685,7 @@ static void G_UpdateVisited(void) if ((earnedEmblems = M_CompletionEmblems())) CONS_Printf(M_GetText("\x82" "Earned %hu emblem%s for level completion.\n"), (UINT16)earnedEmblems, earnedEmblems > 1 ? "s" : ""); - if (M_UpdateUnlockablesAndExtraEmblems()) + if (M_UpdateUnlockablesAndExtraEmblems(true)) S_StartSound(NULL, sfx_ncitem); G_SaveGameData(); } @@ -3876,7 +3870,7 @@ static void G_GetNextMap(void) while (cup) { // Not unlocked? Grab the next result afterwards - if (!marathonmode && cup->unlockrequired != -1 && !unlockables[cup->unlockrequired].unlocked) + if (!marathonmode && cup->unlockrequired != -1 && !gamedata->unlocked[cup->unlockrequired]) { cup = cup->next; gettingresult = 1; @@ -4326,15 +4320,15 @@ void G_LoadGameData(void) UINT32 numgamedatamapheaders; // Stop saving, until we successfully load it again. - gamedataloaded = false; + gamedata->loaded = false; // Clear things so previously read gamedata doesn't transfer // to new gamedata - G_ClearRecords(); // main and nights records + G_ClearRecords(); // records M_ClearSecrets(); // emblems, unlocks, maps visited, etc - totalplaytime = 0; // total play time (separate from all) - matchesplayed = 0; // SRB2Kart: matches played & finished + gamedata->totalplaytime = 0; // total play time (separate from all) + gamedata->matchesplayed = 0; // SRB2Kart: matches played & finished if (M_CheckParm("-nodata")) { @@ -4345,7 +4339,7 @@ void G_LoadGameData(void) if (M_CheckParm("-resetdata")) { // Don't load, but do save. (essentially, reset) - gamedataloaded = true; + gamedata->loaded = true; return; } @@ -4353,7 +4347,7 @@ void G_LoadGameData(void) if (!length) { // No gamedata. We can save a new one. - gamedataloaded = true; + gamedata->loaded = true; return; } @@ -4372,8 +4366,8 @@ void G_LoadGameData(void) I_Error("Game data is not for Ring Racers v2.0.\nDelete %s(maybe in %s) and try again.", gamedatafilename, gdfolder); } - totalplaytime = READUINT32(save_p); - matchesplayed = READUINT32(save_p); + gamedata->totalplaytime = READUINT32(save_p); + gamedata->matchesplayed = READUINT32(save_p); { // Quick & dirty hash for what mod this save file is for. @@ -4392,32 +4386,32 @@ void G_LoadGameData(void) { rtemp = READUINT8(save_p); for (j = 0; j < 8 && j+i < MAXEMBLEMS; ++j) - emblemlocations[j+i].collected = ((rtemp >> j) & 1); + gamedata->collected[j+i] = ((rtemp >> j) & 1); i += j; } for (i = 0; i < MAXEXTRAEMBLEMS;) { rtemp = READUINT8(save_p); for (j = 0; j < 8 && j+i < MAXEXTRAEMBLEMS; ++j) - extraemblems[j+i].collected = ((rtemp >> j) & 1); + gamedata->extraCollected[j+i] = ((rtemp >> j) & 1); i += j; } for (i = 0; i < MAXUNLOCKABLES;) { rtemp = READUINT8(save_p); for (j = 0; j < 8 && j+i < MAXUNLOCKABLES; ++j) - unlockables[j+i].unlocked = ((rtemp >> j) & 1); + gamedata->unlocked[j+i] = ((rtemp >> j) & 1); i += j; } for (i = 0; i < MAXCONDITIONSETS;) { rtemp = READUINT8(save_p); for (j = 0; j < 8 && j+i < MAXCONDITIONSETS; ++j) - conditionSets[j+i].achieved = ((rtemp >> j) & 1); + gamedata->achieved[j+i] = ((rtemp >> j) & 1); i += j; } - timesBeaten = READUINT32(save_p); + gamedata->timesBeaten = READUINT32(save_p); // Main records numgamedatamapheaders = READUINT32(save_p); @@ -4469,10 +4463,10 @@ void G_LoadGameData(void) // It used to do this much earlier, but this would cause the gamedata to // save over itself when it I_Errors from the corruption landing point below, // which can accidentally delete players' legitimate data if the code ever has any tiny mistakes! - gamedataloaded = true; + gamedata->loaded = true; // Silent update unlockables in case they're out of sync with conditions - M_SilentUpdateUnlockablesAndEmblems(); + M_UpdateUnlockablesAndExtraEmblems(false); return; @@ -4498,7 +4492,7 @@ void G_SaveGameData(void) INT32 i, j; UINT8 btemp; - if (!gamedataloaded) + if (!gamedata->loaded) return; // If never loaded (-nodata), don't save if (usedCheats) @@ -4522,8 +4516,8 @@ void G_SaveGameData(void) // Version test WRITEUINT32(save_p, GD_VERSIONCHECK); // 4 - WRITEUINT32(save_p, totalplaytime); // 4 - WRITEUINT32(save_p, matchesplayed); // 4 + WRITEUINT32(save_p, gamedata->totalplaytime); // 4 + WRITEUINT32(save_p, gamedata->matchesplayed); // 4 WRITEUINT32(save_p, quickncasehash(timeattackfolder, 64)); // To save space, use one bit per collected/achieved/unlocked flag @@ -4531,7 +4525,7 @@ void G_SaveGameData(void) { btemp = 0; for (j = 0; j < 8 && j+i < MAXEMBLEMS; ++j) - btemp |= (emblemlocations[j+i].collected << j); + btemp |= (gamedata->collected[j+i] << j); WRITEUINT8(save_p, btemp); i += j; } @@ -4539,7 +4533,7 @@ void G_SaveGameData(void) { btemp = 0; for (j = 0; j < 8 && j+i < MAXEXTRAEMBLEMS; ++j) - btemp |= (extraemblems[j+i].collected << j); + btemp |= (gamedata->extraCollected[j+i] << j); WRITEUINT8(save_p, btemp); i += j; } @@ -4547,7 +4541,7 @@ void G_SaveGameData(void) { btemp = 0; for (j = 0; j < 8 && j+i < MAXUNLOCKABLES; ++j) - btemp |= (unlockables[j+i].unlocked << j); + btemp |= (gamedata->unlocked[j+i] << j); WRITEUINT8(save_p, btemp); i += j; } @@ -4555,12 +4549,12 @@ void G_SaveGameData(void) { btemp = 0; for (j = 0; j < 8 && j+i < MAXCONDITIONSETS; ++j) - btemp |= (conditionSets[j+i].achieved << j); + btemp |= (gamedata->achieved[j+i] << j); WRITEUINT8(save_p, btemp); i += j; } - WRITEUINT32(save_p, timesBeaten); // 4 + WRITEUINT32(save_p, gamedata->timesBeaten); // 4 // Main records WRITEUINT32(save_p, nummapheaders); // 4 diff --git a/src/k_hud.c b/src/k_hud.c index 5325f07eb..73625dba7 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -1494,7 +1494,7 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UI static boolean canplaysound = true; tic_t timetoreach = emblem->var; - if (emblem->collected) + 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); diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 8bfec4716..6c2c2029e 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -1908,7 +1908,7 @@ static void M_DrawCupPreview(INT16 y, cupheader_t *cup) V_DrawFill(0, y, BASEVIDWIDTH, 54, 31); - if (cup && (cup->unlockrequired == -1 || unlockables[cup->unlockrequired].unlocked)) + if (cup && (cup->unlockrequired == -1 || gamedata->unlocked[cup->unlockrequired])) { i = (cupgrid.previewanim / 82) % cup->numlevels; while (x < BASEVIDWIDTH + pad) @@ -1946,7 +1946,7 @@ static void M_DrawCupTitle(INT16 y, cupheader_t *cup) if (cup) { - boolean unlocked = (cup->unlockrequired == -1 || unlockables[cup->unlockrequired].unlocked); + boolean unlocked = (cup->unlockrequired == -1 || gamedata->unlocked[cup->unlockrequired]); UINT8 *colormap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_GREY, GTC_MENUCACHE); patch_t *icon = W_CachePatchName(cup->icon, PU_CACHE); const char *str = (unlocked ? va("%s Cup", cup->name) : "???"); @@ -2014,7 +2014,7 @@ void M_DrawCupSelect(void) V_DrawScaledPatch(x, y, 0, patch); - if (iconcup->unlockrequired != -1 && !unlockables[iconcup->unlockrequired].unlocked) + if (iconcup->unlockrequired != -1 && !gamedata->unlocked[iconcup->unlockrequired]) { patch_t *st = W_CachePatchName(va("ICONST0%d", (cupgrid.previewanim % 4) + 1), PU_CACHE); V_DrawScaledPatch(x + 8, y + icony, 0, st); diff --git a/src/k_menufunc.c b/src/k_menufunc.c index 696c14593..39f94a1d9 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -343,8 +343,8 @@ static void M_EraseDataResponse(INT32 ch) if (optionsmenu.erasecontext == 2) { // SRB2Kart: This actually needs to be done FIRST, so that you don't immediately regain playtime/matches secrets - totalplaytime = 0; - matchesplayed = 0; + gamedata->totalplaytime = 0; + gamedata->matchesplayed = 0; } if (optionsmenu.erasecontext != 1) G_ClearRecords(); @@ -3441,7 +3441,7 @@ static void M_LevelListFromGametype(INT16 gt) while (cup) { - if (cup->unlockrequired == -1 || unlockables[cup->unlockrequired].unlocked) + if (cup->unlockrequired == -1 || gamedata->unlocked[cup->unlockrequired]) { highestid = cup->id; if (Playing() && mapheaderinfo[gamemap-1] && mapheaderinfo[gamemap-1]->cup == cup) @@ -3575,7 +3575,7 @@ void M_CupSelectHandler(INT32 choice) M_SetMenuDelay(pid); if ((!newcup) - || (newcup && newcup->unlockrequired != -1 && !unlockables[newcup->unlockrequired].unlocked) + || (newcup && newcup->unlockrequired != -1 && !gamedata->unlocked[newcup->unlockrequired]) || (newcup->cachedlevels[0] == NEXTMAP_INVALID)) { S_StartSound(NULL, sfx_s3kb2); diff --git a/src/k_pwrlv.c b/src/k_pwrlv.c index 32a4b8ecd..e4623281b 100644 --- a/src/k_pwrlv.c +++ b/src/k_pwrlv.c @@ -418,7 +418,7 @@ void K_CashInPowerLevels(void) { pr->powerlevels[powerType] = clientpowerlevels[i][powerType]; - if (M_UpdateUnlockablesAndExtraEmblems()) + if (M_UpdateUnlockablesAndExtraEmblems(true)) { S_StartSound(NULL, sfx_ncitem); } @@ -642,7 +642,7 @@ void K_PlayerForfeit(UINT8 playerNum, boolean pointLoss) { pr->powerlevels[powerType] = yourPower + inc; - if (M_UpdateUnlockablesAndExtraEmblems()) + if (M_UpdateUnlockablesAndExtraEmblems(true)) { S_StartSound(NULL, sfx_ncitem); } diff --git a/src/m_cheat.c b/src/m_cheat.c index be4f231e1..edd23041c 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -76,16 +76,16 @@ static UINT8 cheatf_warp(void) { if (!unlockables[i].conditionset) continue; - if (!unlockables[i].unlocked) + if (!gamedata->unlocked[i]) { - unlockables[i].unlocked = true; + gamedata->unlocked[i] = true; success = true; } } if (success) { - G_SaveGameData(); //G_SetUsedCheats(); + G_SetUsedCheats(); S_StartSound(0, sfx_kc42); } @@ -111,7 +111,7 @@ static UINT8 cheatf_devmode(void) // Just unlock all the things and turn on -debug and console devmode. G_SetUsedCheats(); for (i = 0; i < MAXUNLOCKABLES; i++) - unlockables[i].unlocked = true; + gamedata->unlocked[i] = true; devparm = true; cht_debug |= 0x8000; diff --git a/src/m_cond.c b/src/m_cond.c index 53ff790a6..79dd92d2a 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -24,6 +24,8 @@ #include "k_pwrlv.h" #include "k_profiles.h" +gamedata_t *gamedata = NULL; + // Map triggers for linedef executors // 32 triggers, one bit each UINT32 unlocktriggers; @@ -44,6 +46,14 @@ unlockable_t unlockables[MAXUNLOCKABLES]; INT32 numemblems = 0; INT32 numextraemblems = 0; +// Create a new gamedata_t, for start-up +void M_NewGameDataStruct(void) +{ + gamedata = Z_Calloc(sizeof (gamedata_t), PU_STATIC, NULL); + M_ClearSecrets(); + G_ClearRecords(); +} + void M_AddRawCondition(UINT8 set, UINT8 id, conditiontype_t c, INT32 r, INT16 x1, INT16 x2) { condition_t *cond; @@ -73,7 +83,7 @@ void M_ClearConditionSet(UINT8 set) conditionSets[set - 1].condition = NULL; conditionSets[set - 1].numconditions = 0; } - conditionSets[set - 1].achieved = false; + gamedata->achieved[set - 1] = false; } // Clear ALL secrets. @@ -87,18 +97,18 @@ void M_ClearSecrets(void) } for (i = 0; i < MAXEMBLEMS; ++i) - emblemlocations[i].collected = false; + gamedata->collected[i] = false; for (i = 0; i < MAXEXTRAEMBLEMS; ++i) - extraemblems[i].collected = false; + gamedata->extraCollected[i] = false; for (i = 0; i < MAXUNLOCKABLES; ++i) - unlockables[i].unlocked = false; + gamedata->unlocked[i] = false; for (i = 0; i < MAXCONDITIONSETS; ++i) - conditionSets[i].achieved = false; + gamedata->achieved[i] = false; - timesBeaten = 0; + gamedata->timesBeaten = 0; // Re-unlock any always unlocked things - M_SilentUpdateUnlockablesAndEmblems(); + M_UpdateUnlockablesAndExtraEmblems(false); } // ---------------------- @@ -109,9 +119,9 @@ UINT8 M_CheckCondition(condition_t *cn) switch (cn->type) { case UC_PLAYTIME: // Requires total playing time >= x - return (totalplaytime >= (unsigned)cn->requirement); + return (gamedata->totalplaytime >= (unsigned)cn->requirement); case UC_MATCHESPLAYED: // Requires any level completed >= x times - return (matchesplayed >= (unsigned)cn->requirement); + return (gamedata->matchesplayed >= (unsigned)cn->requirement); case UC_POWERLEVEL: // Requires power level >= x on a certain gametype { UINT8 i; @@ -128,7 +138,7 @@ UINT8 M_CheckCondition(condition_t *cn) return false; } case UC_GAMECLEAR: // Requires game beaten >= x times - return (timesBeaten >= (unsigned)cn->requirement); + return (gamedata->timesBeaten >= (unsigned)cn->requirement); case UC_OVERALLTIME: // Requires overall time <= x return (M_GotLowEnoughTime(cn->requirement)); case UC_MAPVISITED: // Requires map x to be visited @@ -152,9 +162,9 @@ UINT8 M_CheckCondition(condition_t *cn) case UC_TOTALEMBLEMS: // Requires number of emblems >= x return (M_GotEnoughEmblems(cn->requirement)); case UC_EMBLEM: // Requires emblem x to be obtained - return emblemlocations[cn->requirement-1].collected; + return gamedata->collected[cn->requirement-1]; case UC_EXTRAEMBLEM: // Requires extra emblem x to be obtained - return extraemblems[cn->requirement-1].collected; + return gamedata->extraCollected[cn->requirement-1]; case UC_CONDITIONSET: // requires condition set x to already be achieved return M_Achieved(cn->requirement-1); } @@ -196,14 +206,14 @@ void M_CheckUnlockConditions(void) for (i = 0; i < MAXCONDITIONSETS; ++i) { c = &conditionSets[i]; - if (!c->numconditions || c->achieved) + if (!c->numconditions || gamedata->achieved[i]) continue; - c->achieved = (M_CheckConditionSet(c)); + gamedata->achieved[i] = (M_CheckConditionSet(c)); } } -UINT8 M_UpdateUnlockablesAndExtraEmblems(void) +boolean M_UpdateUnlockablesAndExtraEmblems(boolean loud) { INT32 i; char cechoText[992] = ""; @@ -211,16 +221,31 @@ UINT8 M_UpdateUnlockablesAndExtraEmblems(void) M_CheckUnlockConditions(); + if (!loud) + { + // Just in case they aren't to sync + M_CheckLevelEmblems(); + M_CompletionEmblems(); + } + // Go through extra emblems for (i = 0; i < numextraemblems; ++i) { - if (extraemblems[i].collected || !extraemblems[i].conditionset) - continue; - if ((extraemblems[i].collected = M_Achieved(extraemblems[i].conditionset - 1)) != false) + if (gamedata->extraCollected[i] || !extraemblems[i].conditionset) { - strcat(cechoText, va(M_GetText("Got \"%s\" medal!\\"), extraemblems[i].name)); - ++cechoLines; + continue; } + + if ((gamedata->extraCollected[i] = M_Achieved(extraemblems[i].conditionset - 1)) == false) + { + continue; + } + + if (loud) + { + strcat(cechoText, va("Got \"%s\" medal!\n", extraemblems[i].name)); + } + ++cechoLines; } // Fun part: if any of those unlocked we need to go through the @@ -231,67 +256,40 @@ UINT8 M_UpdateUnlockablesAndExtraEmblems(void) // Go through unlockables for (i = 0; i < MAXUNLOCKABLES; ++i) { - if (unlockables[i].unlocked || !unlockables[i].conditionset) - continue; - if ((unlockables[i].unlocked = M_Achieved(unlockables[i].conditionset - 1)) != false) + if (gamedata->unlocked[i] || !unlockables[i].conditionset) { - if (unlockables[i].nocecho) - continue; - strcat(cechoText, va(M_GetText("\"%s\" unlocked!\\"), unlockables[i].name)); - ++cechoLines; + continue; } + + if ((gamedata->unlocked[i] = M_Achieved(unlockables[i].conditionset - 1)) == false) + { + continue; + } + + if (unlockables[i].nocecho) + { + continue; + } + + if (loud) + { + strcat(cechoText, va("\"%s\" unlocked!\n", unlockables[i].name)); + } + ++cechoLines; } // Announce - if (cechoLines) + if (cechoLines && loud) { - char slashed[1024] = ""; - for (i = 0; (i < 19) && (i < 24 - cechoLines); ++i) - slashed[i] = '\\'; - slashed[i] = 0; - - strcat(slashed, cechoText); - - HU_SetCEchoFlags(V_YELLOWMAP); - HU_SetCEchoDuration(6); - HU_DoCEcho(slashed); +#ifdef DEVELOP + // todo make debugmode + CONS_Printf("%s\n", cechoText); +#endif return true; } return false; } -// Used when loading gamedata to make sure all unlocks are synched with conditions -void M_SilentUpdateUnlockablesAndEmblems(void) -{ - INT32 i; - boolean checkAgain = false; - - // Just in case they aren't to sync - M_CheckUnlockConditions(); - M_CheckLevelEmblems(); - - // Go through extra emblems - for (i = 0; i < numextraemblems; ++i) - { - if (extraemblems[i].collected || !extraemblems[i].conditionset) - continue; - if ((extraemblems[i].collected = M_Achieved(extraemblems[i].conditionset - 1)) != false) - checkAgain = true; - } - - // check again if extra emblems unlocked, blah blah, etc - if (checkAgain) - M_CheckUnlockConditions(); - - // Go through unlockables - for (i = 0; i < MAXUNLOCKABLES; ++i) - { - if (unlockables[i].unlocked || !unlockables[i].conditionset) - continue; - unlockables[i].unlocked = M_Achieved(unlockables[i].conditionset - 1); - } -} - // Emblem unlocking shit UINT8 M_CheckLevelEmblems(void) { @@ -306,7 +304,7 @@ UINT8 M_CheckLevelEmblems(void) { INT32 checkLevel; - if (emblemlocations[i].type < ET_TIME || emblemlocations[i].collected) + if (emblemlocations[i].type < ET_TIME || gamedata->collected[i]) continue; checkLevel = G_MapNumber(emblemlocations[i].level); @@ -326,7 +324,7 @@ UINT8 M_CheckLevelEmblems(void) continue; } - emblemlocations[i].collected = res; + gamedata->collected[i] = res; if (res) ++somethingUnlocked; } @@ -346,7 +344,7 @@ UINT8 M_CompletionEmblems(void) // Bah! Duplication sucks, but it's for a separa { INT32 checkLevel; - if (emblemlocations[i].type < ET_TIME || emblemlocations[i].collected) + if (emblemlocations[i].type < ET_TIME || gamedata->collected[i]) continue; checkLevel = G_MapNumber(emblemlocations[i].level); @@ -363,7 +361,7 @@ UINT8 M_CompletionEmblems(void) // Bah! Duplication sucks, but it's for a separa res = ((mapheaderinfo[levelnum]->mapvisited & flags) == flags); - emblemlocations[i].collected = res; + gamedata->collected[i] = res; if (res) ++somethingUnlocked; } @@ -385,7 +383,7 @@ UINT8 M_AnySecretUnlocked(void) for (i = 0; i < MAXUNLOCKABLES; ++i) { - if (!unlockables[i].nocecho && unlockables[i].unlocked) + if (!unlockables[i].nocecho && gamedata->unlocked[i]) return true; } return false; @@ -412,7 +410,7 @@ UINT8 M_SecretUnlocked(INT32 type) for (i = 0; i < MAXUNLOCKABLES; ++i) { - if (unlockables[i].type == type && unlockables[i].unlocked != CHADYES) + if (unlockables[i].type == type && gamedata->unlocked[i] != CHADYES) return !CHADYES; } return CHADYES; @@ -435,7 +433,7 @@ UINT8 M_MapLocked(INT32 mapnum) if (!mapheaderinfo[mapnum-1] || mapheaderinfo[mapnum-1]->unlockrequired < 0) return false; - if (!unlockables[mapheaderinfo[mapnum-1]->unlockrequired].unlocked) + if (!gamedata->unlocked[mapheaderinfo[mapnum-1]->unlockrequired]) return true; return false; @@ -447,12 +445,12 @@ INT32 M_CountEmblems(void) INT32 found = 0, i; for (i = 0; i < numemblems; ++i) { - if (emblemlocations[i].collected) + if (gamedata->collected[i]) found++; } for (i = 0; i < numextraemblems; ++i) { - if (extraemblems[i].collected) + if (gamedata->extraCollected[i]) found++; } return found; @@ -469,12 +467,12 @@ UINT8 M_GotEnoughEmblems(INT32 number) INT32 i, gottenemblems = 0; for (i = 0; i < numemblems; ++i) { - if (emblemlocations[i].collected) + if (gamedata->collected[i]) if (++gottenemblems >= number) return true; } for (i = 0; i < numextraemblems; ++i) { - if (extraemblems[i].collected) + if (gamedata->extraCollected[i]) if (++gottenemblems >= number) return true; } return false; diff --git a/src/m_cond.h b/src/m_cond.h index 7633cf39b..4df268277 100644 --- a/src/m_cond.h +++ b/src/m_cond.h @@ -52,8 +52,6 @@ typedef struct { UINT32 numconditions; /// <- number of conditions. condition_t *condition; /// <- All conditionals to be checked. - UINT8 achieved; /// <- Whether this conditional has been achieved already or not. - /// (Conditional checking is skipped if true -- it's assumed you can't relock an unlockable) } conditionset_t; // Emblem information @@ -79,7 +77,6 @@ typedef struct INT32 var; ///< If needed, specifies information on the target amount to achieve (or target skin) char *stringVar; ///< String version char hint[110]; ///< Hint for emblem hints menu - UINT8 collected; ///< Do you have this emblem? } emblem_t; typedef struct { @@ -89,7 +86,6 @@ typedef struct UINT8 showconditionset; ///< Condition set that shows this emblem. UINT8 sprite; ///< emblem sprite to use, 0 - 25 UINT16 color; ///< skincolor to use - UINT8 collected; ///< Do you have this emblem? } extraemblem_t; // Unlockable information @@ -104,7 +100,6 @@ typedef struct char *stringVar; UINT8 nocecho; UINT8 nochecklist; - UINT8 unlocked; } unlockable_t; #define SECRET_NONE 0 // Does nil. Use with levels locked by UnlockRequired @@ -135,6 +130,35 @@ typedef struct #define MAXEXTRAEMBLEMS 16 #define MAXUNLOCKABLES 32 +// GAMEDATA STRUCTURE +// Everything that would get saved in gamedata.dat +typedef struct +{ + // WHENEVER OR NOT WE'RE READY TO SAVE + boolean loaded; + + // CONDITION SETS ACHIEVED + boolean achieved[MAXCONDITIONSETS]; + + // EMBLEMS COLLECTED + boolean collected[MAXEMBLEMS]; + + // EXTRA EMBLEMS COLLECTED + boolean extraCollected[MAXEXTRAEMBLEMS]; + + // UNLOCKABLES UNLOCKED + boolean unlocked[MAXUNLOCKABLES]; + + // # OF TIMES THE GAME HAS BEEN BEATEN + UINT32 timesBeaten; + + // PLAY TIME + UINT32 totalplaytime; + UINT32 matchesplayed; +} gamedata_t; + +extern gamedata_t *gamedata; + extern conditionset_t conditionSets[MAXCONDITIONSETS]; extern emblem_t emblemlocations[MAXEMBLEMS]; extern extraemblem_t extraemblems[MAXEXTRAEMBLEMS]; @@ -145,6 +169,8 @@ extern INT32 numextraemblems; extern UINT32 unlocktriggers; +void M_NewGameDataStruct(void); + // Condition set setup void M_AddRawCondition(UINT8 set, UINT8 id, conditiontype_t c, INT32 r, INT16 x1, INT16 x2); @@ -155,8 +181,7 @@ void M_ClearSecrets(void); // Updating conditions and unlockables void M_CheckUnlockConditions(void); UINT8 M_CheckCondition(condition_t *cn); -UINT8 M_UpdateUnlockablesAndExtraEmblems(void); -void M_SilentUpdateUnlockablesAndEmblems(void); +boolean M_UpdateUnlockablesAndExtraEmblems(boolean silent); UINT8 M_CheckLevelEmblems(void); UINT8 M_CompletionEmblems(void); @@ -182,4 +207,4 @@ UINT8 M_GotLowEnoughTime(INT32 tictime); INT32 M_UnlockableSkinNum(unlockable_t *unlock); INT32 M_EmblemSkinNum(emblem_t *emblem); -#define M_Achieved(a) ((a) >= MAXCONDITIONSETS || conditionSets[a].achieved) +#define M_Achieved(a) ((a) >= MAXCONDITIONSETS || gamedata->achieved[a]) diff --git a/src/m_random.c b/src/m_random.c index 6d8beeaa3..755f7ca65 100644 --- a/src/m_random.c +++ b/src/m_random.c @@ -14,7 +14,7 @@ #include "doomdef.h" #include "doomtype.h" -#include "doomstat.h" // totalplaytime +#include "m_cond.h" // gamedata->totalplaytime #include "m_random.h" #include "m_fixed.h" @@ -372,5 +372,5 @@ void P_ClearRandom(UINT32 seed) */ UINT32 M_RandomizedSeed(void) { - return ((totalplaytime & 0xFFFF) << 16) | M_RandomFixed(); + return ((gamedata->totalplaytime & 0xFFFF) << 16) | M_RandomFixed(); } diff --git a/src/p_inter.c b/src/p_inter.c index e77a5d8ff..7c65c6315 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -504,8 +504,8 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (demo.playback || special->health > MAXEMBLEMS) return; - emblemlocations[special->health-1].collected = true; - M_UpdateUnlockablesAndExtraEmblems(); + gamedata->collected[special->health-1] = true; + M_UpdateUnlockablesAndExtraEmblems(true); G_SaveGameData(); break; } diff --git a/src/p_mobj.c b/src/p_mobj.c index 0613d816c..4f447ebc9 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11969,7 +11969,7 @@ static boolean P_SetupEmblem(mapthing_t *mthing, mobj_t *mobj) emcolor = M_GetEmblemColor(&emblemlocations[j]); // workaround for compiler complaint about bad function casting mobj->color = (UINT16)emcolor; - if (emblemlocations[j].collected) + if (gamedata->collected[j]) { P_UnsetThingPosition(mobj); mobj->flags |= MF_NOCLIP; diff --git a/src/p_setup.c b/src/p_setup.c index a308e4ff1..9c06e7038 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -7567,7 +7567,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) { mapheaderinfo[gamemap-1]->mapvisited |= MV_VISITED; - if (M_UpdateUnlockablesAndExtraEmblems()) + if (M_UpdateUnlockablesAndExtraEmblems(true)) S_StartSound(NULL, sfx_ncitem); G_SaveGameData(); } diff --git a/src/p_spec.c b/src/p_spec.c index f2b9398bc..06c658ee1 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -1502,7 +1502,7 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller CONS_Debug(DBG_GAMELOGIC, "Unlockable check (sidedef %hu): bad unlockable ID %d\n", triggerline->sidenum[0], unlockid); return false; } - else if (!(unlockables[unlockid].unlocked)) + else if (!(gamedata->unlocked[unlockid])) return false; } break; @@ -2763,7 +2763,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) unlocktriggers |= 1 << trigid; // Unlocked something? - if (M_UpdateUnlockablesAndExtraEmblems()) + if (M_UpdateUnlockablesAndExtraEmblems(true)) { S_StartSound(NULL, sfx_s3k68); G_SaveGameData(); // only save if unlocked something diff --git a/src/p_tick.c b/src/p_tick.c index 7cf1748b5..8312a18a8 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -20,6 +20,7 @@ #include "st_stuff.h" #include "p_polyobj.h" #include "m_random.h" +#include "m_cond.h" // gamedata->playtime #include "lua_script.h" #include "lua_hook.h" #include "m_perfstats.h" @@ -628,7 +629,7 @@ void P_Ticker(boolean run) // Keep track of how long they've been playing! if (!demo.playback) // Don't increment if a demo is playing. - totalplaytime++; + gamedata->totalplaytime++; // formality so kitemcap gets updated properly each frame. P_RunKartItems(); diff --git a/src/r_skins.c b/src/r_skins.c index e4f3a317c..03753d1b5 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -171,7 +171,7 @@ UINT8 *R_GetSkinAvailabilities(boolean demolock) if (unlockables[i].type != SECRET_SKIN) continue; - if (unlockables[i].unlocked != true && !demolock) + if (gamedata->unlocked[i] != true && !demolock) continue; skinid = M_UnlockableSkinNum(&unlockables[i]); @@ -250,7 +250,7 @@ boolean R_SkinUsable(INT32 playernum, INT32 skinnum, boolean demoskins) } // Use the unlockables table directly - return (boolean)(unlockables[i].unlocked); + return (boolean)(gamedata->unlocked[i]); } // returns true if the skin name is found (loaded from pwad)