mirror of
https://git.do.srb2.org/STJr/SRB2.git
synced 2025-03-22 02:42:20 +00:00
Online emblems
Currently, emblems share with everyone. Will add an option to toggle this.
This commit is contained in:
parent
d6d424f102
commit
49fa46d80e
26 changed files with 824 additions and 450 deletions
|
@ -3645,6 +3645,9 @@ void SV_ResetServer(void)
|
|||
|
||||
CV_RevertNetVars();
|
||||
|
||||
// Ensure synched when creating a new server
|
||||
M_CopyGameData(serverGamedata, clientGamedata);
|
||||
|
||||
DEBFILE("\n-=-=-=-=-=-=-= Server Reset =-=-=-=-=-=-=-\n\n");
|
||||
}
|
||||
|
||||
|
|
|
@ -1350,6 +1350,9 @@ void D_SRB2Main(void)
|
|||
CONS_Printf("Z_Init(): Init zone memory allocation daemon. \n");
|
||||
Z_Init();
|
||||
|
||||
clientGamedata = M_NewGameDataStruct();
|
||||
serverGamedata = M_NewGameDataStruct();
|
||||
|
||||
// Do this up here so that WADs loaded through the command line can use ExecCfg
|
||||
COM_Init();
|
||||
|
||||
|
@ -1479,7 +1482,9 @@ void D_SRB2Main(void)
|
|||
// confusion issues when loading mods.
|
||||
strlcpy(gamedatafilename, M_GetNextParm(), sizeof gamedatafilename);
|
||||
}
|
||||
G_LoadGameData();
|
||||
|
||||
G_LoadGameData(clientGamedata);
|
||||
M_CopyGameData(serverGamedata, clientGamedata);
|
||||
|
||||
#if defined (__unix__) || defined (UNIXCOMMON) || defined (HAVE_SDL)
|
||||
VID_PrepareModeList(); // Regenerate Modelist according to cv_fullscreen
|
||||
|
@ -1710,7 +1715,7 @@ void D_SRB2Main(void)
|
|||
// ... unless you're in a dedicated server. Yes, technically this means you can view any level by
|
||||
// running a dedicated server and joining it yourself, but that's better than making dedicated server's
|
||||
// lives hell.
|
||||
else if (!dedicated && M_MapLocked(pstartmap))
|
||||
else if (!dedicated && M_MapLocked(pstartmap, serverGamedata))
|
||||
I_Error("You need to unlock this level before you can warp to it!\n");
|
||||
else
|
||||
{
|
||||
|
|
|
@ -2036,7 +2036,7 @@ static void Command_Map_f(void)
|
|||
// ... unless you're in a dedicated server. Yes, technically this means you can view any level by
|
||||
// running a dedicated server and joining it yourself, but that's better than making dedicated server's
|
||||
// lives hell.
|
||||
if (!dedicated && M_MapLocked(newmapnum))
|
||||
if (!dedicated && M_MapLocked(newmapnum, serverGamedata))
|
||||
{
|
||||
CONS_Alert(CONS_NOTICE, M_GetText("You need to unlock this level before you can warp to it!\n"));
|
||||
Z_Free(realmapname);
|
||||
|
@ -3945,18 +3945,12 @@ void ItemFinder_OnChange(void)
|
|||
if (!cv_itemfinder.value)
|
||||
return; // it's fine.
|
||||
|
||||
if (!M_SecretUnlocked(SECRET_ITEMFINDER))
|
||||
if (!M_SecretUnlocked(SECRET_ITEMFINDER, clientGamedata))
|
||||
{
|
||||
CONS_Printf(M_GetText("You haven't earned this yet.\n"));
|
||||
CV_StealthSetValue(&cv_itemfinder, 0);
|
||||
return;
|
||||
}
|
||||
else if (netgame || multiplayer)
|
||||
{
|
||||
CONS_Printf(M_GetText("This only works in single player.\n"));
|
||||
CV_StealthSetValue(&cv_itemfinder, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/** Deals with a pointlimit change by printing the change to the console.
|
||||
|
@ -4305,7 +4299,7 @@ void D_GameTypeChanged(INT32 lastgametype)
|
|||
|
||||
static void Ringslinger_OnChange(void)
|
||||
{
|
||||
if (!M_SecretUnlocked(SECRET_PANDORA) && !netgame && cv_ringslinger.value && !cv_debug)
|
||||
if (!M_SecretUnlocked(SECRET_PANDORA, serverGamedata) && !netgame && cv_ringslinger.value && !cv_debug)
|
||||
{
|
||||
CONS_Printf(M_GetText("You haven't earned this yet.\n"));
|
||||
CV_StealthSetValue(&cv_ringslinger, 0);
|
||||
|
@ -4318,7 +4312,7 @@ static void Ringslinger_OnChange(void)
|
|||
|
||||
static void Gravity_OnChange(void)
|
||||
{
|
||||
if (!M_SecretUnlocked(SECRET_PANDORA) && !netgame && !cv_debug
|
||||
if (!M_SecretUnlocked(SECRET_PANDORA, serverGamedata) && !netgame && !cv_debug
|
||||
&& strcmp(cv_gravity.string, cv_gravity.defaultvalue))
|
||||
{
|
||||
CONS_Printf(M_GetText("You haven't earned this yet.\n"));
|
||||
|
|
|
@ -3849,7 +3849,7 @@ void readmaincfg(MYFILE *f)
|
|||
if (!GoodDataFileName(word2))
|
||||
I_Error("Maincfg: bad data file name '%s'\n", word2);
|
||||
|
||||
G_SaveGameData();
|
||||
G_SaveGameData(clientGamedata);
|
||||
strlcpy(gamedatafilename, word2, sizeof (gamedatafilename));
|
||||
strlwr(gamedatafilename);
|
||||
savemoddata = true;
|
||||
|
|
|
@ -575,7 +575,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
|
|||
} // end while
|
||||
|
||||
if (gamedataadded)
|
||||
G_LoadGameData();
|
||||
G_LoadGameData(clientGamedata);
|
||||
|
||||
if (gamestate == GS_TITLESCREEN)
|
||||
{
|
||||
|
|
|
@ -132,8 +132,6 @@ extern INT32 postimgparam2;
|
|||
extern INT32 viewwindowx, viewwindowy;
|
||||
extern INT32 viewwidth, scaledviewwidth;
|
||||
|
||||
extern boolean gamedataloaded;
|
||||
|
||||
// Player taking events, and displaying.
|
||||
extern INT32 consoleplayer;
|
||||
extern INT32 displayplayer;
|
||||
|
@ -495,8 +493,6 @@ typedef struct
|
|||
extern tolinfo_t TYPEOFLEVEL[NUMTOLNAMES];
|
||||
extern UINT32 lastcustomtol;
|
||||
|
||||
extern tic_t totalplaytime;
|
||||
|
||||
extern boolean stagefailed;
|
||||
|
||||
// Emeralds stored as bits to throw savegame hackers off.
|
||||
|
@ -515,52 +511,6 @@ extern INT32 luabanks[NUM_LUABANKS];
|
|||
|
||||
extern INT32 nummaprings; //keep track of spawned rings/coins
|
||||
|
||||
/** Time attack information, currently a very small structure.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
tic_t time; ///< Time in which the level was finished.
|
||||
UINT32 score; ///< Score when the level was finished.
|
||||
UINT16 rings; ///< Rings when the level was finished.
|
||||
} recorddata_t;
|
||||
|
||||
/** Setup for one NiGHTS map.
|
||||
* These are dynamically allocated because I am insane
|
||||
*/
|
||||
#define GRADE_F 0
|
||||
#define GRADE_E 1
|
||||
#define GRADE_D 2
|
||||
#define GRADE_C 3
|
||||
#define GRADE_B 4
|
||||
#define GRADE_A 5
|
||||
#define GRADE_S 6
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// 8 mares, 1 overall (0)
|
||||
UINT8 nummares;
|
||||
UINT32 score[9];
|
||||
UINT8 grade[9];
|
||||
tic_t time[9];
|
||||
} nightsdata_t;
|
||||
|
||||
extern nightsdata_t *nightsrecords[NUMMAPS];
|
||||
extern recorddata_t *mainrecords[NUMMAPS];
|
||||
|
||||
// mapvisited is now a set of flags that says what we've done in the map.
|
||||
#define MV_VISITED 1
|
||||
#define MV_BEATEN 2
|
||||
#define MV_ALLEMERALDS 4
|
||||
#define MV_ULTIMATE 8
|
||||
#define MV_PERFECT 16
|
||||
#define MV_PERFECTRA 32
|
||||
#define MV_MAX 63 // used in gamedata check, update whenever MV's are added
|
||||
#define MV_MP 128
|
||||
extern UINT8 mapvisited[NUMMAPS];
|
||||
|
||||
// Temporary holding place for nights data for the current map
|
||||
extern nightsdata_t ntemprecords;
|
||||
|
||||
extern UINT32 token; ///< Number of tokens collected in a level
|
||||
extern UINT32 tokenlist; ///< List of tokens collected
|
||||
extern boolean gottoken; ///< Did you get a token? Used for end of act
|
||||
|
@ -616,10 +566,6 @@ extern INT32 cheats;
|
|||
|
||||
extern tic_t hidetime;
|
||||
|
||||
extern UINT32 timesBeaten; // # of times the game has been beaten.
|
||||
extern UINT32 timesBeatenWithEmeralds;
|
||||
extern UINT32 timesBeatenUltimate;
|
||||
|
||||
// ===========================
|
||||
// Internal parameters, fixed.
|
||||
// ===========================
|
||||
|
|
|
@ -1411,7 +1411,7 @@ boolean F_CreditResponder(event_t *event)
|
|||
break;
|
||||
}
|
||||
|
||||
if (!(timesBeaten) && !(netgame || multiplayer) && !cv_debug)
|
||||
if (!(serverGamedata->timesBeaten) && !(netgame || multiplayer) && !cv_debug)
|
||||
return false;
|
||||
|
||||
if (event->type != ev_keydown)
|
||||
|
@ -1573,23 +1573,17 @@ void F_GameEvaluationDrawer(void)
|
|||
#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)
|
||||
{
|
||||
INT32 startcoord = 32;
|
||||
V_DrawString(8, 16, V_YELLOWMAP, "Unlocked:");
|
||||
|
||||
if (netgame)
|
||||
V_DrawString(8, 96, V_YELLOWMAP, "Multiplayer games\ncan't unlock\nextras!");
|
||||
else
|
||||
for (i = 0; i < MAXUNLOCKABLES; i++)
|
||||
{
|
||||
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].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;
|
||||
}
|
||||
if (clientGamedata->unlocked[i])
|
||||
V_DrawString(8, startcoord, 0, unlockables[i].name);
|
||||
startcoord += 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1657,18 +1651,27 @@ void F_GameEvaluationTicker(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
++timesBeaten;
|
||||
serverGamedata->timesBeaten++;
|
||||
clientGamedata->timesBeaten++;
|
||||
|
||||
if (ALL7EMERALDS(emeralds))
|
||||
++timesBeatenWithEmeralds;
|
||||
{
|
||||
serverGamedata->timesBeatenWithEmeralds++;
|
||||
clientGamedata->timesBeatenWithEmeralds++;
|
||||
}
|
||||
|
||||
if (ultimatemode)
|
||||
++timesBeatenUltimate;
|
||||
{
|
||||
serverGamedata->timesBeatenUltimate++;
|
||||
clientGamedata->timesBeatenUltimate++;
|
||||
}
|
||||
|
||||
if (M_UpdateUnlockablesAndExtraEmblems())
|
||||
M_SilentUpdateUnlockablesAndEmblems(serverGamedata);
|
||||
|
||||
if (M_UpdateUnlockablesAndExtraEmblems(clientGamedata))
|
||||
S_StartSound(NULL, sfx_s3k68);
|
||||
|
||||
G_SaveGameData();
|
||||
G_SaveGameData(clientGamedata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2183,7 +2186,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<<V_ALPHASHIFT), str);
|
||||
V_DrawCharacter(32, BASEVIDHEIGHT-16, '>'|(trans<<V_ALPHASHIFT), false);
|
||||
V_DrawString(40, ((finalecount == STOPPINGPOINT-(20+TICRATE)) ? 1 : 0)+BASEVIDHEIGHT-16, ((timesBeaten || finalecount >= STOPPINGPOINT-TICRATE) ? V_PURPLEMAP : V_BLUEMAP)|(trans<<V_ALPHASHIFT), " [S] ===>");
|
||||
V_DrawString(40, ((finalecount == STOPPINGPOINT-(20+TICRATE)) ? 1 : 0)+BASEVIDHEIGHT-16, ((serverGamedata->timesBeaten || finalecount >= STOPPINGPOINT-TICRATE) ? V_PURPLEMAP : V_BLUEMAP)|(trans<<V_ALPHASHIFT), " [S] ===>");
|
||||
}
|
||||
|
||||
if (finalecount > STOPPINGPOINT-(20+(2*TICRATE)))
|
||||
|
|
251
src/g_game.c
251
src/g_game.c
|
@ -185,18 +185,6 @@ INT32 tokenbits; // Used for setting token bits
|
|||
// Old Special Stage
|
||||
INT32 sstimer; // Time allotted in the special stage
|
||||
|
||||
tic_t totalplaytime;
|
||||
boolean gamedataloaded = false;
|
||||
|
||||
// Time attack data for levels
|
||||
// These are dynamically allocated for space reasons now
|
||||
recorddata_t *mainrecords[NUMMAPS] = {NULL};
|
||||
nightsdata_t *nightsrecords[NUMMAPS] = {NULL};
|
||||
UINT8 mapvisited[NUMMAPS];
|
||||
|
||||
// Temporary holding place for nights data for the current map
|
||||
nightsdata_t ntemprecords;
|
||||
|
||||
UINT32 bluescore, redscore; // CTF and Team Match team scores
|
||||
|
||||
// ring count... for PERFECT!
|
||||
|
@ -252,11 +240,6 @@ INT32 cheats; //for multiplayer cheat commands
|
|||
|
||||
tic_t hidetime;
|
||||
|
||||
// Grading
|
||||
UINT32 timesBeaten;
|
||||
UINT32 timesBeatenWithEmeralds;
|
||||
UINT32 timesBeatenUltimate;
|
||||
|
||||
typedef struct joystickvector2_s
|
||||
{
|
||||
INT32 xaxis;
|
||||
|
@ -452,86 +435,86 @@ INT16 rw_maximums[NUM_WEAPONS] =
|
|||
};
|
||||
|
||||
// Allocation for time and nights data
|
||||
void G_AllocMainRecordData(INT16 i)
|
||||
void G_AllocMainRecordData(INT16 i, gamedata_t *data)
|
||||
{
|
||||
if (!mainrecords[i])
|
||||
mainrecords[i] = Z_Malloc(sizeof(recorddata_t), PU_STATIC, NULL);
|
||||
memset(mainrecords[i], 0, sizeof(recorddata_t));
|
||||
if (!data->mainrecords[i])
|
||||
data->mainrecords[i] = Z_Malloc(sizeof(recorddata_t), PU_STATIC, NULL);
|
||||
memset(data->mainrecords[i], 0, sizeof(recorddata_t));
|
||||
}
|
||||
|
||||
void G_AllocNightsRecordData(INT16 i)
|
||||
void G_AllocNightsRecordData(INT16 i, gamedata_t *data)
|
||||
{
|
||||
if (!nightsrecords[i])
|
||||
nightsrecords[i] = Z_Malloc(sizeof(nightsdata_t), PU_STATIC, NULL);
|
||||
memset(nightsrecords[i], 0, sizeof(nightsdata_t));
|
||||
if (!data->nightsrecords[i])
|
||||
data->nightsrecords[i] = Z_Malloc(sizeof(nightsdata_t), PU_STATIC, NULL);
|
||||
memset(data->nightsrecords[i], 0, sizeof(nightsdata_t));
|
||||
}
|
||||
|
||||
// MAKE SURE YOU SAVE DATA BEFORE CALLING THIS
|
||||
void G_ClearRecords(void)
|
||||
void G_ClearRecords(gamedata_t *data)
|
||||
{
|
||||
INT16 i;
|
||||
for (i = 0; i < NUMMAPS; ++i)
|
||||
{
|
||||
if (mainrecords[i])
|
||||
if (data->mainrecords[i])
|
||||
{
|
||||
Z_Free(mainrecords[i]);
|
||||
mainrecords[i] = NULL;
|
||||
Z_Free(data->mainrecords[i]);
|
||||
data->mainrecords[i] = NULL;
|
||||
}
|
||||
if (nightsrecords[i])
|
||||
if (data->nightsrecords[i])
|
||||
{
|
||||
Z_Free(nightsrecords[i]);
|
||||
nightsrecords[i] = NULL;
|
||||
Z_Free(data->nightsrecords[i]);
|
||||
data->nightsrecords[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For easy retrieval of records
|
||||
UINT32 G_GetBestScore(INT16 map)
|
||||
UINT32 G_GetBestScore(INT16 map, gamedata_t *data)
|
||||
{
|
||||
if (!mainrecords[map-1])
|
||||
if (!data->mainrecords[map-1])
|
||||
return 0;
|
||||
|
||||
return mainrecords[map-1]->score;
|
||||
return data->mainrecords[map-1]->score;
|
||||
}
|
||||
|
||||
tic_t G_GetBestTime(INT16 map)
|
||||
tic_t G_GetBestTime(INT16 map, gamedata_t *data)
|
||||
{
|
||||
if (!mainrecords[map-1] || mainrecords[map-1]->time <= 0)
|
||||
if (!data->mainrecords[map-1] || data->mainrecords[map-1]->time <= 0)
|
||||
return (tic_t)UINT32_MAX;
|
||||
|
||||
return mainrecords[map-1]->time;
|
||||
return data->mainrecords[map-1]->time;
|
||||
}
|
||||
|
||||
UINT16 G_GetBestRings(INT16 map)
|
||||
UINT16 G_GetBestRings(INT16 map, gamedata_t *data)
|
||||
{
|
||||
if (!mainrecords[map-1])
|
||||
if (!data->mainrecords[map-1])
|
||||
return 0;
|
||||
|
||||
return mainrecords[map-1]->rings;
|
||||
return data->mainrecords[map-1]->rings;
|
||||
}
|
||||
|
||||
UINT32 G_GetBestNightsScore(INT16 map, UINT8 mare)
|
||||
UINT32 G_GetBestNightsScore(INT16 map, UINT8 mare, gamedata_t *data)
|
||||
{
|
||||
if (!nightsrecords[map-1])
|
||||
if (!data->nightsrecords[map-1])
|
||||
return 0;
|
||||
|
||||
return nightsrecords[map-1]->score[mare];
|
||||
return data->nightsrecords[map-1]->score[mare];
|
||||
}
|
||||
|
||||
tic_t G_GetBestNightsTime(INT16 map, UINT8 mare)
|
||||
tic_t G_GetBestNightsTime(INT16 map, UINT8 mare, gamedata_t *data)
|
||||
{
|
||||
if (!nightsrecords[map-1] || nightsrecords[map-1]->time[mare] <= 0)
|
||||
if (!data->nightsrecords[map-1] || data->nightsrecords[map-1]->time[mare] <= 0)
|
||||
return (tic_t)UINT32_MAX;
|
||||
|
||||
return nightsrecords[map-1]->time[mare];
|
||||
return data->nightsrecords[map-1]->time[mare];
|
||||
}
|
||||
|
||||
UINT8 G_GetBestNightsGrade(INT16 map, UINT8 mare)
|
||||
UINT8 G_GetBestNightsGrade(INT16 map, UINT8 mare, gamedata_t *data)
|
||||
{
|
||||
if (!nightsrecords[map-1])
|
||||
if (!data->nightsrecords[map-1])
|
||||
return 0;
|
||||
|
||||
return nightsrecords[map-1]->grade[mare];
|
||||
return data->nightsrecords[map-1]->grade[mare];
|
||||
}
|
||||
|
||||
// For easy adding of NiGHTS records
|
||||
|
@ -553,7 +536,7 @@ void G_AddTempNightsRecords(UINT32 pscore, tic_t ptime, UINT8 mare)
|
|||
// Update replay files/data, etc. for Record Attack
|
||||
// See G_SetNightsRecords for NiGHTS Attack.
|
||||
//
|
||||
static void G_UpdateRecordReplays(void)
|
||||
static void G_UpdateRecordReplays(gamedata_t *data)
|
||||
{
|
||||
const size_t glen = strlen(srb2home)+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1;
|
||||
char *gpath;
|
||||
|
@ -561,17 +544,17 @@ static void G_UpdateRecordReplays(void)
|
|||
UINT8 earnedEmblems;
|
||||
|
||||
// Record new best time
|
||||
if (!mainrecords[gamemap-1])
|
||||
G_AllocMainRecordData(gamemap-1);
|
||||
if (!data->mainrecords[gamemap-1])
|
||||
G_AllocMainRecordData(gamemap-1, data);
|
||||
|
||||
if (players[consoleplayer].score > mainrecords[gamemap-1]->score)
|
||||
mainrecords[gamemap-1]->score = players[consoleplayer].score;
|
||||
if (players[consoleplayer].score > data->mainrecords[gamemap-1]->score)
|
||||
data->mainrecords[gamemap-1]->score = players[consoleplayer].score;
|
||||
|
||||
if ((mainrecords[gamemap-1]->time == 0) || (players[consoleplayer].realtime < mainrecords[gamemap-1]->time))
|
||||
mainrecords[gamemap-1]->time = players[consoleplayer].realtime;
|
||||
if ((data->mainrecords[gamemap-1]->time == 0) || (players[consoleplayer].realtime < data->mainrecords[gamemap-1]->time))
|
||||
data->mainrecords[gamemap-1]->time = players[consoleplayer].realtime;
|
||||
|
||||
if ((UINT16)(players[consoleplayer].rings) > mainrecords[gamemap-1]->rings)
|
||||
mainrecords[gamemap-1]->rings = (UINT16)(players[consoleplayer].rings);
|
||||
if ((UINT16)(players[consoleplayer].rings) > data->mainrecords[gamemap-1]->rings)
|
||||
data->mainrecords[gamemap-1]->rings = (UINT16)(players[consoleplayer].rings);
|
||||
|
||||
// Save demo!
|
||||
bestdemo[255] = '\0';
|
||||
|
@ -627,14 +610,14 @@ static void G_UpdateRecordReplays(void)
|
|||
free(gpath);
|
||||
|
||||
// Check emblems when level data is updated
|
||||
if ((earnedEmblems = M_CheckLevelEmblems()))
|
||||
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(void)
|
||||
void G_SetNightsRecords(gamedata_t *data)
|
||||
{
|
||||
INT32 i;
|
||||
UINT32 totalscore = 0;
|
||||
|
@ -675,9 +658,9 @@ void G_SetNightsRecords(void)
|
|||
{
|
||||
nightsdata_t *maprecords;
|
||||
|
||||
if (!nightsrecords[gamemap-1])
|
||||
G_AllocNightsRecordData(gamemap-1);
|
||||
maprecords = nightsrecords[gamemap-1];
|
||||
if (!data->nightsrecords[gamemap-1])
|
||||
G_AllocNightsRecordData(gamemap-1, data);
|
||||
maprecords = data->nightsrecords[gamemap-1];
|
||||
|
||||
if (maprecords->nummares != ntemprecords.nummares)
|
||||
maprecords->nummares = ntemprecords.nummares;
|
||||
|
@ -739,7 +722,7 @@ void G_SetNightsRecords(void)
|
|||
}
|
||||
free(gpath);
|
||||
|
||||
if ((earnedEmblems = M_CheckLevelEmblems()))
|
||||
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
|
||||
|
@ -3838,7 +3821,7 @@ static INT16 RandMap(UINT32 tolflags, INT16 pprevmap)
|
|||
for (ix = 0; ix < NUMMAPS; ix++)
|
||||
if (mapheaderinfo[ix] && (mapheaderinfo[ix]->typeoflevel & tolflags) == tolflags
|
||||
&& ix != pprevmap // Don't pick the same map.
|
||||
&& (dedicated || !M_MapLocked(ix+1)) // Don't pick locked maps.
|
||||
&& (dedicated || !M_MapLocked(ix+1, serverGamedata)) // Don't pick locked maps.
|
||||
)
|
||||
okmaps[numokmaps++] = ix;
|
||||
|
||||
|
@ -3855,7 +3838,7 @@ static INT16 RandMap(UINT32 tolflags, INT16 pprevmap)
|
|||
//
|
||||
// G_UpdateVisited
|
||||
//
|
||||
static void G_UpdateVisited(void)
|
||||
static void G_UpdateVisited(gamedata_t *data, boolean silent)
|
||||
{
|
||||
boolean spec = G_IsSpecialStage(gamemap);
|
||||
// Update visitation flags?
|
||||
|
@ -3865,30 +3848,37 @@ static void G_UpdateVisited(void)
|
|||
UINT8 earnedEmblems;
|
||||
|
||||
// Update visitation flags
|
||||
mapvisited[gamemap-1] |= MV_BEATEN;
|
||||
data->mapvisited[gamemap-1] |= MV_BEATEN;
|
||||
// eh, what the hell
|
||||
if (ultimatemode)
|
||||
mapvisited[gamemap-1] |= MV_ULTIMATE;
|
||||
data->mapvisited[gamemap-1] |= MV_ULTIMATE;
|
||||
// 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)
|
||||
{
|
||||
mapvisited[gamemap-1] |= MV_PERFECT;
|
||||
data->mapvisited[gamemap-1] |= MV_PERFECT;
|
||||
if (modeattacking)
|
||||
mapvisited[gamemap-1] |= MV_PERFECTRA;
|
||||
data->mapvisited[gamemap-1] |= MV_PERFECTRA;
|
||||
}
|
||||
if (!spec)
|
||||
{
|
||||
// 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))
|
||||
mapvisited[gamemap-1] |= MV_ALLEMERALDS;
|
||||
data->mapvisited[gamemap-1] |= MV_ALLEMERALDS;
|
||||
}
|
||||
|
||||
if (modeattacking == ATTACKING_RECORD)
|
||||
G_UpdateRecordReplays();
|
||||
else if (modeattacking == ATTACKING_NIGHTS)
|
||||
G_SetNightsRecords();
|
||||
if (silent)
|
||||
{
|
||||
M_CheckLevelEmblems(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (modeattacking == ATTACKING_RECORD)
|
||||
G_UpdateRecordReplays(data);
|
||||
else if (modeattacking == ATTACKING_NIGHTS)
|
||||
G_SetNightsRecords(data);
|
||||
}
|
||||
|
||||
if ((earnedEmblems = M_CompletionEmblems()))
|
||||
if ((earnedEmblems = M_CompletionEmblems(data)) && !silent)
|
||||
CONS_Printf(M_GetText("\x82" "Earned %hu emblem%s for level completion.\n"), (UINT16)earnedEmblems, earnedEmblems > 1 ? "s" : "");
|
||||
}
|
||||
}
|
||||
|
@ -4091,7 +4081,8 @@ static void G_DoCompleted(void)
|
|||
|
||||
if ((skipstats && !modeattacking) || (modeattacking && stagefailed) || (intertype == int_none))
|
||||
{
|
||||
G_UpdateVisited();
|
||||
G_UpdateVisited(serverGamedata, true);
|
||||
G_UpdateVisited(clientGamedata, false);
|
||||
G_HandleSaveLevel();
|
||||
G_AfterIntermission();
|
||||
}
|
||||
|
@ -4100,7 +4091,8 @@ static void G_DoCompleted(void)
|
|||
G_SetGamestate(GS_INTERMISSION);
|
||||
Y_StartIntermission();
|
||||
Y_LoadIntermissionData();
|
||||
G_UpdateVisited();
|
||||
G_UpdateVisited(serverGamedata, true);
|
||||
G_UpdateVisited(clientGamedata, false);
|
||||
G_HandleSaveLevel();
|
||||
}
|
||||
}
|
||||
|
@ -4287,7 +4279,7 @@ void G_LoadGameSettings(void)
|
|||
|
||||
// G_LoadGameData
|
||||
// Loads the main data file, which stores information such as emblems found, etc.
|
||||
void G_LoadGameData(void)
|
||||
void G_LoadGameData(gamedata_t *data)
|
||||
{
|
||||
size_t length;
|
||||
INT32 i, j;
|
||||
|
@ -4304,13 +4296,13 @@ void G_LoadGameData(void)
|
|||
INT32 curmare;
|
||||
|
||||
// Stop saving, until we successfully load it again.
|
||||
gamedataloaded = false;
|
||||
data->loaded = false;
|
||||
|
||||
// Clear things so previously read gamedata doesn't transfer
|
||||
// to new gamedata
|
||||
G_ClearRecords(); // main and nights records
|
||||
M_ClearSecrets(); // emblems, unlocks, maps visited, etc
|
||||
totalplaytime = 0; // total play time (separate from all)
|
||||
G_ClearRecords(data); // main and nights records
|
||||
M_ClearSecrets(data); // emblems, unlocks, maps visited, etc
|
||||
data->totalplaytime = 0; // total play time (separate from all)
|
||||
|
||||
if (M_CheckParm("-nodata"))
|
||||
{
|
||||
|
@ -4321,7 +4313,7 @@ void G_LoadGameData(void)
|
|||
if (M_CheckParm("-resetdata"))
|
||||
{
|
||||
// Don't load, but do save. (essentially, reset)
|
||||
gamedataloaded = true;
|
||||
data->loaded = true;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -4329,7 +4321,7 @@ void G_LoadGameData(void)
|
|||
if (!length)
|
||||
{
|
||||
// No gamedata. We can save a new one.
|
||||
gamedataloaded = true;
|
||||
data->loaded = true;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -4352,7 +4344,7 @@ void G_LoadGameData(void)
|
|||
I_Error("Game data is from another version of SRB2.\nDelete %s(maybe in %s) and try again.", gamedatafilename, gdfolder);
|
||||
}
|
||||
|
||||
totalplaytime = READUINT32(save_p);
|
||||
data->totalplaytime = READUINT32(save_p);
|
||||
|
||||
#ifdef COMPAT_GAMEDATA_ID
|
||||
if (versionID == COMPAT_GAMEDATA_ID)
|
||||
|
@ -4386,7 +4378,7 @@ void G_LoadGameData(void)
|
|||
|
||||
// TODO put another cipher on these things? meh, I don't care...
|
||||
for (i = 0; i < NUMMAPS; i++)
|
||||
if ((mapvisited[i] = READUINT8(save_p)) > MV_MAX)
|
||||
if ((data->mapvisited[i] = READUINT8(save_p)) > MV_MAX)
|
||||
goto datacorrupt;
|
||||
|
||||
// To save space, use one bit per collected/achieved/unlocked flag
|
||||
|
@ -4394,34 +4386,34 @@ void G_LoadGameData(void)
|
|||
{
|
||||
rtemp = READUINT8(save_p);
|
||||
for (j = 0; j < 8 && j+i < MAXEMBLEMS; ++j)
|
||||
emblemlocations[j+i].collected = ((rtemp >> j) & 1);
|
||||
data->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);
|
||||
data->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);
|
||||
data->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);
|
||||
data->achieved[j+i] = ((rtemp >> j) & 1);
|
||||
i += j;
|
||||
}
|
||||
|
||||
timesBeaten = READUINT32(save_p);
|
||||
timesBeatenWithEmeralds = READUINT32(save_p);
|
||||
timesBeatenUltimate = READUINT32(save_p);
|
||||
data->timesBeaten = READUINT32(save_p);
|
||||
data->timesBeatenWithEmeralds = READUINT32(save_p);
|
||||
data->timesBeatenUltimate = READUINT32(save_p);
|
||||
|
||||
// Main records
|
||||
for (i = 0; i < NUMMAPS; ++i)
|
||||
|
@ -4436,10 +4428,10 @@ void G_LoadGameData(void)
|
|||
|
||||
if (recscore || rectime || recrings)
|
||||
{
|
||||
G_AllocMainRecordData((INT16)i);
|
||||
mainrecords[i]->score = recscore;
|
||||
mainrecords[i]->time = rectime;
|
||||
mainrecords[i]->rings = recrings;
|
||||
G_AllocMainRecordData((INT16)i, data);
|
||||
data->mainrecords[i]->score = recscore;
|
||||
data->mainrecords[i]->time = rectime;
|
||||
data->mainrecords[i]->rings = recrings;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4449,19 +4441,21 @@ void G_LoadGameData(void)
|
|||
if ((recmares = READUINT8(save_p)) == 0)
|
||||
continue;
|
||||
|
||||
G_AllocNightsRecordData((INT16)i);
|
||||
G_AllocNightsRecordData((INT16)i, data);
|
||||
|
||||
for (curmare = 0; curmare < (recmares+1); ++curmare)
|
||||
{
|
||||
nightsrecords[i]->score[curmare] = READUINT32(save_p);
|
||||
nightsrecords[i]->grade[curmare] = READUINT8(save_p);
|
||||
nightsrecords[i]->time[curmare] = (tic_t)READUINT32(save_p);
|
||||
data->nightsrecords[i]->score[curmare] = READUINT32(save_p);
|
||||
data->nightsrecords[i]->grade[curmare] = READUINT8(save_p);
|
||||
data->nightsrecords[i]->time[curmare] = (tic_t)READUINT32(save_p);
|
||||
|
||||
if (nightsrecords[i]->grade[curmare] > GRADE_S)
|
||||
if (data->nightsrecords[i]->grade[curmare] > GRADE_S)
|
||||
{
|
||||
goto datacorrupt;
|
||||
}
|
||||
}
|
||||
|
||||
nightsrecords[i]->nummares = recmares;
|
||||
data->nightsrecords[i]->nummares = recmares;
|
||||
}
|
||||
|
||||
// done
|
||||
|
@ -4472,10 +4466,11 @@ 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;
|
||||
data->loaded = true;
|
||||
|
||||
// Silent update unlockables in case they're out of sync with conditions
|
||||
M_SilentUpdateUnlockablesAndEmblems();
|
||||
M_SilentUpdateUnlockablesAndEmblems(data);
|
||||
M_SilentUpdateSkinAvailabilites();
|
||||
|
||||
return;
|
||||
|
||||
|
@ -4495,7 +4490,7 @@ void G_LoadGameData(void)
|
|||
|
||||
// G_SaveGameData
|
||||
// Saves the main data file, which stores information such as emblems found, etc.
|
||||
void G_SaveGameData(void)
|
||||
void G_SaveGameData(gamedata_t *data)
|
||||
{
|
||||
size_t length;
|
||||
INT32 i, j;
|
||||
|
@ -4503,7 +4498,7 @@ void G_SaveGameData(void)
|
|||
|
||||
INT32 curmare;
|
||||
|
||||
if (!gamedataloaded)
|
||||
if (!data->loaded)
|
||||
return; // If never loaded (-nodata), don't save
|
||||
|
||||
save_p = savebuffer = (UINT8 *)malloc(GAMEDATASIZE);
|
||||
|
@ -4523,20 +4518,20 @@ void G_SaveGameData(void)
|
|||
// Version test
|
||||
WRITEUINT32(save_p, GAMEDATA_ID);
|
||||
|
||||
WRITEUINT32(save_p, totalplaytime);
|
||||
WRITEUINT32(save_p, data->totalplaytime);
|
||||
|
||||
WRITEUINT32(save_p, quickncasehash(timeattackfolder, sizeof timeattackfolder));
|
||||
|
||||
// TODO put another cipher on these things? meh, I don't care...
|
||||
for (i = 0; i < NUMMAPS; i++)
|
||||
WRITEUINT8(save_p, (mapvisited[i] & MV_MAX));
|
||||
WRITEUINT8(save_p, (data->mapvisited[i] & MV_MAX));
|
||||
|
||||
// To save space, use one bit per collected/achieved/unlocked flag
|
||||
for (i = 0; i < MAXEMBLEMS;)
|
||||
{
|
||||
btemp = 0;
|
||||
for (j = 0; j < 8 && j+i < MAXEMBLEMS; ++j)
|
||||
btemp |= (emblemlocations[j+i].collected << j);
|
||||
btemp |= (data->collected[j+i] << j);
|
||||
WRITEUINT8(save_p, btemp);
|
||||
i += j;
|
||||
}
|
||||
|
@ -4544,7 +4539,7 @@ void G_SaveGameData(void)
|
|||
{
|
||||
btemp = 0;
|
||||
for (j = 0; j < 8 && j+i < MAXEXTRAEMBLEMS; ++j)
|
||||
btemp |= (extraemblems[j+i].collected << j);
|
||||
btemp |= (data->extraCollected[j+i] << j);
|
||||
WRITEUINT8(save_p, btemp);
|
||||
i += j;
|
||||
}
|
||||
|
@ -4552,7 +4547,7 @@ void G_SaveGameData(void)
|
|||
{
|
||||
btemp = 0;
|
||||
for (j = 0; j < 8 && j+i < MAXUNLOCKABLES; ++j)
|
||||
btemp |= (unlockables[j+i].unlocked << j);
|
||||
btemp |= (data->unlocked[j+i] << j);
|
||||
WRITEUINT8(save_p, btemp);
|
||||
i += j;
|
||||
}
|
||||
|
@ -4560,23 +4555,23 @@ void G_SaveGameData(void)
|
|||
{
|
||||
btemp = 0;
|
||||
for (j = 0; j < 8 && j+i < MAXCONDITIONSETS; ++j)
|
||||
btemp |= (conditionSets[j+i].achieved << j);
|
||||
btemp |= (data->achieved[j+i] << j);
|
||||
WRITEUINT8(save_p, btemp);
|
||||
i += j;
|
||||
}
|
||||
|
||||
WRITEUINT32(save_p, timesBeaten);
|
||||
WRITEUINT32(save_p, timesBeatenWithEmeralds);
|
||||
WRITEUINT32(save_p, timesBeatenUltimate);
|
||||
WRITEUINT32(save_p, data->timesBeaten);
|
||||
WRITEUINT32(save_p, data->timesBeatenWithEmeralds);
|
||||
WRITEUINT32(save_p, data->timesBeatenUltimate);
|
||||
|
||||
// Main records
|
||||
for (i = 0; i < NUMMAPS; i++)
|
||||
{
|
||||
if (mainrecords[i])
|
||||
if (data->mainrecords[i])
|
||||
{
|
||||
WRITEUINT32(save_p, mainrecords[i]->score);
|
||||
WRITEUINT32(save_p, mainrecords[i]->time);
|
||||
WRITEUINT16(save_p, mainrecords[i]->rings);
|
||||
WRITEUINT32(save_p, data->mainrecords[i]->score);
|
||||
WRITEUINT32(save_p, data->mainrecords[i]->time);
|
||||
WRITEUINT16(save_p, data->mainrecords[i]->rings);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -4590,19 +4585,19 @@ void G_SaveGameData(void)
|
|||
// NiGHTS records
|
||||
for (i = 0; i < NUMMAPS; i++)
|
||||
{
|
||||
if (!nightsrecords[i] || !nightsrecords[i]->nummares)
|
||||
if (!data->nightsrecords[i] || !data->nightsrecords[i]->nummares)
|
||||
{
|
||||
WRITEUINT8(save_p, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
WRITEUINT8(save_p, nightsrecords[i]->nummares);
|
||||
WRITEUINT8(save_p, data->nightsrecords[i]->nummares);
|
||||
|
||||
for (curmare = 0; curmare < (nightsrecords[i]->nummares + 1); ++curmare)
|
||||
for (curmare = 0; curmare < (data->nightsrecords[i]->nummares + 1); ++curmare)
|
||||
{
|
||||
WRITEUINT32(save_p, nightsrecords[i]->score[curmare]);
|
||||
WRITEUINT8(save_p, nightsrecords[i]->grade[curmare]);
|
||||
WRITEUINT32(save_p, nightsrecords[i]->time[curmare]);
|
||||
WRITEUINT32(save_p, data->nightsrecords[i]->score[curmare]);
|
||||
WRITEUINT8(save_p, data->nightsrecords[i]->grade[curmare]);
|
||||
WRITEUINT32(save_p, data->nightsrecords[i]->time[curmare]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
25
src/g_game.h
25
src/g_game.h
|
@ -19,6 +19,7 @@
|
|||
#include "d_event.h"
|
||||
#include "g_demo.h"
|
||||
#include "m_cheat.h" // objectplacing
|
||||
#include "m_cond.h"
|
||||
|
||||
extern char gamedatafilename[64];
|
||||
extern char timeattackfolder[64];
|
||||
|
@ -183,7 +184,7 @@ boolean G_IsTitleCardAvailable(void);
|
|||
// Can be called by the startup code or M_Responder, calls P_SetupLevel.
|
||||
void G_LoadGame(UINT32 slot, INT16 mapoverride);
|
||||
|
||||
void G_SaveGameData(void);
|
||||
void G_SaveGameData(gamedata_t *data);
|
||||
|
||||
void G_SaveGame(UINT32 slot, INT16 mapnum);
|
||||
|
||||
|
@ -239,7 +240,7 @@ void G_SetModeAttackRetryFlag(void);
|
|||
void G_ClearModeAttackRetryFlag(void);
|
||||
boolean G_GetModeAttackRetryFlag(void);
|
||||
|
||||
void G_LoadGameData(void);
|
||||
void G_LoadGameData(gamedata_t *data);
|
||||
void G_LoadGameSettings(void);
|
||||
|
||||
void G_SetGameModified(boolean silent);
|
||||
|
@ -248,19 +249,19 @@ void G_SetUsedCheats(boolean silent);
|
|||
void G_SetGamestate(gamestate_t newstate);
|
||||
|
||||
// Gamedata record shit
|
||||
void G_AllocMainRecordData(INT16 i);
|
||||
void G_AllocNightsRecordData(INT16 i);
|
||||
void G_ClearRecords(void);
|
||||
void G_AllocMainRecordData(INT16 i, gamedata_t *data);
|
||||
void G_AllocNightsRecordData(INT16 i, gamedata_t *data);
|
||||
void G_ClearRecords(gamedata_t *data);
|
||||
|
||||
UINT32 G_GetBestScore(INT16 map);
|
||||
tic_t G_GetBestTime(INT16 map);
|
||||
UINT16 G_GetBestRings(INT16 map);
|
||||
UINT32 G_GetBestNightsScore(INT16 map, UINT8 mare);
|
||||
tic_t G_GetBestNightsTime(INT16 map, UINT8 mare);
|
||||
UINT8 G_GetBestNightsGrade(INT16 map, UINT8 mare);
|
||||
UINT32 G_GetBestScore(INT16 map, gamedata_t *data);
|
||||
tic_t G_GetBestTime(INT16 map, gamedata_t *data);
|
||||
UINT16 G_GetBestRings(INT16 map, gamedata_t *data);
|
||||
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(void);
|
||||
void G_SetNightsRecords(gamedata_t *data);
|
||||
|
||||
FUNCMATH INT32 G_TicsToHours(tic_t tics);
|
||||
FUNCMATH INT32 G_TicsToMinutes(tic_t tics, boolean full);
|
||||
|
|
|
@ -2996,7 +2996,7 @@ static void HU_DrawCoopOverlay(void)
|
|||
|
||||
if (LUA_HudEnabled(hud_tabemblems))
|
||||
{
|
||||
V_DrawString(160, 144, 0, va("- %d/%d", M_CountEmblems(), numemblems+numextraemblems));
|
||||
V_DrawString(160, 144, 0, va("- %d/%d", M_CountEmblems(clientGamedata), numemblems+numextraemblems));
|
||||
V_DrawScaledPatch(128, 144 - emblemicon->height/4, 0, emblemicon);
|
||||
}
|
||||
|
||||
|
|
|
@ -102,7 +102,7 @@ static UINT8 cheatf_devmode(void)
|
|||
// Just unlock all the things and turn on -debug and console devmode.
|
||||
G_SetUsedCheats(false);
|
||||
for (i = 0; i < MAXUNLOCKABLES; i++)
|
||||
unlockables[i].unlocked = true;
|
||||
clientGamedata->unlocked[i] = true;
|
||||
devparm = true;
|
||||
cv_debug |= 0x8000;
|
||||
|
||||
|
@ -238,7 +238,7 @@ boolean cht_Responder(event_t *ev)
|
|||
}
|
||||
|
||||
// Console cheat commands rely on these a lot...
|
||||
#define REQUIRE_PANDORA if (!M_SecretUnlocked(SECRET_PANDORA) && !cv_debug)\
|
||||
#define REQUIRE_PANDORA if (!M_SecretUnlocked(SECRET_PANDORA, serverGamedata) && !cv_debug)\
|
||||
{ CONS_Printf(M_GetText("You haven't earned this yet.\n")); return; }
|
||||
|
||||
#define REQUIRE_DEVMODE if (!cv_debug)\
|
||||
|
|
248
src/m_cond.c
248
src/m_cond.c
|
@ -21,6 +21,9 @@
|
|||
#include "r_skins.h" // numskins
|
||||
#include "r_draw.h" // R_GetColorByName
|
||||
|
||||
gamedata_t *clientGamedata; // Our gamedata
|
||||
gamedata_t *serverGamedata; // Server's gamedata
|
||||
|
||||
// Map triggers for linedef executors
|
||||
// 32 triggers, one bit each
|
||||
UINT32 unlocktriggers;
|
||||
|
@ -41,6 +44,70 @@ unlockable_t unlockables[MAXUNLOCKABLES];
|
|||
INT32 numemblems = 0;
|
||||
INT32 numextraemblems = 0;
|
||||
|
||||
// Temporary holding place for nights data for the current map
|
||||
nightsdata_t ntemprecords;
|
||||
|
||||
// Create a new gamedata_t, for start-up
|
||||
gamedata_t *M_NewGameDataStruct(void)
|
||||
{
|
||||
gamedata_t *data = Z_Calloc(sizeof (*data), PU_STATIC, NULL);
|
||||
M_ClearSecrets(data);
|
||||
G_ClearRecords(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
void M_CopyGameData(gamedata_t *dest, gamedata_t *src)
|
||||
{
|
||||
INT32 i, j;
|
||||
|
||||
M_ClearSecrets(dest);
|
||||
G_ClearRecords(dest);
|
||||
|
||||
dest->loaded = src->loaded;
|
||||
dest->totalplaytime = src->totalplaytime;
|
||||
|
||||
dest->timesBeaten = src->timesBeaten;
|
||||
dest->timesBeatenWithEmeralds = src->timesBeatenWithEmeralds;
|
||||
dest->timesBeatenUltimate = src->timesBeatenUltimate;
|
||||
|
||||
memcpy(dest->achieved, src->achieved, sizeof(dest->achieved));
|
||||
memcpy(dest->collected, src->collected, sizeof(dest->collected));
|
||||
memcpy(dest->extraCollected, src->extraCollected, sizeof(dest->extraCollected));
|
||||
memcpy(dest->unlocked, src->unlocked, sizeof(dest->unlocked));
|
||||
|
||||
memcpy(dest->mapvisited, src->mapvisited, sizeof(dest->mapvisited));
|
||||
|
||||
// Main records
|
||||
for (i = 0; i < NUMMAPS; ++i)
|
||||
{
|
||||
if (!src->mainrecords[i])
|
||||
continue;
|
||||
|
||||
G_AllocMainRecordData((INT16)i, dest);
|
||||
dest->mainrecords[i]->score = src->mainrecords[i]->score;
|
||||
dest->mainrecords[i]->time = src->mainrecords[i]->time;
|
||||
dest->mainrecords[i]->rings = src->mainrecords[i]->rings;
|
||||
}
|
||||
|
||||
// Nights records
|
||||
for (i = 0; i < NUMMAPS; ++i)
|
||||
{
|
||||
if (!src->nightsrecords[i] || !src->nightsrecords[i]->nummares)
|
||||
continue;
|
||||
|
||||
G_AllocNightsRecordData((INT16)i, dest);
|
||||
|
||||
for (j = 0; j < (src->nightsrecords[i]->nummares + 1); j++)
|
||||
{
|
||||
dest->nightsrecords[i]->score[j] = src->nightsrecords[i]->score[j];
|
||||
dest->nightsrecords[i]->grade[j] = src->nightsrecords[i]->grade[j];
|
||||
dest->nightsrecords[i]->time[j] = src->nightsrecords[i]->time[j];
|
||||
}
|
||||
|
||||
dest->nightsrecords[i]->nummares = src->nightsrecords[i]->nummares;
|
||||
}
|
||||
}
|
||||
|
||||
void M_AddRawCondition(UINT8 set, UINT8 id, conditiontype_t c, INT32 r, INT16 x1, INT16 x2)
|
||||
{
|
||||
condition_t *cond;
|
||||
|
@ -70,89 +137,90 @@ void M_ClearConditionSet(UINT8 set)
|
|||
conditionSets[set - 1].condition = NULL;
|
||||
conditionSets[set - 1].numconditions = 0;
|
||||
}
|
||||
conditionSets[set - 1].achieved = false;
|
||||
clientGamedata->achieved[set - 1] = serverGamedata->achieved[set - 1] = false;
|
||||
}
|
||||
|
||||
// Clear ALL secrets.
|
||||
void M_ClearSecrets(void)
|
||||
void M_ClearSecrets(gamedata_t *data)
|
||||
{
|
||||
INT32 i;
|
||||
|
||||
memset(mapvisited, 0, sizeof(mapvisited));
|
||||
memset(data->mapvisited, 0, sizeof(data->mapvisited));
|
||||
|
||||
for (i = 0; i < MAXEMBLEMS; ++i)
|
||||
emblemlocations[i].collected = false;
|
||||
data->collected[i] = false;
|
||||
for (i = 0; i < MAXEXTRAEMBLEMS; ++i)
|
||||
extraemblems[i].collected = false;
|
||||
data->extraCollected[i] = false;
|
||||
for (i = 0; i < MAXUNLOCKABLES; ++i)
|
||||
unlockables[i].unlocked = false;
|
||||
data->unlocked[i] = false;
|
||||
for (i = 0; i < MAXCONDITIONSETS; ++i)
|
||||
conditionSets[i].achieved = false;
|
||||
data->achieved[i] = false;
|
||||
|
||||
timesBeaten = timesBeatenWithEmeralds = timesBeatenUltimate = 0;
|
||||
data->timesBeaten = data->timesBeatenWithEmeralds = data->timesBeatenUltimate = 0;
|
||||
|
||||
// Re-unlock any always unlocked things
|
||||
M_SilentUpdateUnlockablesAndEmblems();
|
||||
M_SilentUpdateUnlockablesAndEmblems(data);
|
||||
M_SilentUpdateSkinAvailabilites();
|
||||
}
|
||||
|
||||
// ----------------------
|
||||
// Condition set checking
|
||||
// ----------------------
|
||||
static UINT8 M_CheckCondition(condition_t *cn)
|
||||
static UINT8 M_CheckCondition(condition_t *cn, gamedata_t *data)
|
||||
{
|
||||
switch (cn->type)
|
||||
{
|
||||
case UC_PLAYTIME: // Requires total playing time >= x
|
||||
return (totalplaytime >= (unsigned)cn->requirement);
|
||||
return (data->totalplaytime >= (unsigned)cn->requirement);
|
||||
case UC_GAMECLEAR: // Requires game beaten >= x times
|
||||
return (timesBeaten >= (unsigned)cn->requirement);
|
||||
return (data->timesBeaten >= (unsigned)cn->requirement);
|
||||
case UC_ALLEMERALDS: // Requires game beaten with all 7 emeralds >= x times
|
||||
return (timesBeatenWithEmeralds >= (unsigned)cn->requirement);
|
||||
return (data->timesBeatenWithEmeralds >= (unsigned)cn->requirement);
|
||||
case UC_ULTIMATECLEAR: // Requires game beaten on ultimate >= x times (in other words, never)
|
||||
return (timesBeatenUltimate >= (unsigned)cn->requirement);
|
||||
return (data->timesBeatenUltimate >= (unsigned)cn->requirement);
|
||||
case UC_OVERALLSCORE: // Requires overall score >= x
|
||||
return (M_GotHighEnoughScore(cn->requirement));
|
||||
return (M_GotHighEnoughScore(cn->requirement, data));
|
||||
case UC_OVERALLTIME: // Requires overall time <= x
|
||||
return (M_GotLowEnoughTime(cn->requirement));
|
||||
return (M_GotLowEnoughTime(cn->requirement, data));
|
||||
case UC_OVERALLRINGS: // Requires overall rings >= x
|
||||
return (M_GotHighEnoughRings(cn->requirement));
|
||||
return (M_GotHighEnoughRings(cn->requirement, data));
|
||||
case UC_MAPVISITED: // Requires map x to be visited
|
||||
return ((mapvisited[cn->requirement - 1] & MV_VISITED) == MV_VISITED);
|
||||
return ((data->mapvisited[cn->requirement - 1] & MV_VISITED) == MV_VISITED);
|
||||
case UC_MAPBEATEN: // Requires map x to be beaten
|
||||
return ((mapvisited[cn->requirement - 1] & MV_BEATEN) == MV_BEATEN);
|
||||
return ((data->mapvisited[cn->requirement - 1] & MV_BEATEN) == MV_BEATEN);
|
||||
case UC_MAPALLEMERALDS: // Requires map x to be beaten with all emeralds in possession
|
||||
return ((mapvisited[cn->requirement - 1] & MV_ALLEMERALDS) == MV_ALLEMERALDS);
|
||||
return ((data->mapvisited[cn->requirement - 1] & MV_ALLEMERALDS) == MV_ALLEMERALDS);
|
||||
case UC_MAPULTIMATE: // Requires map x to be beaten on ultimate
|
||||
return ((mapvisited[cn->requirement - 1] & MV_ULTIMATE) == MV_ULTIMATE);
|
||||
return ((data->mapvisited[cn->requirement - 1] & MV_ULTIMATE) == MV_ULTIMATE);
|
||||
case UC_MAPPERFECT: // Requires map x to be beaten with a perfect bonus
|
||||
return ((mapvisited[cn->requirement - 1] & MV_PERFECT) == MV_PERFECT);
|
||||
return ((data->mapvisited[cn->requirement - 1] & MV_PERFECT) == MV_PERFECT);
|
||||
case UC_MAPSCORE: // Requires score on map >= x
|
||||
return (G_GetBestScore(cn->extrainfo1) >= (unsigned)cn->requirement);
|
||||
return (G_GetBestScore(cn->extrainfo1, data) >= (unsigned)cn->requirement);
|
||||
case UC_MAPTIME: // Requires time on map <= x
|
||||
return (G_GetBestTime(cn->extrainfo1) <= (unsigned)cn->requirement);
|
||||
return (G_GetBestTime(cn->extrainfo1, data) <= (unsigned)cn->requirement);
|
||||
case UC_MAPRINGS: // Requires rings on map >= x
|
||||
return (G_GetBestRings(cn->extrainfo1) >= cn->requirement);
|
||||
return (G_GetBestRings(cn->extrainfo1, data) >= cn->requirement);
|
||||
case UC_NIGHTSSCORE:
|
||||
return (G_GetBestNightsScore(cn->extrainfo1, (UINT8)cn->extrainfo2) >= (unsigned)cn->requirement);
|
||||
return (G_GetBestNightsScore(cn->extrainfo1, (UINT8)cn->extrainfo2, data) >= (unsigned)cn->requirement);
|
||||
case UC_NIGHTSTIME:
|
||||
return (G_GetBestNightsTime(cn->extrainfo1, (UINT8)cn->extrainfo2) <= (unsigned)cn->requirement);
|
||||
return (G_GetBestNightsTime(cn->extrainfo1, (UINT8)cn->extrainfo2, data) <= (unsigned)cn->requirement);
|
||||
case UC_NIGHTSGRADE:
|
||||
return (G_GetBestNightsGrade(cn->extrainfo1, (UINT8)cn->extrainfo2) >= cn->requirement);
|
||||
return (G_GetBestNightsGrade(cn->extrainfo1, (UINT8)cn->extrainfo2, data) >= cn->requirement);
|
||||
case UC_TRIGGER: // requires map trigger set
|
||||
return !!(unlocktriggers & (1 << cn->requirement));
|
||||
case UC_TOTALEMBLEMS: // Requires number of emblems >= x
|
||||
return (M_GotEnoughEmblems(cn->requirement));
|
||||
return (M_GotEnoughEmblems(cn->requirement, data));
|
||||
case UC_EMBLEM: // Requires emblem x to be obtained
|
||||
return emblemlocations[cn->requirement-1].collected;
|
||||
return data->collected[cn->requirement-1];
|
||||
case UC_EXTRAEMBLEM: // Requires extra emblem x to be obtained
|
||||
return extraemblems[cn->requirement-1].collected;
|
||||
return data->extraCollected[cn->requirement-1];
|
||||
case UC_CONDITIONSET: // requires condition set x to already be achieved
|
||||
return M_Achieved(cn->requirement-1);
|
||||
return M_Achieved(cn->requirement-1, data);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static UINT8 M_CheckConditionSet(conditionset_t *c)
|
||||
static UINT8 M_CheckConditionSet(conditionset_t *c, gamedata_t *data)
|
||||
{
|
||||
UINT32 i;
|
||||
UINT32 lastID = 0;
|
||||
|
@ -173,13 +241,13 @@ static UINT8 M_CheckConditionSet(conditionset_t *c)
|
|||
continue;
|
||||
|
||||
lastID = cn->id;
|
||||
achievedSoFar = M_CheckCondition(cn);
|
||||
achievedSoFar = M_CheckCondition(cn, data);
|
||||
}
|
||||
|
||||
return achievedSoFar;
|
||||
}
|
||||
|
||||
void M_CheckUnlockConditions(void)
|
||||
void M_CheckUnlockConditions(gamedata_t *data)
|
||||
{
|
||||
INT32 i;
|
||||
conditionset_t *c;
|
||||
|
@ -187,27 +255,27 @@ void M_CheckUnlockConditions(void)
|
|||
for (i = 0; i < MAXCONDITIONSETS; ++i)
|
||||
{
|
||||
c = &conditionSets[i];
|
||||
if (!c->numconditions || c->achieved)
|
||||
if (!c->numconditions || data->achieved[i])
|
||||
continue;
|
||||
|
||||
c->achieved = (M_CheckConditionSet(c));
|
||||
data->achieved[i] = (M_CheckConditionSet(c, data));
|
||||
}
|
||||
}
|
||||
|
||||
UINT8 M_UpdateUnlockablesAndExtraEmblems(void)
|
||||
UINT8 M_UpdateUnlockablesAndExtraEmblems(gamedata_t *data)
|
||||
{
|
||||
INT32 i;
|
||||
char cechoText[992] = "";
|
||||
UINT8 cechoLines = 0;
|
||||
|
||||
M_CheckUnlockConditions();
|
||||
M_CheckUnlockConditions(data);
|
||||
|
||||
// Go through extra emblems
|
||||
for (i = 0; i < numextraemblems; ++i)
|
||||
{
|
||||
if (extraemblems[i].collected || !extraemblems[i].conditionset)
|
||||
if (data->extraCollected[i] || !extraemblems[i].conditionset)
|
||||
continue;
|
||||
if ((extraemblems[i].collected = M_Achieved(extraemblems[i].conditionset - 1)) != false)
|
||||
if ((data->extraCollected[i] = M_Achieved(extraemblems[i].conditionset - 1, data)) != false)
|
||||
{
|
||||
strcat(cechoText, va(M_GetText("Got \"%s\" emblem!\\"), extraemblems[i].name));
|
||||
++cechoLines;
|
||||
|
@ -217,14 +285,14 @@ UINT8 M_UpdateUnlockablesAndExtraEmblems(void)
|
|||
// Fun part: if any of those unlocked we need to go through the
|
||||
// unlock conditions AGAIN just in case an emblem reward was reached
|
||||
if (cechoLines)
|
||||
M_CheckUnlockConditions();
|
||||
M_CheckUnlockConditions(data);
|
||||
|
||||
// Go through unlockables
|
||||
for (i = 0; i < MAXUNLOCKABLES; ++i)
|
||||
{
|
||||
if (unlockables[i].unlocked || !unlockables[i].conditionset)
|
||||
if (data->unlocked[i] || !unlockables[i].conditionset)
|
||||
continue;
|
||||
if ((unlockables[i].unlocked = M_Achieved(unlockables[i].conditionset - 1)) != false)
|
||||
if ((data->unlocked[i] = M_Achieved(unlockables[i].conditionset - 1, data)) != false)
|
||||
{
|
||||
if (unlockables[i].nocecho)
|
||||
continue;
|
||||
|
@ -248,45 +316,49 @@ UINT8 M_UpdateUnlockablesAndExtraEmblems(void)
|
|||
HU_DoCEcho(slashed);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Used when loading gamedata to make sure all unlocks are synched with conditions
|
||||
void M_SilentUpdateUnlockablesAndEmblems(void)
|
||||
void M_SilentUpdateUnlockablesAndEmblems(gamedata_t *data)
|
||||
{
|
||||
INT32 i;
|
||||
boolean checkAgain = false;
|
||||
|
||||
// Just in case they aren't to sync
|
||||
M_CheckUnlockConditions();
|
||||
M_CheckLevelEmblems();
|
||||
M_CheckUnlockConditions(data);
|
||||
M_CheckLevelEmblems(data);
|
||||
|
||||
// Go through extra emblems
|
||||
for (i = 0; i < numextraemblems; ++i)
|
||||
{
|
||||
if (extraemblems[i].collected || !extraemblems[i].conditionset)
|
||||
if (data->extraCollected[i] || !extraemblems[i].conditionset)
|
||||
continue;
|
||||
if ((extraemblems[i].collected = M_Achieved(extraemblems[i].conditionset - 1)) != false)
|
||||
if ((data->extraCollected[i] = M_Achieved(extraemblems[i].conditionset - 1, data)) != false)
|
||||
checkAgain = true;
|
||||
}
|
||||
|
||||
// check again if extra emblems unlocked, blah blah, etc
|
||||
if (checkAgain)
|
||||
M_CheckUnlockConditions();
|
||||
M_CheckUnlockConditions(data);
|
||||
|
||||
// Go through unlockables
|
||||
for (i = 0; i < MAXUNLOCKABLES; ++i)
|
||||
{
|
||||
if (unlockables[i].unlocked || !unlockables[i].conditionset)
|
||||
if (data->unlocked[i] || !unlockables[i].conditionset)
|
||||
continue;
|
||||
unlockables[i].unlocked = M_Achieved(unlockables[i].conditionset - 1);
|
||||
data->unlocked[i] = M_Achieved(unlockables[i].conditionset - 1, data);
|
||||
}
|
||||
}
|
||||
|
||||
void M_SilentUpdateSkinAvailabilites(void)
|
||||
{
|
||||
players[consoleplayer].availabilities = players[1].availabilities = R_GetSkinAvailabilities(); // players[1] is supposed to be for 2p
|
||||
}
|
||||
|
||||
// Emblem unlocking shit
|
||||
UINT8 M_CheckLevelEmblems(void)
|
||||
UINT8 M_CheckLevelEmblems(gamedata_t *data)
|
||||
{
|
||||
INT32 i;
|
||||
INT32 valToReach;
|
||||
|
@ -297,7 +369,7 @@ UINT8 M_CheckLevelEmblems(void)
|
|||
// Update Score, Time, Rings emblems
|
||||
for (i = 0; i < numemblems; ++i)
|
||||
{
|
||||
if (emblemlocations[i].type <= ET_SKIN || emblemlocations[i].type == ET_MAP || emblemlocations[i].collected)
|
||||
if (emblemlocations[i].type <= ET_SKIN || emblemlocations[i].type == ET_MAP || data->collected[i])
|
||||
continue;
|
||||
|
||||
levelnum = emblemlocations[i].level;
|
||||
|
@ -306,32 +378,32 @@ UINT8 M_CheckLevelEmblems(void)
|
|||
switch (emblemlocations[i].type)
|
||||
{
|
||||
case ET_SCORE: // Requires score on map >= x
|
||||
res = (G_GetBestScore(levelnum) >= (unsigned)valToReach);
|
||||
res = (G_GetBestScore(levelnum, data) >= (unsigned)valToReach);
|
||||
break;
|
||||
case ET_TIME: // Requires time on map <= x
|
||||
res = (G_GetBestTime(levelnum) <= (unsigned)valToReach);
|
||||
res = (G_GetBestTime(levelnum, data) <= (unsigned)valToReach);
|
||||
break;
|
||||
case ET_RINGS: // Requires rings on map >= x
|
||||
res = (G_GetBestRings(levelnum) >= valToReach);
|
||||
res = (G_GetBestRings(levelnum, data) >= valToReach);
|
||||
break;
|
||||
case ET_NGRADE: // Requires NiGHTS grade on map >= x
|
||||
res = (G_GetBestNightsGrade(levelnum, 0) >= valToReach);
|
||||
res = (G_GetBestNightsGrade(levelnum, 0, data) >= valToReach);
|
||||
break;
|
||||
case ET_NTIME: // Requires NiGHTS time on map <= x
|
||||
res = (G_GetBestNightsTime(levelnum, 0) <= (unsigned)valToReach);
|
||||
res = (G_GetBestNightsTime(levelnum, 0, data) <= (unsigned)valToReach);
|
||||
break;
|
||||
default: // unreachable but shuts the compiler up.
|
||||
continue;
|
||||
}
|
||||
|
||||
emblemlocations[i].collected = res;
|
||||
data->collected[i] = res;
|
||||
if (res)
|
||||
++somethingUnlocked;
|
||||
}
|
||||
return somethingUnlocked;
|
||||
}
|
||||
|
||||
UINT8 M_CompletionEmblems(void) // Bah! Duplication sucks, but it's for a separate print when awarding emblems and it's sorta different enough.
|
||||
UINT8 M_CompletionEmblems(gamedata_t *data) // Bah! Duplication sucks, but it's for a separate print when awarding emblems and it's sorta different enough.
|
||||
{
|
||||
INT32 i;
|
||||
INT32 embtype;
|
||||
|
@ -342,7 +414,7 @@ UINT8 M_CompletionEmblems(void) // Bah! Duplication sucks, but it's for a separa
|
|||
|
||||
for (i = 0; i < numemblems; ++i)
|
||||
{
|
||||
if (emblemlocations[i].type != ET_MAP || emblemlocations[i].collected)
|
||||
if (emblemlocations[i].type != ET_MAP || data->collected[i])
|
||||
continue;
|
||||
|
||||
levelnum = emblemlocations[i].level;
|
||||
|
@ -358,9 +430,9 @@ UINT8 M_CompletionEmblems(void) // Bah! Duplication sucks, but it's for a separa
|
|||
if (embtype & ME_PERFECT)
|
||||
flags |= MV_PERFECT;
|
||||
|
||||
res = ((mapvisited[levelnum - 1] & flags) == flags);
|
||||
res = ((data->mapvisited[levelnum - 1] & flags) == flags);
|
||||
|
||||
emblemlocations[i].collected = res;
|
||||
data->collected[i] = res;
|
||||
if (res)
|
||||
++somethingUnlocked;
|
||||
}
|
||||
|
@ -370,48 +442,54 @@ UINT8 M_CompletionEmblems(void) // Bah! Duplication sucks, but it's for a separa
|
|||
// -------------------
|
||||
// Quick unlock checks
|
||||
// -------------------
|
||||
UINT8 M_AnySecretUnlocked(void)
|
||||
UINT8 M_AnySecretUnlocked(gamedata_t *data)
|
||||
{
|
||||
INT32 i;
|
||||
for (i = 0; i < MAXUNLOCKABLES; ++i)
|
||||
{
|
||||
if (!unlockables[i].nocecho && unlockables[i].unlocked)
|
||||
if (!unlockables[i].nocecho && data->unlocked[i])
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
UINT8 M_SecretUnlocked(INT32 type)
|
||||
UINT8 M_SecretUnlocked(INT32 type, gamedata_t *data)
|
||||
{
|
||||
INT32 i;
|
||||
for (i = 0; i < MAXUNLOCKABLES; ++i)
|
||||
{
|
||||
if (unlockables[i].type == type && unlockables[i].unlocked)
|
||||
if (unlockables[i].type == type && data->unlocked[i])
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
UINT8 M_MapLocked(INT32 mapnum)
|
||||
UINT8 M_MapLocked(INT32 mapnum, gamedata_t *data)
|
||||
{
|
||||
if (!mapheaderinfo[mapnum-1] || mapheaderinfo[mapnum-1]->unlockrequired < 0)
|
||||
{
|
||||
return false;
|
||||
if (!unlockables[mapheaderinfo[mapnum-1]->unlockrequired].unlocked)
|
||||
}
|
||||
|
||||
if (!data->unlocked[mapheaderinfo[mapnum-1]->unlockrequired])
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
INT32 M_CountEmblems(void)
|
||||
INT32 M_CountEmblems(gamedata_t *data)
|
||||
{
|
||||
INT32 found = 0, i;
|
||||
for (i = 0; i < numemblems; ++i)
|
||||
{
|
||||
if (emblemlocations[i].collected)
|
||||
if (data->collected[i])
|
||||
found++;
|
||||
}
|
||||
for (i = 0; i < numextraemblems; ++i)
|
||||
{
|
||||
if (extraemblems[i].collected)
|
||||
if (data->extraCollected[i])
|
||||
found++;
|
||||
}
|
||||
return found;
|
||||
|
@ -423,23 +501,23 @@ INT32 M_CountEmblems(void)
|
|||
|
||||
// Theoretically faster than using M_CountEmblems()
|
||||
// Stops when it reaches the target number of emblems.
|
||||
UINT8 M_GotEnoughEmblems(INT32 number)
|
||||
UINT8 M_GotEnoughEmblems(INT32 number, gamedata_t *data)
|
||||
{
|
||||
INT32 i, gottenemblems = 0;
|
||||
for (i = 0; i < numemblems; ++i)
|
||||
{
|
||||
if (emblemlocations[i].collected)
|
||||
if (data->collected[i])
|
||||
if (++gottenemblems >= number) return true;
|
||||
}
|
||||
for (i = 0; i < numextraemblems; ++i)
|
||||
{
|
||||
if (extraemblems[i].collected)
|
||||
if (data->extraCollected[i])
|
||||
if (++gottenemblems >= number) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
UINT8 M_GotHighEnoughScore(INT32 tscore)
|
||||
UINT8 M_GotHighEnoughScore(INT32 tscore, gamedata_t *data)
|
||||
{
|
||||
INT32 mscore = 0;
|
||||
INT32 i;
|
||||
|
@ -448,16 +526,16 @@ UINT8 M_GotHighEnoughScore(INT32 tscore)
|
|||
{
|
||||
if (!mapheaderinfo[i] || !(mapheaderinfo[i]->menuflags & LF2_RECORDATTACK))
|
||||
continue;
|
||||
if (!mainrecords[i])
|
||||
if (!data->mainrecords[i])
|
||||
continue;
|
||||
|
||||
if ((mscore += mainrecords[i]->score) > tscore)
|
||||
if ((mscore += data->mainrecords[i]->score) > tscore)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
UINT8 M_GotLowEnoughTime(INT32 tictime)
|
||||
UINT8 M_GotLowEnoughTime(INT32 tictime, gamedata_t *data)
|
||||
{
|
||||
INT32 curtics = 0;
|
||||
INT32 i;
|
||||
|
@ -467,15 +545,15 @@ UINT8 M_GotLowEnoughTime(INT32 tictime)
|
|||
if (!mapheaderinfo[i] || !(mapheaderinfo[i]->menuflags & LF2_RECORDATTACK))
|
||||
continue;
|
||||
|
||||
if (!mainrecords[i] || !mainrecords[i]->time)
|
||||
if (!data->mainrecords[i] || !data->mainrecords[i]->time)
|
||||
return false;
|
||||
else if ((curtics += mainrecords[i]->time) > tictime)
|
||||
else if ((curtics += data->mainrecords[i]->time) > tictime)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
UINT8 M_GotHighEnoughRings(INT32 trings)
|
||||
UINT8 M_GotHighEnoughRings(INT32 trings, gamedata_t *data)
|
||||
{
|
||||
INT32 mrings = 0;
|
||||
INT32 i;
|
||||
|
@ -484,10 +562,10 @@ UINT8 M_GotHighEnoughRings(INT32 trings)
|
|||
{
|
||||
if (!mapheaderinfo[i] || !(mapheaderinfo[i]->menuflags & LF2_RECORDATTACK))
|
||||
continue;
|
||||
if (!mainrecords[i])
|
||||
if (!data->mainrecords[i])
|
||||
continue;
|
||||
|
||||
if ((mrings += mainrecords[i]->rings) > trings)
|
||||
if ((mrings += data->mainrecords[i]->rings) > trings)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
123
src/m_cond.h
123
src/m_cond.h
|
@ -10,7 +10,11 @@
|
|||
/// \file m_cond.h
|
||||
/// \brief Unlockable condition system for SRB2 version 2.1
|
||||
|
||||
#ifndef __M_COND__
|
||||
#define __M_COND__
|
||||
|
||||
#include "doomdef.h"
|
||||
#include "doomdata.h"
|
||||
|
||||
// --------
|
||||
// Typedefs
|
||||
|
@ -61,8 +65,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
|
||||
|
@ -94,7 +96,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
|
||||
{
|
||||
|
@ -104,7 +105,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
|
||||
|
@ -120,7 +120,6 @@ typedef struct
|
|||
char *stringVar;
|
||||
UINT8 nocecho;
|
||||
UINT8 nochecklist;
|
||||
UINT8 unlocked;
|
||||
} unlockable_t;
|
||||
|
||||
#define SECRET_NONE -6 // Does nil. Use with levels locked by UnlockRequired
|
||||
|
@ -143,6 +142,83 @@ typedef struct
|
|||
#define MAXEXTRAEMBLEMS 16
|
||||
#define MAXUNLOCKABLES 32
|
||||
|
||||
/** Time attack information, currently a very small structure.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
tic_t time; ///< Time in which the level was finished.
|
||||
UINT32 score; ///< Score when the level was finished.
|
||||
UINT16 rings; ///< Rings when the level was finished.
|
||||
} recorddata_t;
|
||||
|
||||
/** Setup for one NiGHTS map.
|
||||
* These are dynamically allocated because I am insane
|
||||
*/
|
||||
#define GRADE_F 0
|
||||
#define GRADE_E 1
|
||||
#define GRADE_D 2
|
||||
#define GRADE_C 3
|
||||
#define GRADE_B 4
|
||||
#define GRADE_A 5
|
||||
#define GRADE_S 6
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// 8 mares, 1 overall (0)
|
||||
UINT8 nummares;
|
||||
UINT32 score[9];
|
||||
UINT8 grade[9];
|
||||
tic_t time[9];
|
||||
} nightsdata_t;
|
||||
|
||||
// mapvisited is now a set of flags that says what we've done in the map.
|
||||
#define MV_VISITED 1
|
||||
#define MV_BEATEN 2
|
||||
#define MV_ALLEMERALDS 4
|
||||
#define MV_ULTIMATE 8
|
||||
#define MV_PERFECT 16
|
||||
#define MV_PERFECTRA 32
|
||||
#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;
|
||||
|
||||
// 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];
|
||||
|
||||
// TIME ATTACK DATA
|
||||
recorddata_t *mainrecords[NUMMAPS];
|
||||
nightsdata_t *nightsrecords[NUMMAPS];
|
||||
UINT8 mapvisited[NUMMAPS];
|
||||
|
||||
// # OF TIMES THE GAME HAS BEEN BEATEN
|
||||
UINT32 timesBeaten;
|
||||
UINT32 timesBeatenWithEmeralds;
|
||||
UINT32 timesBeatenUltimate;
|
||||
|
||||
// PLAY TIME
|
||||
UINT32 totalplaytime;
|
||||
} gamedata_t;
|
||||
|
||||
extern gamedata_t *clientGamedata;
|
||||
extern gamedata_t *serverGamedata;
|
||||
|
||||
extern conditionset_t conditionSets[MAXCONDITIONSETS];
|
||||
extern emblem_t emblemlocations[MAXEMBLEMS];
|
||||
extern extraemblem_t extraemblems[MAXEXTRAEMBLEMS];
|
||||
|
@ -153,25 +229,30 @@ extern INT32 numextraemblems;
|
|||
|
||||
extern UINT32 unlocktriggers;
|
||||
|
||||
gamedata_t *M_NewGameDataStruct(void);
|
||||
void M_CopyGameData(gamedata_t *dest, gamedata_t *src);
|
||||
|
||||
// Condition set setup
|
||||
void M_AddRawCondition(UINT8 set, UINT8 id, conditiontype_t c, INT32 r, INT16 x1, INT16 x2);
|
||||
|
||||
// Clearing secrets
|
||||
void M_ClearConditionSet(UINT8 set);
|
||||
void M_ClearSecrets(void);
|
||||
void M_ClearSecrets(gamedata_t *data);
|
||||
|
||||
// Updating conditions and unlockables
|
||||
void M_CheckUnlockConditions(void);
|
||||
UINT8 M_UpdateUnlockablesAndExtraEmblems(void);
|
||||
void M_SilentUpdateUnlockablesAndEmblems(void);
|
||||
UINT8 M_CheckLevelEmblems(void);
|
||||
UINT8 M_CompletionEmblems(void);
|
||||
void M_CheckUnlockConditions(gamedata_t *data);
|
||||
UINT8 M_UpdateUnlockablesAndExtraEmblems(gamedata_t *data);
|
||||
void M_SilentUpdateUnlockablesAndEmblems(gamedata_t *data);
|
||||
UINT8 M_CheckLevelEmblems(gamedata_t *data);
|
||||
UINT8 M_CompletionEmblems(gamedata_t *data);
|
||||
|
||||
void M_SilentUpdateSkinAvailabilites(void);
|
||||
|
||||
// Checking unlockable status
|
||||
UINT8 M_AnySecretUnlocked(void);
|
||||
UINT8 M_SecretUnlocked(INT32 type);
|
||||
UINT8 M_MapLocked(INT32 mapnum);
|
||||
INT32 M_CountEmblems(void);
|
||||
UINT8 M_AnySecretUnlocked(gamedata_t *data);
|
||||
UINT8 M_SecretUnlocked(INT32 type, gamedata_t *data);
|
||||
UINT8 M_MapLocked(INT32 mapnum, gamedata_t *data);
|
||||
INT32 M_CountEmblems(gamedata_t *data);
|
||||
|
||||
// Emblem shit
|
||||
emblem_t *M_GetLevelEmblems(INT32 mapnum);
|
||||
|
@ -183,12 +264,14 @@ const char *M_GetExtraEmblemPatch(extraemblem_t *em, boolean big);
|
|||
// If you're looking to compare stats for unlocks or what not, use these
|
||||
// They stop checking upon reaching the target number so they
|
||||
// should be (theoretically?) slightly faster.
|
||||
UINT8 M_GotEnoughEmblems(INT32 number);
|
||||
UINT8 M_GotHighEnoughScore(INT32 tscore);
|
||||
UINT8 M_GotLowEnoughTime(INT32 tictime);
|
||||
UINT8 M_GotHighEnoughRings(INT32 trings);
|
||||
UINT8 M_GotEnoughEmblems(INT32 number, gamedata_t *data);
|
||||
UINT8 M_GotHighEnoughScore(INT32 tscore, gamedata_t *data);
|
||||
UINT8 M_GotLowEnoughTime(INT32 tictime, gamedata_t *data);
|
||||
UINT8 M_GotHighEnoughRings(INT32 trings, gamedata_t *data);
|
||||
|
||||
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, data) ((a) >= MAXCONDITIONSETS || data->achieved[a])
|
||||
|
||||
#endif
|
||||
|
|
155
src/m_menu.c
155
src/m_menu.c
|
@ -2284,6 +2284,7 @@ static boolean M_CanShowLevelOnPlatter(INT32 mapnum, INT32 gt);
|
|||
// Nextmap. Used for Level select.
|
||||
void Nextmap_OnChange(void)
|
||||
{
|
||||
gamedata_t *data = clientGamedata;
|
||||
char *leveltitle;
|
||||
char tabase[256];
|
||||
#ifdef OLDNREPLAYNAME
|
||||
|
@ -2301,7 +2302,7 @@ void Nextmap_OnChange(void)
|
|||
{
|
||||
CV_StealthSetValue(&cv_dummymares, 0);
|
||||
// Hide the record changing CVAR if only one mare is available.
|
||||
if (!nightsrecords[cv_nextmap.value-1] || nightsrecords[cv_nextmap.value-1]->nummares < 2)
|
||||
if (!data->nightsrecords[cv_nextmap.value-1] || data->nightsrecords[cv_nextmap.value-1]->nummares < 2)
|
||||
SP_NightsAttackMenu[narecords].status = IT_DISABLED;
|
||||
else
|
||||
SP_NightsAttackMenu[narecords].status = IT_STRING|IT_CVAR;
|
||||
|
@ -2432,14 +2433,15 @@ void Nextmap_OnChange(void)
|
|||
|
||||
static void Dummymares_OnChange(void)
|
||||
{
|
||||
if (!nightsrecords[cv_nextmap.value-1])
|
||||
gamedata_t *data = clientGamedata;
|
||||
if (!data->nightsrecords[cv_nextmap.value-1])
|
||||
{
|
||||
CV_StealthSetValue(&cv_dummymares, 0);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
UINT8 mares = nightsrecords[cv_nextmap.value-1]->nummares;
|
||||
UINT8 mares = data->nightsrecords[cv_nextmap.value-1]->nummares;
|
||||
|
||||
if (cv_dummymares.value < 0)
|
||||
CV_StealthSetValue(&cv_dummymares, mares);
|
||||
|
@ -3670,9 +3672,9 @@ void M_StartControlPanel(void)
|
|||
if (!Playing())
|
||||
{
|
||||
// Secret menu!
|
||||
MainMenu[singleplr].alphaKey = (M_AnySecretUnlocked()) ? 76 : 84;
|
||||
MainMenu[multiplr].alphaKey = (M_AnySecretUnlocked()) ? 84 : 92;
|
||||
MainMenu[secrets].status = (M_AnySecretUnlocked()) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
|
||||
MainMenu[singleplr].alphaKey = (M_AnySecretUnlocked(clientGamedata)) ? 76 : 84;
|
||||
MainMenu[multiplr].alphaKey = (M_AnySecretUnlocked(clientGamedata)) ? 84 : 92;
|
||||
MainMenu[secrets].status = (M_AnySecretUnlocked(clientGamedata)) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
|
||||
|
||||
currentMenu = &MainDef;
|
||||
itemOn = singleplr;
|
||||
|
@ -3680,14 +3682,14 @@ void M_StartControlPanel(void)
|
|||
else if (modeattacking)
|
||||
{
|
||||
currentMenu = &MAPauseDef;
|
||||
MAPauseMenu[mapause_hints].status = (M_SecretUnlocked(SECRET_EMBLEMHINTS)) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
|
||||
MAPauseMenu[mapause_hints].status = (M_SecretUnlocked(SECRET_EMBLEMHINTS, clientGamedata)) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
|
||||
itemOn = mapause_continue;
|
||||
}
|
||||
else if (!(netgame || multiplayer)) // Single Player
|
||||
{
|
||||
if (gamestate != GS_LEVEL || ultimatemode) // intermission, so gray out stuff.
|
||||
{
|
||||
SPauseMenu[spause_pandora].status = (M_SecretUnlocked(SECRET_PANDORA)) ? (IT_GRAYEDOUT) : (IT_DISABLED);
|
||||
SPauseMenu[spause_pandora].status = (M_SecretUnlocked(SECRET_PANDORA, serverGamedata)) ? (IT_GRAYEDOUT) : (IT_DISABLED);
|
||||
SPauseMenu[spause_retry].status = IT_GRAYEDOUT;
|
||||
}
|
||||
else
|
||||
|
@ -3696,7 +3698,7 @@ void M_StartControlPanel(void)
|
|||
if (players[consoleplayer].playerstate != PST_LIVE)
|
||||
++numlives;
|
||||
|
||||
SPauseMenu[spause_pandora].status = (M_SecretUnlocked(SECRET_PANDORA) && !marathonmode) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
|
||||
SPauseMenu[spause_pandora].status = (M_SecretUnlocked(SECRET_PANDORA, serverGamedata) && !marathonmode) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
|
||||
|
||||
// The list of things that can disable retrying is (was?) a little too complex
|
||||
// for me to want to use the short if statement syntax
|
||||
|
@ -3710,7 +3712,7 @@ void M_StartControlPanel(void)
|
|||
SPauseMenu[spause_levelselect].status = (gamecomplete == 1) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
|
||||
|
||||
// And emblem hints.
|
||||
SPauseMenu[spause_hints].status = (M_SecretUnlocked(SECRET_EMBLEMHINTS) && !marathonmode) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
|
||||
SPauseMenu[spause_hints].status = (M_SecretUnlocked(SECRET_EMBLEMHINTS, clientGamedata) && !marathonmode) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
|
||||
|
||||
// Shift up Pandora's Box if both pandora and levelselect are active
|
||||
/*if (SPauseMenu[spause_pandora].status != (IT_DISABLED)
|
||||
|
@ -4259,7 +4261,7 @@ static void M_DrawMapEmblems(INT32 mapnum, INT32 x, INT32 y, boolean norecordatt
|
|||
x -= 4;
|
||||
lasttype = curtype;
|
||||
|
||||
if (emblem->collected)
|
||||
if (clientGamedata->collected[emblem - emblemlocations])
|
||||
V_DrawSmallMappedPatch(x, y, 0, W_CachePatchName(M_GetEmblemPatch(emblem, false), PU_PATCH),
|
||||
R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(emblem), GTC_CACHE));
|
||||
else
|
||||
|
@ -4692,6 +4694,8 @@ static void M_DrawGenericScrollMenu(void)
|
|||
|
||||
static void M_DrawPauseMenu(void)
|
||||
{
|
||||
gamedata_t *data = clientGamedata;
|
||||
|
||||
if (!netgame && !multiplayer && (gamestate == GS_LEVEL || gamestate == GS_INTERMISSION))
|
||||
{
|
||||
emblem_t *emblem_detail[3] = {NULL, NULL, NULL};
|
||||
|
@ -4720,7 +4724,7 @@ static void M_DrawPauseMenu(void)
|
|||
{
|
||||
case ET_SCORE:
|
||||
snprintf(targettext, 9, "%d", emblem->var);
|
||||
snprintf(currenttext, 9, "%u", G_GetBestScore(gamemap));
|
||||
snprintf(currenttext, 9, "%u", G_GetBestScore(gamemap, data));
|
||||
|
||||
targettext[8] = 0;
|
||||
currenttext[8] = 0;
|
||||
|
@ -4734,7 +4738,7 @@ static void M_DrawPauseMenu(void)
|
|||
G_TicsToSeconds((tic_t)emblemslot),
|
||||
G_TicsToCentiseconds((tic_t)emblemslot));
|
||||
|
||||
emblemslot = (INT32)G_GetBestTime(gamemap); // dumb hack pt ii
|
||||
emblemslot = (INT32)G_GetBestTime(gamemap, data); // dumb hack pt ii
|
||||
if ((tic_t)emblemslot == UINT32_MAX)
|
||||
snprintf(currenttext, 9, "-:--.--");
|
||||
else
|
||||
|
@ -4750,7 +4754,7 @@ static void M_DrawPauseMenu(void)
|
|||
break;
|
||||
case ET_RINGS:
|
||||
snprintf(targettext, 9, "%d", emblem->var);
|
||||
snprintf(currenttext, 9, "%u", G_GetBestRings(gamemap));
|
||||
snprintf(currenttext, 9, "%u", G_GetBestRings(gamemap, data));
|
||||
|
||||
targettext[8] = 0;
|
||||
currenttext[8] = 0;
|
||||
|
@ -4758,8 +4762,8 @@ static void M_DrawPauseMenu(void)
|
|||
emblemslot = 2;
|
||||
break;
|
||||
case ET_NGRADE:
|
||||
snprintf(targettext, 9, "%u", P_GetScoreForGradeOverall(gamemap, emblem->var));
|
||||
snprintf(currenttext, 9, "%u", G_GetBestNightsScore(gamemap, 0));
|
||||
snprintf(targettext, 9, "%u", P_GetScoreForGrade(gamemap, 0, emblem->var));
|
||||
snprintf(currenttext, 9, "%u", G_GetBestNightsScore(gamemap, 0, data));
|
||||
|
||||
targettext[8] = 0;
|
||||
currenttext[8] = 0;
|
||||
|
@ -4773,7 +4777,7 @@ static void M_DrawPauseMenu(void)
|
|||
G_TicsToSeconds((tic_t)emblemslot),
|
||||
G_TicsToCentiseconds((tic_t)emblemslot));
|
||||
|
||||
emblemslot = (INT32)G_GetBestNightsTime(gamemap, 0); // dumb hack pt iv
|
||||
emblemslot = (INT32)G_GetBestNightsTime(gamemap, 0, data); // dumb hack pt iv
|
||||
if ((tic_t)emblemslot == UINT32_MAX)
|
||||
snprintf(currenttext, 9, "-:--.--");
|
||||
else
|
||||
|
@ -4807,7 +4811,7 @@ static void M_DrawPauseMenu(void)
|
|||
if (!emblem)
|
||||
continue;
|
||||
|
||||
if (emblem->collected)
|
||||
if (data->collected[emblem - emblemlocations])
|
||||
V_DrawSmallMappedPatch(40, 44 + (i*8), 0, W_CachePatchName(M_GetEmblemPatch(emblem, false), PU_PATCH),
|
||||
R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(emblem), GTC_CACHE));
|
||||
else
|
||||
|
@ -5019,7 +5023,9 @@ static void M_PatchSkinNameTable(void)
|
|||
//
|
||||
static boolean M_LevelAvailableOnPlatter(INT32 mapnum)
|
||||
{
|
||||
if (M_MapLocked(mapnum+1))
|
||||
gamedata_t *data = serverGamedata;
|
||||
|
||||
if (M_MapLocked(mapnum+1, data))
|
||||
return false; // not unlocked
|
||||
|
||||
switch (levellistmode)
|
||||
|
@ -5032,7 +5038,7 @@ static boolean M_LevelAvailableOnPlatter(INT32 mapnum)
|
|||
return true;
|
||||
|
||||
#ifndef DEVELOP
|
||||
if (mapvisited[mapnum]) // MV_MP
|
||||
if (data->mapvisited[mapnum])
|
||||
#endif
|
||||
return true;
|
||||
|
||||
|
@ -5040,7 +5046,7 @@ static boolean M_LevelAvailableOnPlatter(INT32 mapnum)
|
|||
case LLM_RECORDATTACK:
|
||||
case LLM_NIGHTSATTACK:
|
||||
#ifndef DEVELOP
|
||||
if (mapvisited[mapnum] & MV_MAX)
|
||||
if (data->mapvisited[mapnum])
|
||||
return true;
|
||||
|
||||
if (mapheaderinfo[mapnum]->menuflags & LF2_NOVISITNEEDED)
|
||||
|
@ -5071,7 +5077,7 @@ static boolean M_CanShowLevelOnPlatter(INT32 mapnum, INT32 gt)
|
|||
if (!mapheaderinfo[mapnum]->lvlttl[0])
|
||||
return false;
|
||||
|
||||
/*if (M_MapLocked(mapnum+1))
|
||||
/*if (M_MapLocked(mapnum+1, serverGamedata))
|
||||
return false; // not unlocked*/
|
||||
|
||||
switch (levellistmode)
|
||||
|
@ -6904,7 +6910,7 @@ static void M_HandleAddons(INT32 choice)
|
|||
closefilemenu(true);
|
||||
|
||||
// secrets disabled by addfile...
|
||||
MainMenu[secrets].status = (M_AnySecretUnlocked()) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
|
||||
MainMenu[secrets].status = (M_AnySecretUnlocked(clientGamedata)) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
|
||||
|
||||
if (currentMenu->prevMenu)
|
||||
M_SetupNextMenu(currentMenu->prevMenu);
|
||||
|
@ -7150,7 +7156,9 @@ static boolean checklist_cangodown; // uuuueeerggghhhh HACK
|
|||
|
||||
static void M_HandleChecklist(INT32 choice)
|
||||
{
|
||||
gamedata_t *data = clientGamedata;
|
||||
INT32 j;
|
||||
|
||||
switch (choice)
|
||||
{
|
||||
case KEY_DOWNARROW:
|
||||
|
@ -7167,7 +7175,7 @@ static void M_HandleChecklist(INT32 choice)
|
|||
continue;
|
||||
if (unlockables[j].conditionset > MAXCONDITIONSETS)
|
||||
continue;
|
||||
if (!unlockables[j].unlocked && unlockables[j].showconditionset && !M_Achieved(unlockables[j].showconditionset))
|
||||
if (!data->unlocked[j] && unlockables[j].showconditionset && !M_Achieved(unlockables[j].showconditionset, data))
|
||||
continue;
|
||||
if (unlockables[j].conditionset == unlockables[check_on].conditionset)
|
||||
continue;
|
||||
|
@ -7192,7 +7200,7 @@ static void M_HandleChecklist(INT32 choice)
|
|||
continue;
|
||||
if (unlockables[j].conditionset > MAXCONDITIONSETS)
|
||||
continue;
|
||||
if (!unlockables[j].unlocked && unlockables[j].showconditionset && !M_Achieved(unlockables[j].showconditionset))
|
||||
if (!data->unlocked[j] && unlockables[j].showconditionset && !M_Achieved(unlockables[j].showconditionset, data))
|
||||
continue;
|
||||
if (j && unlockables[j].conditionset == unlockables[j-1].conditionset)
|
||||
continue;
|
||||
|
@ -7218,6 +7226,9 @@ static void M_HandleChecklist(INT32 choice)
|
|||
|
||||
static void M_DrawChecklist(void)
|
||||
{
|
||||
gamedata_t *data = clientGamedata;
|
||||
INT32 emblemCount = M_CountEmblems(data);
|
||||
|
||||
INT32 i = check_on, j = 0, y = currentMenu->y, emblems = numemblems+numextraemblems;
|
||||
UINT32 condnum, previd, maxcond;
|
||||
condition_t *cond;
|
||||
|
@ -7228,7 +7239,7 @@ static void M_DrawChecklist(void)
|
|||
// draw emblem counter
|
||||
if (emblems > 0)
|
||||
{
|
||||
V_DrawString(42, 20, (emblems == M_CountEmblems()) ? V_GREENMAP : 0, va("%d/%d", M_CountEmblems(), emblems));
|
||||
V_DrawString(42, 20, (emblems == emblemCount) ? V_GREENMAP : 0, va("%d/%d", emblemCount, emblems));
|
||||
V_DrawSmallScaledPatch(28, 20, 0, W_CachePatchName("EMBLICON", PU_PATCH));
|
||||
}
|
||||
|
||||
|
@ -7239,13 +7250,13 @@ static void M_DrawChecklist(void)
|
|||
{
|
||||
if (unlockables[i].name[0] == 0 //|| unlockables[i].nochecklist
|
||||
|| !unlockables[i].conditionset || unlockables[i].conditionset > MAXCONDITIONSETS
|
||||
|| (!unlockables[i].unlocked && unlockables[i].showconditionset && !M_Achieved(unlockables[i].showconditionset)))
|
||||
|| (!data->unlocked[i] && unlockables[i].showconditionset && !M_Achieved(unlockables[i].showconditionset, data)))
|
||||
{
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
V_DrawString(currentMenu->x, y, ((unlockables[i].unlocked) ? V_GREENMAP : V_TRANSLUCENT)|V_ALLOWLOWERCASE, ((unlockables[i].unlocked || !unlockables[i].nochecklist) ? unlockables[i].name : M_CreateSecretMenuOption(unlockables[i].name)));
|
||||
V_DrawString(currentMenu->x, y, ((data->unlocked[i]) ? V_GREENMAP : V_TRANSLUCENT)|V_ALLOWLOWERCASE, ((data->unlocked[i] || !unlockables[i].nochecklist) ? unlockables[i].name : M_CreateSecretMenuOption(unlockables[i].name)));
|
||||
|
||||
for (j = i+1; j < MAXUNLOCKABLES; j++)
|
||||
{
|
||||
|
@ -7323,7 +7334,7 @@ static void M_DrawChecklist(void)
|
|||
|
||||
if (title)
|
||||
{
|
||||
const char *level = ((M_MapLocked(cond[condnum].requirement) || !((mapheaderinfo[cond[condnum].requirement-1]->menuflags & LF2_NOVISITNEEDED) || (mapvisited[cond[condnum].requirement-1] & MV_MAX))) ? M_CreateSecretMenuOption(title) : title);
|
||||
const char *level = ((M_MapLocked(cond[condnum].requirement, data) || !((mapheaderinfo[cond[condnum].requirement-1]->menuflags & LF2_NOVISITNEEDED) || (data->mapvisited[cond[condnum].requirement-1] & MV_MAX))) ? M_CreateSecretMenuOption(title) : title);
|
||||
|
||||
switch (cond[condnum].type)
|
||||
{
|
||||
|
@ -7356,7 +7367,7 @@ static void M_DrawChecklist(void)
|
|||
|
||||
if (title)
|
||||
{
|
||||
const char *level = ((M_MapLocked(cond[condnum].extrainfo1) || !((mapheaderinfo[cond[condnum].extrainfo1-1]->menuflags & LF2_NOVISITNEEDED) || (mapvisited[cond[condnum].extrainfo1-1] & MV_MAX))) ? M_CreateSecretMenuOption(title) : title);
|
||||
const char *level = ((M_MapLocked(cond[condnum].extrainfo1, data) || !((mapheaderinfo[cond[condnum].extrainfo1-1]->menuflags & LF2_NOVISITNEEDED) || (data->mapvisited[cond[condnum].extrainfo1-1] & MV_MAX))) ? M_CreateSecretMenuOption(title) : title);
|
||||
|
||||
switch (cond[condnum].type)
|
||||
{
|
||||
|
@ -7425,7 +7436,7 @@ static void M_DrawChecklist(void)
|
|||
|
||||
if (title)
|
||||
{
|
||||
const char *level = ((M_MapLocked(cond[condnum].extrainfo1) || !((mapheaderinfo[cond[condnum].extrainfo1-1]->menuflags & LF2_NOVISITNEEDED) || (mapvisited[cond[condnum].extrainfo1-1] & MV_MAX))) ? M_CreateSecretMenuOption(title) : title);
|
||||
const char *level = ((M_MapLocked(cond[condnum].extrainfo1, data) || !((mapheaderinfo[cond[condnum].extrainfo1-1]->menuflags & LF2_NOVISITNEEDED) || (data->mapvisited[cond[condnum].extrainfo1-1] & MV_MAX))) ? M_CreateSecretMenuOption(title) : title);
|
||||
|
||||
switch (cond[condnum].type)
|
||||
{
|
||||
|
@ -7488,7 +7499,7 @@ static void M_DrawChecklist(void)
|
|||
|
||||
/*V_DrawString(160, 8+(24*j), V_RETURN8, V_WordWrap(160, 292, 0, unlockables[i].objective));
|
||||
|
||||
if (unlockables[i].unlocked)
|
||||
if (data->unlocked[i])
|
||||
V_DrawString(308, 8+(24*j), V_YELLOWMAP, "Y");
|
||||
else
|
||||
V_DrawString(308, 8+(24*j), V_YELLOWMAP, "N");*/
|
||||
|
@ -7517,7 +7528,7 @@ static void M_EmblemHints(INT32 choice)
|
|||
|
||||
(void)choice;
|
||||
SR_EmblemHintMenu[0].status = (local > NUMHINTS*2) ? (IT_STRING | IT_ARROWS) : (IT_DISABLED);
|
||||
SR_EmblemHintMenu[1].status = (M_SecretUnlocked(SECRET_ITEMFINDER)) ? (IT_CVAR|IT_STRING) : (IT_SECRET);
|
||||
SR_EmblemHintMenu[1].status = (M_SecretUnlocked(SECRET_ITEMFINDER, clientGamedata)) ? (IT_CVAR|IT_STRING) : (IT_SECRET);
|
||||
hintpage = 1;
|
||||
SR_EmblemHintDef.prevMenu = currentMenu;
|
||||
M_SetupNextMenu(&SR_EmblemHintDef);
|
||||
|
@ -7577,7 +7588,7 @@ static void M_DrawEmblemHints(void)
|
|||
|
||||
if (totalemblems >= ((hintpage-1)*(NUMHINTS*2) + 1) && totalemblems < (hintpage*NUMHINTS*2)+1){
|
||||
|
||||
if (emblem->collected)
|
||||
if (clientGamedata->collected[i])
|
||||
{
|
||||
collected = V_GREENMAP;
|
||||
V_DrawMappedPatch(x, y+4, 0, W_CachePatchName(M_GetEmblemPatch(emblem, false), PU_PATCH),
|
||||
|
@ -8117,7 +8128,7 @@ static void M_SecretsMenu(INT32 choice)
|
|||
|
||||
SR_MainMenu[i].status = IT_SECRET;
|
||||
|
||||
if (unlockables[ul].unlocked)
|
||||
if (clientGamedata->unlocked[ul])
|
||||
{
|
||||
switch (unlockables[ul].type)
|
||||
{
|
||||
|
@ -8216,7 +8227,7 @@ static void M_SinglePlayerMenu(INT32 choice)
|
|||
|
||||
levellistmode = LLM_RECORDATTACK;
|
||||
if (M_GametypeHasLevels(-1))
|
||||
SP_MainMenu[sprecordattack].status = (M_SecretUnlocked(SECRET_RECORDATTACK)) ? IT_CALL|IT_STRING : IT_SECRET;
|
||||
SP_MainMenu[sprecordattack].status = (M_SecretUnlocked(SECRET_RECORDATTACK, clientGamedata)) ? IT_CALL|IT_STRING : IT_SECRET;
|
||||
else // If Record Attack is nonexistent in the current add-on...
|
||||
{
|
||||
SP_MainMenu[sprecordattack].status = IT_NOTHING|IT_DISABLED; // ...hide and disable the Record Attack option...
|
||||
|
@ -8226,7 +8237,7 @@ static void M_SinglePlayerMenu(INT32 choice)
|
|||
|
||||
levellistmode = LLM_NIGHTSATTACK;
|
||||
if (M_GametypeHasLevels(-1))
|
||||
SP_MainMenu[spnightsmode].status = (M_SecretUnlocked(SECRET_NIGHTSMODE)) ? IT_CALL|IT_STRING : IT_SECRET;
|
||||
SP_MainMenu[spnightsmode].status = (M_SecretUnlocked(SECRET_NIGHTSMODE, clientGamedata)) ? IT_CALL|IT_STRING : IT_SECRET;
|
||||
else // If NiGHTS Mode is nonexistent in the current add-on...
|
||||
{
|
||||
SP_MainMenu[spnightsmode].status = IT_NOTHING|IT_DISABLED; // ...hide and disable the NiGHTS Mode option...
|
||||
|
@ -8249,7 +8260,7 @@ static void M_SinglePlayerMenu(INT32 choice)
|
|||
SP_MainMenu[spnightsmode] .alphaKey += 8;
|
||||
}
|
||||
else // Otherwise, if Marathon Run is allowed and Record Attack is unlocked, unlock Marathon Run!
|
||||
SP_MainMenu[spmarathon].status = (M_SecretUnlocked(SECRET_RECORDATTACK)) ? IT_CALL|IT_STRING|IT_CALL_NOTMODIFIED : IT_SECRET;
|
||||
SP_MainMenu[spmarathon].status = (M_SecretUnlocked(SECRET_RECORDATTACK, clientGamedata)) ? IT_CALL|IT_STRING|IT_CALL_NOTMODIFIED : IT_SECRET;
|
||||
|
||||
|
||||
if (tutorialmap) // If there's a tutorial available in the current add-on...
|
||||
|
@ -9626,7 +9637,7 @@ static void M_Statistics(INT32 choice)
|
|||
if (!(mapheaderinfo[i]->typeoflevel & TOL_SP) || (mapheaderinfo[i]->menuflags & LF2_HIDEINSTATS))
|
||||
continue;
|
||||
|
||||
if (!(mapvisited[i] & MV_MAX))
|
||||
if (!(clientGamedata->mapvisited[i] & MV_MAX))
|
||||
continue;
|
||||
|
||||
statsMapList[j++] = i;
|
||||
|
@ -9643,6 +9654,7 @@ static void M_Statistics(INT32 choice)
|
|||
|
||||
static void M_DrawStatsMaps(int location)
|
||||
{
|
||||
gamedata_t *data = clientGamedata;
|
||||
INT32 y = 80, i = -1;
|
||||
INT16 mnum;
|
||||
extraemblem_t *exemblem;
|
||||
|
@ -9710,14 +9722,14 @@ static void M_DrawStatsMaps(int location)
|
|||
{
|
||||
exemblem = &extraemblems[i];
|
||||
|
||||
if (exemblem->collected)
|
||||
if (data->extraCollected[i])
|
||||
V_DrawSmallMappedPatch(292, y, 0, W_CachePatchName(M_GetExtraEmblemPatch(exemblem, false), PU_PATCH),
|
||||
R_GetTranslationColormap(TC_DEFAULT, M_GetExtraEmblemColor(exemblem), GTC_CACHE));
|
||||
else
|
||||
V_DrawSmallScaledPatch(292, y, 0, W_CachePatchName("NEEDIT", PU_PATCH));
|
||||
|
||||
V_DrawString(20, y, V_YELLOWMAP|V_ALLOWLOWERCASE,
|
||||
(!exemblem->collected && exemblem->showconditionset && !M_Achieved(exemblem->showconditionset))
|
||||
(!data->extraCollected[i] && exemblem->showconditionset && !M_Achieved(exemblem->showconditionset, data))
|
||||
? M_CreateSecretMenuOption(exemblem->description)
|
||||
: exemblem->description);
|
||||
}
|
||||
|
@ -9734,6 +9746,7 @@ bottomarrow:
|
|||
|
||||
static void M_DrawLevelStats(void)
|
||||
{
|
||||
gamedata_t *data = clientGamedata;
|
||||
char beststr[40];
|
||||
|
||||
tic_t besttime = 0;
|
||||
|
@ -9748,9 +9761,9 @@ static void M_DrawLevelStats(void)
|
|||
|
||||
V_DrawString(20, 24, V_YELLOWMAP, "Total Play Time:");
|
||||
V_DrawCenteredString(BASEVIDWIDTH/2, 32, 0, va("%i hours, %i minutes, %i seconds",
|
||||
G_TicsToHours(totalplaytime),
|
||||
G_TicsToMinutes(totalplaytime, false),
|
||||
G_TicsToSeconds(totalplaytime)));
|
||||
G_TicsToHours(data->totalplaytime),
|
||||
G_TicsToMinutes(data->totalplaytime, false),
|
||||
G_TicsToSeconds(data->totalplaytime)));
|
||||
|
||||
for (i = 0; i < NUMMAPS; i++)
|
||||
{
|
||||
|
@ -9759,25 +9772,25 @@ static void M_DrawLevelStats(void)
|
|||
if (!mapheaderinfo[i] || !(mapheaderinfo[i]->menuflags & LF2_RECORDATTACK))
|
||||
continue;
|
||||
|
||||
if (!mainrecords[i])
|
||||
if (!data->mainrecords[i])
|
||||
{
|
||||
mapsunfinished++;
|
||||
bestunfinished[0] = bestunfinished[1] = bestunfinished[2] = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mainrecords[i]->score > 0)
|
||||
bestscore += mainrecords[i]->score;
|
||||
if (data->mainrecords[i]->score > 0)
|
||||
bestscore += data->mainrecords[i]->score;
|
||||
else
|
||||
mapunfinished = bestunfinished[0] = true;
|
||||
|
||||
if (mainrecords[i]->time > 0)
|
||||
besttime += mainrecords[i]->time;
|
||||
if (data->mainrecords[i]->time > 0)
|
||||
besttime += data->mainrecords[i]->time;
|
||||
else
|
||||
mapunfinished = bestunfinished[1] = true;
|
||||
|
||||
if (mainrecords[i]->rings > 0)
|
||||
bestrings += mainrecords[i]->rings;
|
||||
if (data->mainrecords[i]->rings > 0)
|
||||
bestrings += data->mainrecords[i]->rings;
|
||||
else
|
||||
mapunfinished = bestunfinished[2] = true;
|
||||
|
||||
|
@ -9792,7 +9805,7 @@ static void M_DrawLevelStats(void)
|
|||
else
|
||||
V_DrawString(20, 56, V_GREENMAP, "(complete)");
|
||||
|
||||
V_DrawString(36, 64, 0, va("x %d/%d", M_CountEmblems(), numemblems+numextraemblems));
|
||||
V_DrawString(36, 64, 0, va("x %d/%d", M_CountEmblems(data), numemblems+numextraemblems));
|
||||
V_DrawSmallScaledPatch(20, 64, 0, W_CachePatchName("EMBLICON", PU_PATCH));
|
||||
|
||||
sprintf(beststr, "%u", bestscore);
|
||||
|
@ -9859,6 +9872,7 @@ static void M_HandleLevelStats(INT32 choice)
|
|||
// Drawing function for Time Attack
|
||||
void M_DrawTimeAttackMenu(void)
|
||||
{
|
||||
gamedata_t *data = clientGamedata;
|
||||
INT32 i, x, y, empatx, empaty, cursory = 0;
|
||||
UINT16 dispstatus;
|
||||
patch_t *PictureOfUrFace; // my WHAT
|
||||
|
@ -10017,7 +10031,7 @@ void M_DrawTimeAttackMenu(void)
|
|||
empatx = empatch->leftoffset / 2;
|
||||
empaty = empatch->topoffset / 2;
|
||||
|
||||
if (em->collected)
|
||||
if (data->collected[em - emblemlocations])
|
||||
V_DrawSmallMappedPatch(104+76+empatx, yHeight+lsheadingheight/2+empaty, 0, empatch,
|
||||
R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(em), GTC_CACHE));
|
||||
else
|
||||
|
@ -10030,34 +10044,34 @@ void M_DrawTimeAttackMenu(void)
|
|||
// Draw in-level emblems.
|
||||
M_DrawMapEmblems(cv_nextmap.value, 288, 28, true);
|
||||
|
||||
if (!mainrecords[cv_nextmap.value-1] || !mainrecords[cv_nextmap.value-1]->score)
|
||||
if (!data->mainrecords[cv_nextmap.value-1] || !data->mainrecords[cv_nextmap.value-1]->score)
|
||||
sprintf(beststr, "(none)");
|
||||
else
|
||||
sprintf(beststr, "%u", mainrecords[cv_nextmap.value-1]->score);
|
||||
sprintf(beststr, "%u", data->mainrecords[cv_nextmap.value-1]->score);
|
||||
|
||||
V_DrawString(104-72, 33+lsheadingheight/2, V_YELLOWMAP, "SCORE:");
|
||||
V_DrawRightAlignedString(104+64, 33+lsheadingheight/2, V_ALLOWLOWERCASE, beststr);
|
||||
V_DrawRightAlignedString(104+72, 43+lsheadingheight/2, V_ALLOWLOWERCASE, reqscore);
|
||||
|
||||
if (!mainrecords[cv_nextmap.value-1] || !mainrecords[cv_nextmap.value-1]->time)
|
||||
if (!data->mainrecords[cv_nextmap.value-1] || !data->mainrecords[cv_nextmap.value-1]->time)
|
||||
sprintf(beststr, "(none)");
|
||||
else
|
||||
sprintf(beststr, "%i:%02i.%02i", G_TicsToMinutes(mainrecords[cv_nextmap.value-1]->time, true),
|
||||
G_TicsToSeconds(mainrecords[cv_nextmap.value-1]->time),
|
||||
G_TicsToCentiseconds(mainrecords[cv_nextmap.value-1]->time));
|
||||
sprintf(beststr, "%i:%02i.%02i", G_TicsToMinutes(data->mainrecords[cv_nextmap.value-1]->time, true),
|
||||
G_TicsToSeconds(data->mainrecords[cv_nextmap.value-1]->time),
|
||||
G_TicsToCentiseconds(data->mainrecords[cv_nextmap.value-1]->time));
|
||||
|
||||
V_DrawString(104-72, 53+lsheadingheight/2, V_YELLOWMAP, "TIME:");
|
||||
V_DrawRightAlignedString(104+64, 53+lsheadingheight/2, V_ALLOWLOWERCASE, beststr);
|
||||
V_DrawRightAlignedString(104+72, 63+lsheadingheight/2, V_ALLOWLOWERCASE, reqtime);
|
||||
|
||||
if (!mainrecords[cv_nextmap.value-1] || !mainrecords[cv_nextmap.value-1]->rings)
|
||||
if (!data->mainrecords[cv_nextmap.value-1] || !data->mainrecords[cv_nextmap.value-1]->rings)
|
||||
sprintf(beststr, "(none)");
|
||||
else
|
||||
sprintf(beststr, "%hu", mainrecords[cv_nextmap.value-1]->rings);
|
||||
sprintf(beststr, "%hu", data->mainrecords[cv_nextmap.value-1]->rings);
|
||||
|
||||
V_DrawString(104-72, 73+lsheadingheight/2, V_YELLOWMAP, "RINGS:");
|
||||
|
||||
V_DrawRightAlignedString(104+64, 73+lsheadingheight/2, V_ALLOWLOWERCASE|((mapvisited[cv_nextmap.value-1] & MV_PERFECTRA) ? V_YELLOWMAP : 0), beststr);
|
||||
V_DrawRightAlignedString(104+64, 73+lsheadingheight/2, V_ALLOWLOWERCASE|((data->mapvisited[cv_nextmap.value-1] & MV_PERFECTRA) ? V_YELLOWMAP : 0), beststr);
|
||||
|
||||
V_DrawRightAlignedString(104+72, 83+lsheadingheight/2, V_ALLOWLOWERCASE, reqrings);
|
||||
}
|
||||
|
@ -10151,6 +10165,7 @@ static void M_TimeAttack(INT32 choice)
|
|||
// Drawing function for Nights Attack
|
||||
void M_DrawNightsAttackMenu(void)
|
||||
{
|
||||
gamedata_t *data = clientGamedata;
|
||||
INT32 i, x, y, cursory = 0;
|
||||
UINT16 dispstatus;
|
||||
|
||||
|
@ -10217,10 +10232,10 @@ void M_DrawNightsAttackMenu(void)
|
|||
lumpnum_t lumpnum;
|
||||
char beststr[40];
|
||||
|
||||
//UINT8 bestoverall = G_GetBestNightsGrade(cv_nextmap.value, 0);
|
||||
UINT8 bestgrade = G_GetBestNightsGrade(cv_nextmap.value, cv_dummymares.value);
|
||||
UINT32 bestscore = G_GetBestNightsScore(cv_nextmap.value, cv_dummymares.value);
|
||||
tic_t besttime = G_GetBestNightsTime(cv_nextmap.value, cv_dummymares.value);
|
||||
//UINT8 bestoverall = G_GetBestNightsGrade(cv_nextmap.value, 0, data);
|
||||
UINT8 bestgrade = G_GetBestNightsGrade(cv_nextmap.value, cv_dummymares.value, data);
|
||||
UINT32 bestscore = G_GetBestNightsScore(cv_nextmap.value, cv_dummymares.value, data);
|
||||
tic_t besttime = G_GetBestNightsTime(cv_nextmap.value, cv_dummymares.value, data);
|
||||
|
||||
M_DrawLevelPlatterHeader(32-lsheadingheight/2, cv_nextmap.string, true, false);
|
||||
|
||||
|
@ -10301,7 +10316,7 @@ void M_DrawNightsAttackMenu(void)
|
|||
goto skipThisOne;
|
||||
}
|
||||
|
||||
if (em->collected)
|
||||
if (data->collected[em - emblemlocations])
|
||||
V_DrawSmallMappedPatch(xpos, yHeight+lsheadingheight/2, 0, W_CachePatchName(M_GetEmblemPatch(em, false), PU_PATCH),
|
||||
R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(em), GTC_CACHE));
|
||||
else
|
||||
|
@ -12544,12 +12559,12 @@ static void M_EraseDataResponse(INT32 ch)
|
|||
|
||||
// Delete the data
|
||||
if (erasecontext != 1)
|
||||
G_ClearRecords();
|
||||
G_ClearRecords(clientGamedata);
|
||||
if (erasecontext != 0)
|
||||
M_ClearSecrets();
|
||||
M_ClearSecrets(clientGamedata);
|
||||
if (erasecontext == 2)
|
||||
{
|
||||
totalplaytime = 0;
|
||||
clientGamedata->totalplaytime = 0;
|
||||
F_StartIntro();
|
||||
}
|
||||
BwehHehHe();
|
||||
|
|
|
@ -14,12 +14,11 @@
|
|||
|
||||
#include "doomdef.h"
|
||||
#include "doomtype.h"
|
||||
#include "doomstat.h" // totalplaytime
|
||||
|
||||
#include "m_random.h"
|
||||
#include "m_fixed.h"
|
||||
|
||||
|
||||
#include "m_cond.h" // totalplaytime
|
||||
|
||||
// ---------------------------
|
||||
// RNG functions (not synched)
|
||||
|
@ -252,5 +251,5 @@ void P_SetRandSeedD(const char *rfile, INT32 rline, UINT32 seed)
|
|||
*/
|
||||
UINT32 M_RandomizedSeed(void)
|
||||
{
|
||||
return ((totalplaytime & 0xFFFF) << 16)|M_RandomFixed();
|
||||
return ((serverGamedata->totalplaytime & 0xFFFF) << 16) | M_RandomFixed();
|
||||
}
|
||||
|
|
|
@ -740,10 +740,22 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
{
|
||||
if (demoplayback || (player->bot && player->bot != BOT_MPAI) || special->health <= 0 || special->health > MAXEMBLEMS)
|
||||
return;
|
||||
emblemlocations[special->health-1].collected = true;
|
||||
|
||||
M_UpdateUnlockablesAndExtraEmblems();
|
||||
G_SaveGameData();
|
||||
if (emblemlocations[special->health-1].type == ET_SKIN)
|
||||
{
|
||||
INT32 skinnum = M_EmblemSkinNum(&emblemlocations[special->health-1]);
|
||||
|
||||
if (player->skin != skinnum)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
clientGamedata->collected[special->health-1] = serverGamedata->collected[special->health-1] = true;
|
||||
|
||||
M_SilentUpdateUnlockablesAndEmblems(serverGamedata);
|
||||
M_UpdateUnlockablesAndExtraEmblems(clientGamedata);
|
||||
G_SaveGameData(clientGamedata);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
19
src/p_mobj.c
19
src/p_mobj.c
|
@ -12004,10 +12004,6 @@ static boolean P_AllowMobjSpawn(mapthing_t* mthing, mobjtype_t i)
|
|||
return false; // You already got this token
|
||||
|
||||
break;
|
||||
case MT_EMBLEM:
|
||||
if (netgame || multiplayer)
|
||||
return false; // Single player (You're next on my shit list)
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -12175,15 +12171,20 @@ 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;
|
||||
|
||||
validEmblem = !emblemlocations[j].collected;
|
||||
validEmblem = true;
|
||||
|
||||
if (emblemlocations[j].type == ET_SKIN)
|
||||
if (!netgame)
|
||||
{
|
||||
INT32 skinnum = M_EmblemSkinNum(&emblemlocations[j]);
|
||||
validEmblem = !serverGamedata->collected[j];
|
||||
|
||||
if (players[0].skin != skinnum)
|
||||
if (emblemlocations[j].type == ET_SKIN && !multiplayer)
|
||||
{
|
||||
validEmblem = false;
|
||||
INT32 skinnum = M_EmblemSkinNum(&emblemlocations[j]);
|
||||
|
||||
if (players[0].skin != skinnum)
|
||||
{
|
||||
validEmblem = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
225
src/p_saveg.c
225
src/p_saveg.c
|
@ -47,6 +47,7 @@ UINT8 *save_p;
|
|||
#define ARCHIVEBLOCK_POBJS 0x7F928546
|
||||
#define ARCHIVEBLOCK_THINKERS 0x7F37037C
|
||||
#define ARCHIVEBLOCK_SPECIALS 0x7F228378
|
||||
#define ARCHIVEBLOCK_EMBLEMS 0x7F4A5445
|
||||
|
||||
// Note: This cannot be bigger
|
||||
// than an UINT16
|
||||
|
@ -4339,6 +4340,8 @@ static void P_NetArchiveMisc(boolean resending)
|
|||
|
||||
WRITEUINT32(save_p, hidetime);
|
||||
|
||||
WRITEUINT32(save_p, unlocktriggers);
|
||||
|
||||
// Is it paused?
|
||||
if (paused)
|
||||
WRITEUINT8(save_p, 0x2f);
|
||||
|
@ -4437,6 +4440,8 @@ 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;
|
||||
|
@ -4444,6 +4449,224 @@ static inline boolean P_NetUnArchiveMisc(boolean reloading)
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
static inline void P_NetArchiveEmblems(void)
|
||||
{
|
||||
gamedata_t *data = serverGamedata;
|
||||
INT32 i, j;
|
||||
UINT8 btemp;
|
||||
INT32 curmare;
|
||||
|
||||
WRITEUINT32(save_p, ARCHIVEBLOCK_EMBLEMS);
|
||||
|
||||
// These should be synchronized before savegame loading by the wad files being the same anyway,
|
||||
// but just in case, for now, we'll leave them here for testing. It would be very bad if they mismatch.
|
||||
WRITEUINT8(save_p, (UINT8)savemoddata);
|
||||
WRITEINT32(save_p, numemblems);
|
||||
WRITEINT32(save_p, numextraemblems);
|
||||
|
||||
// The rest of this is lifted straight from G_SaveGameData in g_game.c
|
||||
// TODO: Optimize this to only send information about emblems, unlocks, etc. which actually exist
|
||||
// There is no need to go all the way up to MAXEMBLEMS when wads are guaranteed to be the same.
|
||||
|
||||
WRITEUINT32(save_p, data->totalplaytime);
|
||||
|
||||
// TODO put another cipher on these things? meh, I don't care...
|
||||
for (i = 0; i < NUMMAPS; i++)
|
||||
WRITEUINT8(save_p, (data->mapvisited[i] & MV_MAX));
|
||||
|
||||
// To save space, use one bit per collected/achieved/unlocked flag
|
||||
for (i = 0; i < MAXEMBLEMS;)
|
||||
{
|
||||
btemp = 0;
|
||||
for (j = 0; j < 8 && j+i < MAXEMBLEMS; ++j)
|
||||
btemp |= (data->collected[j+i] << j);
|
||||
WRITEUINT8(save_p, btemp);
|
||||
i += j;
|
||||
}
|
||||
for (i = 0; i < MAXEXTRAEMBLEMS;)
|
||||
{
|
||||
btemp = 0;
|
||||
for (j = 0; j < 8 && j+i < MAXEXTRAEMBLEMS; ++j)
|
||||
btemp |= (data->extraCollected[j+i] << j);
|
||||
WRITEUINT8(save_p, btemp);
|
||||
i += j;
|
||||
}
|
||||
for (i = 0; i < MAXUNLOCKABLES;)
|
||||
{
|
||||
btemp = 0;
|
||||
for (j = 0; j < 8 && j+i < MAXUNLOCKABLES; ++j)
|
||||
btemp |= (data->unlocked[j+i] << j);
|
||||
WRITEUINT8(save_p, btemp);
|
||||
i += j;
|
||||
}
|
||||
for (i = 0; i < MAXCONDITIONSETS;)
|
||||
{
|
||||
btemp = 0;
|
||||
for (j = 0; j < 8 && j+i < MAXCONDITIONSETS; ++j)
|
||||
btemp |= (data->achieved[j+i] << j);
|
||||
WRITEUINT8(save_p, btemp);
|
||||
i += j;
|
||||
}
|
||||
|
||||
WRITEUINT32(save_p, data->timesBeaten);
|
||||
WRITEUINT32(save_p, data->timesBeatenWithEmeralds);
|
||||
WRITEUINT32(save_p, data->timesBeatenUltimate);
|
||||
|
||||
// Main records
|
||||
for (i = 0; i < NUMMAPS; i++)
|
||||
{
|
||||
if (data->mainrecords[i])
|
||||
{
|
||||
WRITEUINT32(save_p, data->mainrecords[i]->score);
|
||||
WRITEUINT32(save_p, data->mainrecords[i]->time);
|
||||
WRITEUINT16(save_p, data->mainrecords[i]->rings);
|
||||
}
|
||||
else
|
||||
{
|
||||
WRITEUINT32(save_p, 0);
|
||||
WRITEUINT32(save_p, 0);
|
||||
WRITEUINT16(save_p, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// NiGHTS records
|
||||
for (i = 0; i < NUMMAPS; i++)
|
||||
{
|
||||
if (!data->nightsrecords[i] || !data->nightsrecords[i]->nummares)
|
||||
{
|
||||
WRITEUINT8(save_p, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
WRITEUINT8(save_p, data->nightsrecords[i]->nummares);
|
||||
|
||||
for (curmare = 0; curmare < (data->nightsrecords[i]->nummares + 1); ++curmare)
|
||||
{
|
||||
WRITEUINT32(save_p, data->nightsrecords[i]->score[curmare]);
|
||||
WRITEUINT8(save_p, data->nightsrecords[i]->grade[curmare]);
|
||||
WRITEUINT32(save_p, data->nightsrecords[i]->time[curmare]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void P_NetUnArchiveEmblems(void)
|
||||
{
|
||||
gamedata_t *data = serverGamedata;
|
||||
INT32 i, j;
|
||||
UINT8 rtemp;
|
||||
UINT32 recscore;
|
||||
tic_t rectime;
|
||||
UINT16 recrings;
|
||||
UINT8 recmares;
|
||||
INT32 curmare;
|
||||
|
||||
if (READUINT32(save_p) != ARCHIVEBLOCK_EMBLEMS)
|
||||
I_Error("Bad $$$.sav at archive block Emblems");
|
||||
|
||||
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");
|
||||
if (numextraemblems != READINT32(save_p))
|
||||
I_Error("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,
|
||||
// then this prevents it from being saved over yours.
|
||||
data->loaded = false;
|
||||
|
||||
M_ClearSecrets(data);
|
||||
G_ClearRecords(data);
|
||||
|
||||
// The rest of this is lifted straight from G_LoadGameData in g_game.c
|
||||
// TODO: Optimize this to only read information about emblems, unlocks, etc. which actually exist
|
||||
// There is no need to go all the way up to MAXEMBLEMS when wads are guaranteed to be the same.
|
||||
|
||||
data->totalplaytime = READUINT32(save_p);
|
||||
|
||||
// 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");
|
||||
|
||||
// To save space, use one bit per collected/achieved/unlocked flag
|
||||
for (i = 0; i < MAXEMBLEMS;)
|
||||
{
|
||||
rtemp = READUINT8(save_p);
|
||||
for (j = 0; j < 8 && j+i < MAXEMBLEMS; ++j)
|
||||
data->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)
|
||||
data->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)
|
||||
data->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)
|
||||
data->achieved[j+i] = ((rtemp >> j) & 1);
|
||||
i += j;
|
||||
}
|
||||
|
||||
data->timesBeaten = READUINT32(save_p);
|
||||
data->timesBeatenWithEmeralds = READUINT32(save_p);
|
||||
data->timesBeatenUltimate = READUINT32(save_p);
|
||||
|
||||
// Main records
|
||||
for (i = 0; i < NUMMAPS; ++i)
|
||||
{
|
||||
recscore = READUINT32(save_p);
|
||||
rectime = (tic_t)READUINT32(save_p);
|
||||
recrings = READUINT16(save_p);
|
||||
|
||||
if (recrings > 10000 || recscore > MAXSCORE)
|
||||
I_Error("Bad $$$.sav dearchiving Emblems");
|
||||
|
||||
if (recscore || rectime || recrings)
|
||||
{
|
||||
G_AllocMainRecordData((INT16)i, data);
|
||||
data->mainrecords[i]->score = recscore;
|
||||
data->mainrecords[i]->time = rectime;
|
||||
data->mainrecords[i]->rings = recrings;
|
||||
}
|
||||
}
|
||||
|
||||
// Nights records
|
||||
for (i = 0; i < NUMMAPS; ++i)
|
||||
{
|
||||
if ((recmares = READUINT8(save_p)) == 0)
|
||||
continue;
|
||||
|
||||
G_AllocNightsRecordData((INT16)i, data);
|
||||
|
||||
for (curmare = 0; curmare < (recmares+1); ++curmare)
|
||||
{
|
||||
data->nightsrecords[i]->score[curmare] = READUINT32(save_p);
|
||||
data->nightsrecords[i]->grade[curmare] = READUINT8(save_p);
|
||||
data->nightsrecords[i]->time[curmare] = (tic_t)READUINT32(save_p);
|
||||
|
||||
if (data->nightsrecords[i]->grade[curmare] > GRADE_S)
|
||||
{
|
||||
I_Error("Bad $$$.sav dearchiving Emblems");
|
||||
}
|
||||
}
|
||||
|
||||
data->nightsrecords[i]->nummares = recmares;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void P_ArchiveLuabanksAndConsistency(void)
|
||||
{
|
||||
UINT8 i, banksinuse = NUM_LUABANKS;
|
||||
|
@ -4507,6 +4730,7 @@ void P_SaveNetGame(boolean resending)
|
|||
|
||||
CV_SaveNetVars(&save_p);
|
||||
P_NetArchiveMisc(resending);
|
||||
P_NetArchiveEmblems();
|
||||
|
||||
// Assign the mobjnumber for pointer tracking
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
|
@ -4559,6 +4783,7 @@ boolean P_LoadNetGame(boolean reloading)
|
|||
CV_LoadNetVars(&save_p);
|
||||
if (!P_NetUnArchiveMisc(reloading))
|
||||
return false;
|
||||
P_NetUnArchiveEmblems();
|
||||
P_NetUnArchivePlayers();
|
||||
if (gamestate == GS_LEVEL)
|
||||
{
|
||||
|
|
|
@ -7460,7 +7460,7 @@ static void P_WriteLetter(void)
|
|||
{
|
||||
char *buf, *b;
|
||||
|
||||
if (!unlockables[28].unlocked) // pandora's box
|
||||
if (!serverGamedata->unlocked[28]) // pandora's box
|
||||
return;
|
||||
|
||||
if (modeattacking)
|
||||
|
@ -7804,10 +7804,11 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
|
|||
nextmapoverride = 0;
|
||||
skipstats = 0;
|
||||
|
||||
if (!(netgame || multiplayer || demoplayback))
|
||||
mapvisited[gamemap-1] |= MV_VISITED;
|
||||
else if (netgame || multiplayer)
|
||||
mapvisited[gamemap-1] |= MV_MP; // you want to record that you've been there this session, but not permanently
|
||||
if (!demoplayback)
|
||||
{
|
||||
clientGamedata->mapvisited[gamemap-1] |= MV_VISITED;
|
||||
serverGamedata->mapvisited[gamemap-1] |= MV_VISITED;
|
||||
}
|
||||
|
||||
levelloading = false;
|
||||
|
||||
|
|
|
@ -2937,7 +2937,6 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
|
|||
break;
|
||||
|
||||
case 441: // Trigger unlockable
|
||||
if (!(netgame || multiplayer))
|
||||
{
|
||||
INT32 trigid = line->args[0];
|
||||
|
||||
|
@ -2948,10 +2947,12 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
|
|||
unlocktriggers |= 1 << trigid;
|
||||
|
||||
// Unlocked something?
|
||||
if (M_UpdateUnlockablesAndExtraEmblems())
|
||||
M_SilentUpdateUnlockablesAndEmblems(serverGamedata);
|
||||
|
||||
if (M_UpdateUnlockablesAndExtraEmblems(clientGamedata))
|
||||
{
|
||||
S_StartSound(NULL, sfx_s3k68);
|
||||
G_SaveGameData(); // only save if unlocked something
|
||||
G_SaveGameData(clientGamedata); // only save if unlocked something
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -675,7 +675,10 @@ void P_Ticker(boolean run)
|
|||
|
||||
// Keep track of how long they've been playing!
|
||||
if (!demoplayback) // Don't increment if a demo is playing.
|
||||
totalplaytime++;
|
||||
{
|
||||
clientGamedata->totalplaytime++;
|
||||
serverGamedata->totalplaytime++;
|
||||
}
|
||||
|
||||
if (!(maptol & TOL_NIGHTS) && G_IsSpecialStage(gamemap))
|
||||
P_DoSpecialStageStuff();
|
||||
|
|
|
@ -194,7 +194,7 @@ UINT32 R_GetSkinAvailabilities(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (unlockables[i].unlocked)
|
||||
if (clientGamedata->unlocked[i])
|
||||
{
|
||||
response |= (1 << unlockShift);
|
||||
}
|
||||
|
@ -242,11 +242,12 @@ boolean R_SkinUsable(INT32 playernum, INT32 skinnum)
|
|||
// Force 3.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (playernum != -1 && players[playernum].bot)
|
||||
{
|
||||
//Force 4.
|
||||
return true;
|
||||
}
|
||||
{
|
||||
// Force 4.
|
||||
return true;
|
||||
}
|
||||
|
||||
// We will now check if this skin is supposed to be locked or not.
|
||||
|
||||
|
@ -284,7 +285,7 @@ boolean R_SkinUsable(INT32 playernum, INT32 skinnum)
|
|||
else
|
||||
{
|
||||
// We want to check our global unlockables.
|
||||
return (unlockables[unlockID].unlocked);
|
||||
return (clientGamedata->unlocked[unlockID]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1692,6 +1692,7 @@ UINT8 soundtestpage = 1;
|
|||
//
|
||||
boolean S_PrepareSoundTest(void)
|
||||
{
|
||||
gamedata_t *data = clientGamedata;
|
||||
musicdef_t *def;
|
||||
INT32 pos = numsoundtestdefs = 0;
|
||||
|
||||
|
@ -1717,9 +1718,9 @@ boolean S_PrepareSoundTest(void)
|
|||
if (!(def->soundtestpage & soundtestpage))
|
||||
continue;
|
||||
soundtestdefs[pos++] = def;
|
||||
if (def->soundtestcond > 0 && !(mapvisited[def->soundtestcond-1] & MV_BEATEN))
|
||||
if (def->soundtestcond > 0 && !(data->mapvisited[def->soundtestcond-1] & MV_BEATEN))
|
||||
continue;
|
||||
if (def->soundtestcond < 0 && !M_Achieved(-1-def->soundtestcond))
|
||||
if (def->soundtestcond < 0 && !M_Achieved(-1-def->soundtestcond, data))
|
||||
continue;
|
||||
def->allowed = true;
|
||||
}
|
||||
|
|
|
@ -2352,7 +2352,7 @@ void I_Quit(void)
|
|||
#ifndef NONET
|
||||
D_SaveBan(); // save the ban list
|
||||
#endif
|
||||
G_SaveGameData(); // Tails 12-08-2002
|
||||
G_SaveGameData(clientGamedata); // Tails 12-08-2002
|
||||
//added:16-02-98: when recording a demo, should exit using 'q' key,
|
||||
// but sometimes we forget and use 'F10'.. so save here too.
|
||||
|
||||
|
@ -2436,7 +2436,7 @@ void I_Error(const char *error, ...)
|
|||
if (errorcount == 8)
|
||||
{
|
||||
M_SaveConfig(NULL);
|
||||
G_SaveGameData();
|
||||
G_SaveGameData(clientGamedata);
|
||||
}
|
||||
if (errorcount > 20)
|
||||
{
|
||||
|
@ -2469,7 +2469,7 @@ void I_Error(const char *error, ...)
|
|||
#ifndef NONET
|
||||
D_SaveBan(); // save the ban list
|
||||
#endif
|
||||
G_SaveGameData(); // Tails 12-08-2002
|
||||
G_SaveGameData(clientGamedata); // Tails 12-08-2002
|
||||
|
||||
// Shutdown. Here might be other errors.
|
||||
if (demorecording)
|
||||
|
|
|
@ -1697,7 +1697,7 @@ static void ST_drawNightsRecords(void)
|
|||
ST_DrawNightsOverlayNum((BASEVIDWIDTH/2 + 56)<<FRACBITS, 160<<FRACBITS, FRACUNIT, aflag, stplyr->lastmarescore, nightsnum, SKINCOLOR_AZURE);
|
||||
|
||||
// If new record, say so!
|
||||
if (!(netgame || multiplayer) && G_GetBestNightsScore(gamemap, stplyr->lastmare + 1) <= stplyr->lastmarescore)
|
||||
if (!(netgame || multiplayer) && G_GetBestNightsScore(gamemap, stplyr->lastmare + 1, clientGamedata) <= stplyr->lastmarescore)
|
||||
{
|
||||
if (stplyr->texttimer & 16)
|
||||
V_DrawCenteredString(BASEVIDWIDTH/2, 184, V_YELLOWMAP|aflag, "* NEW RECORD *");
|
||||
|
@ -2563,8 +2563,11 @@ static void ST_doItemFinderIconsAndSound(void)
|
|||
|
||||
emblems[stemblems++] = i;
|
||||
|
||||
if (!emblemlocations[i].collected)
|
||||
if (!(clientGamedata->collected[i] && serverGamedata->collected[i]))
|
||||
{
|
||||
// It can be worth collecting again if the server doesn't have it.
|
||||
++stunfound;
|
||||
}
|
||||
|
||||
if (stemblems >= 16)
|
||||
break;
|
||||
|
@ -2723,7 +2726,7 @@ static void ST_overlayDrawer(void)
|
|||
ST_drawRaceHUD();
|
||||
|
||||
// Emerald Hunt Indicators
|
||||
if (cv_itemfinder.value && M_SecretUnlocked(SECRET_ITEMFINDER))
|
||||
if (cv_itemfinder.value && M_SecretUnlocked(SECRET_ITEMFINDER, clientGamedata))
|
||||
ST_doItemFinderIconsAndSound();
|
||||
else
|
||||
ST_doHuntIconsAndSound();
|
||||
|
|
|
@ -1092,12 +1092,14 @@ void Y_Ticker(void)
|
|||
S_StartSound(NULL, (gottoken ? sfx_token : sfx_chchng)); // cha-ching!
|
||||
|
||||
// Update when done with tally
|
||||
if (!(netgame || multiplayer) && !demoplayback)
|
||||
if (!demoplayback)
|
||||
{
|
||||
if (M_UpdateUnlockablesAndExtraEmblems())
|
||||
M_SilentUpdateUnlockablesAndEmblems(serverGamedata);
|
||||
|
||||
if (M_UpdateUnlockablesAndExtraEmblems(clientGamedata))
|
||||
S_StartSound(NULL, sfx_s3k68);
|
||||
|
||||
G_SaveGameData();
|
||||
G_SaveGameData(clientGamedata);
|
||||
}
|
||||
}
|
||||
else if (!(intertic & 1))
|
||||
|
@ -1228,12 +1230,14 @@ void Y_Ticker(void)
|
|||
S_StartSound(NULL, (gottoken ? sfx_token : sfx_chchng)); // cha-ching!
|
||||
|
||||
// Update when done with tally
|
||||
if (!(netgame || multiplayer) && !demoplayback)
|
||||
if (!demoplayback)
|
||||
{
|
||||
if (M_UpdateUnlockablesAndExtraEmblems())
|
||||
M_SilentUpdateUnlockablesAndEmblems(serverGamedata);
|
||||
|
||||
if (M_UpdateUnlockablesAndExtraEmblems(clientGamedata))
|
||||
S_StartSound(NULL, sfx_s3k68);
|
||||
|
||||
G_SaveGameData();
|
||||
G_SaveGameData(clientGamedata);
|
||||
}
|
||||
}
|
||||
else if (!(intertic & 1))
|
||||
|
|
Loading…
Reference in a new issue