mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Merge branch 'gamedata-extension' into 'master'
Gamedata Extensions See merge request KartKrew/Kart!1262
This commit is contained in:
commit
9724144e99
37 changed files with 1223 additions and 418 deletions
|
|
@ -264,16 +264,12 @@ static bool ACS_GetStateFromString(const char *word, statenum_t *type)
|
|||
--------------------------------------------------*/
|
||||
static bool ACS_GetSkinFromString(const char *word, INT32 *type)
|
||||
{
|
||||
for (int i = 0; i < numskins; i++)
|
||||
{
|
||||
if (fastcmp(word, skins[i].name))
|
||||
{
|
||||
*type = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
INT32 skin = R_SkinAvailable(word);
|
||||
if (skin == -1)
|
||||
return false;
|
||||
|
||||
return false;
|
||||
*type = skin;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
|
|
@ -293,7 +289,7 @@ static bool ACS_GetColorFromString(const char *word, skincolornum_t *type)
|
|||
{
|
||||
for (int i = 0; i < numskincolors; i++)
|
||||
{
|
||||
if (fastcmp(word, skins[i].name))
|
||||
if (fastcmp(word, skincolors[i].name))
|
||||
{
|
||||
*type = static_cast<skincolornum_t>(i);
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -2051,7 +2051,7 @@ static void CV_SetValueMaybeStealth(consvar_t *var, INT32 value, boolean stealth
|
|||
tmpskin = "None";
|
||||
else
|
||||
tmpskin = skins[value].name;
|
||||
strncpy(val, tmpskin, SKINNAMESIZE);
|
||||
strlcpy(val, tmpskin, SKINNAMESIZE+1);
|
||||
}
|
||||
else
|
||||
sprintf(val, "%d", value);
|
||||
|
|
|
|||
41
src/d_main.c
41
src/d_main.c
|
|
@ -1851,6 +1851,47 @@ void D_SRB2Main(void)
|
|||
{
|
||||
PR_ApplyProfile(cv_ttlprofilen.value, 0);
|
||||
|
||||
if (gamedata->importprofilewins == true)
|
||||
{
|
||||
profile_t *pr = PR_GetProfile(cv_ttlprofilen.value);
|
||||
if (pr != NULL)
|
||||
{
|
||||
INT32 importskin = R_SkinAvailable(pr->skinname);
|
||||
if (importskin != -1)
|
||||
{
|
||||
skins[importskin].records.wins = pr->wins;
|
||||
|
||||
cupheader_t *cup;
|
||||
for (cup = kartcupheaders; cup; cup = cup->next)
|
||||
{
|
||||
for (i = 0; i < KARTGP_MAX; i++)
|
||||
{
|
||||
if (cup->windata[i].best_placement == 0)
|
||||
continue;
|
||||
cup->windata[i].best_skin.id = importskin;
|
||||
cup->windata[i].best_skin.unloaded = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
unloaded_cupheader_t *unloadedcup;
|
||||
for (unloadedcup = unloadedcupheaders; unloadedcup; unloadedcup = unloadedcup->next)
|
||||
{
|
||||
for (i = 0; i < KARTGP_MAX; i++)
|
||||
{
|
||||
if (unloadedcup->windata[i].best_placement == 0)
|
||||
continue;
|
||||
unloadedcup->windata[i].best_skin.id = importskin;
|
||||
unloadedcup->windata[i].best_skin.unloaded = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
CONS_Printf(" Wins for profile \"%s\" imported onto character \"%s\"\n", pr->profilename, skins[importskin].name);
|
||||
}
|
||||
}
|
||||
|
||||
gamedata->importprofilewins = false;
|
||||
}
|
||||
|
||||
for (i = 1; i < cv_splitplayers.value; i++)
|
||||
{
|
||||
PR_ApplyProfile(cv_lastprofile[i].value, i);
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ void clear_unlockables(void)
|
|||
|
||||
void clear_conditionsets(void)
|
||||
{
|
||||
UINT8 i;
|
||||
UINT16 i;
|
||||
for (i = 0; i < MAXCONDITIONSETS; ++i)
|
||||
M_ClearConditionSet(i);
|
||||
}
|
||||
|
|
@ -192,8 +192,6 @@ void clear_levels(void)
|
|||
|
||||
P_DeleteHeaderFollowers(nummapheaders);
|
||||
|
||||
Z_Free(mapheaderinfo[nummapheaders]->mainrecord);
|
||||
|
||||
Patch_Free(mapheaderinfo[nummapheaders]->thumbnailPic);
|
||||
Patch_Free(mapheaderinfo[nummapheaders]->minimapPic);
|
||||
|
||||
|
|
@ -952,7 +950,46 @@ void readlevelheader(MYFILE *f, char * name)
|
|||
|
||||
if (mapheaderinfo[num]->lumpname == NULL)
|
||||
{
|
||||
mapheaderinfo[num]->lumpname = Z_StrDup(name);
|
||||
mapheaderinfo[num]->lumpnamehash = quickncasehash(name, MAXMAPLUMPNAME);
|
||||
|
||||
// Check to see if we have any custom map record data that we could substitute in.
|
||||
unloaded_mapheader_t *unloadedmap, *prev = NULL;
|
||||
for (unloadedmap = unloadedmapheaders; unloadedmap; prev = unloadedmap, unloadedmap = unloadedmap->next)
|
||||
{
|
||||
if (unloadedmap->lumpnamehash != mapheaderinfo[num]->lumpnamehash)
|
||||
continue;
|
||||
|
||||
if (strcasecmp(name, unloadedmap->lumpname) != 0)
|
||||
continue;
|
||||
|
||||
// Copy in mapvisited, time, lap, etc.
|
||||
unloadedmap->records.mapvisited &= MV_MAX;
|
||||
M_Memcpy(&mapheaderinfo[num]->records, &unloadedmap->records, sizeof(recorddata_t));
|
||||
|
||||
// Reuse the zone-allocated lumpname string.
|
||||
mapheaderinfo[num]->lumpname = unloadedmap->lumpname;
|
||||
|
||||
// Remove this entry from the chain.
|
||||
if (prev)
|
||||
{
|
||||
prev->next = unloadedmap->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
unloadedmapheaders = unloadedmap->next;
|
||||
}
|
||||
|
||||
// Finally, free.
|
||||
Z_Free(unloadedmap);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (mapheaderinfo[num]->lumpname == NULL)
|
||||
{
|
||||
// If there was no string to reuse, dup our own.
|
||||
mapheaderinfo[num]->lumpname = Z_StrDup(name);
|
||||
}
|
||||
}
|
||||
|
||||
do
|
||||
|
|
@ -2280,9 +2317,9 @@ void readunlockable(MYFILE *f, INT32 num)
|
|||
strupr(word2);
|
||||
|
||||
if (fastcmp(word, "CONDITIONSET"))
|
||||
unlockables[num].conditionset = (UINT8)i;
|
||||
unlockables[num].conditionset = (UINT16)i;
|
||||
else if (fastcmp(word, "MAJORUNLOCK"))
|
||||
unlockables[num].majorunlock = (UINT8)(i || word2[0] == 'T' || word2[0] == 'Y');
|
||||
unlockables[num].majorunlock = (UINT8)(i != 0 || word2[0] == 'T' || word2[0] == 'Y');
|
||||
else if (fastcmp(word, "TYPE"))
|
||||
{
|
||||
if (fastcmp(word2, "NONE"))
|
||||
|
|
@ -2638,9 +2675,10 @@ static void readcondition(UINT8 set, UINT32 id, char *word2)
|
|||
ty = UCRP_PODIUMCUP;
|
||||
{
|
||||
cupheader_t *cup = kartcupheaders;
|
||||
UINT32 hash = quickncasehash(params[1], MAXCUPNAME);
|
||||
while (cup)
|
||||
{
|
||||
if (!strcmp(cup->name, params[1]))
|
||||
if (hash == cup->namehash && !strcmp(cup->name, params[1]))
|
||||
break;
|
||||
cup = cup->next;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -465,39 +465,81 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
|
|||
//
|
||||
else if (fastcmp(word, "CUP"))
|
||||
{
|
||||
cupheader_t *cup = kartcupheaders;
|
||||
cupheader_t *prev = NULL;
|
||||
|
||||
while (cup)
|
||||
size_t len = strlen(word2);
|
||||
if (len <= MAXCUPNAME-1)
|
||||
{
|
||||
if (fastcmp(cup->name, word2))
|
||||
cupheader_t *cup = kartcupheaders;
|
||||
cupheader_t *prev = NULL;
|
||||
UINT32 hash = quickncasehash(word2, MAXCUPNAME);
|
||||
|
||||
while (cup)
|
||||
{
|
||||
// Only a major mod if editing stuff that isn't your own!
|
||||
G_SetGameModified(multiplayer, true);
|
||||
break;
|
||||
if (hash == cup->namehash && fastcmp(cup->name, word2))
|
||||
{
|
||||
// Only a major mod if editing stuff that isn't your own!
|
||||
G_SetGameModified(multiplayer, true);
|
||||
break;
|
||||
}
|
||||
|
||||
prev = cup;
|
||||
cup = cup->next;
|
||||
}
|
||||
|
||||
prev = cup;
|
||||
cup = cup->next;
|
||||
}
|
||||
// Nothing found, add to the end.
|
||||
if (!cup)
|
||||
{
|
||||
cup = Z_Calloc(sizeof (cupheader_t), PU_STATIC, NULL);
|
||||
cup->id = numkartcupheaders;
|
||||
cup->monitor = 1;
|
||||
deh_strlcpy(cup->name, word2,
|
||||
sizeof(cup->name), va("Cup header %s: name", word2));
|
||||
cup->namehash = hash;
|
||||
|
||||
// Nothing found, add to the end.
|
||||
if (!cup)
|
||||
// Check to see if we have any custom cup record data that we could substitute in.
|
||||
unloaded_cupheader_t *unloadedcup, *unloadedprev = NULL;
|
||||
for (unloadedcup = unloadedcupheaders; unloadedcup; unloadedprev = unloadedcup, unloadedcup = unloadedcup->next)
|
||||
{
|
||||
if (unloadedcup->namehash != hash)
|
||||
continue;
|
||||
|
||||
if (strcasecmp(word2, unloadedcup->name) != 0)
|
||||
continue;
|
||||
|
||||
// Copy in standings, etc.
|
||||
M_Memcpy(&cup->windata, &unloadedcup->windata, sizeof(cup->windata));
|
||||
|
||||
// Remove this entry from the chain.
|
||||
if (unloadedprev)
|
||||
{
|
||||
unloadedprev->next = unloadedcup->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
unloadedcupheaders = unloadedcup->next;
|
||||
}
|
||||
|
||||
// Finally, free.
|
||||
Z_Free(unloadedcup);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (prev != NULL)
|
||||
prev->next = cup;
|
||||
if (kartcupheaders == NULL)
|
||||
kartcupheaders = cup;
|
||||
numkartcupheaders++;
|
||||
CONS_Printf("Added cup %d ('%s')\n", cup->id, cup->name);
|
||||
}
|
||||
|
||||
readcupheader(f, cup);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
cup = Z_Calloc(sizeof (cupheader_t), PU_STATIC, NULL);
|
||||
cup->id = numkartcupheaders;
|
||||
cup->monitor = 1;
|
||||
deh_strlcpy(cup->name, word2,
|
||||
sizeof(cup->name), va("Cup header %s: name", word2));
|
||||
if (prev != NULL)
|
||||
prev->next = cup;
|
||||
if (kartcupheaders == NULL)
|
||||
kartcupheaders = cup;
|
||||
numkartcupheaders++;
|
||||
CONS_Printf("Added cup %d ('%s')\n", cup->id, cup->name);
|
||||
deh_warning("Cup header's name %s is too long (%s characters VS %d max)", word2, sizeu1(len), (MAXCUPNAME-1));
|
||||
ignorelines(f);
|
||||
}
|
||||
|
||||
readcupheader(f, cup);
|
||||
}
|
||||
else if (fastcmp(word, "WEATHER") || fastcmp(word, "PRECIP") || fastcmp(word, "PRECIPITATION"))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -112,12 +112,47 @@ extern preciptype_t curWeather;
|
|||
|
||||
/** Time attack information, currently a very small structure.
|
||||
*/
|
||||
|
||||
struct skinrecord_t
|
||||
{
|
||||
UINT32 wins;
|
||||
|
||||
// Purely assistive in gamedata save processes
|
||||
UINT32 _saveid;
|
||||
};
|
||||
|
||||
struct unloaded_skin_t
|
||||
{
|
||||
char name[SKINNAMESIZE+1];
|
||||
UINT32 namehash;
|
||||
|
||||
skinrecord_t records;
|
||||
|
||||
unloaded_skin_t *next;
|
||||
};
|
||||
|
||||
extern unloaded_skin_t *unloadedskins;
|
||||
|
||||
struct skinreference_t
|
||||
{
|
||||
unloaded_skin_t *unloaded;
|
||||
UINT8 id;
|
||||
};
|
||||
|
||||
// mapvisited is now a set of flags that says what we've done in the map.
|
||||
#define MV_VISITED (1)
|
||||
#define MV_BEATEN (1<<1)
|
||||
#define MV_ENCORE (1<<2)
|
||||
#define MV_SPBATTACK (1<<3)
|
||||
#define MV_MAX (MV_VISITED|MV_BEATEN|MV_ENCORE|MV_SPBATTACK)
|
||||
#define MV_FINISHNEEDED (1<<7)
|
||||
#define MV_PERSISTUNLOADED (MV_SPBATTACK|MV_FINISHNEEDED)
|
||||
|
||||
struct recorddata_t
|
||||
{
|
||||
UINT8 mapvisited;
|
||||
tic_t time; ///< Time in which the level was finished.
|
||||
tic_t lap; ///< Best lap time for this level.
|
||||
//UINT32 score; ///< Score when the level was finished.
|
||||
//UINT16 rings; ///< Rings when the level was finished.
|
||||
};
|
||||
|
||||
#define KARTSPEED_AUTO -1
|
||||
|
|
@ -142,16 +177,9 @@ struct cupwindata_t
|
|||
UINT8 best_placement;
|
||||
gp_rank_e best_grade;
|
||||
boolean got_emerald;
|
||||
skinreference_t best_skin;
|
||||
};
|
||||
|
||||
// mapvisited is now a set of flags that says what we've done in the map.
|
||||
#define MV_VISITED (1)
|
||||
#define MV_BEATEN (1<<1)
|
||||
#define MV_ENCORE (1<<2)
|
||||
#define MV_SPBATTACK (1<<3)
|
||||
#define MV_MAX (MV_VISITED|MV_BEATEN|MV_ENCORE|MV_SPBATTACK)
|
||||
#define MV_MP ((MV_MAX+1)<<1)
|
||||
|
||||
// Set if homebrew PWAD stuff has been added.
|
||||
extern boolean modifiedgame;
|
||||
extern boolean majormods;
|
||||
|
|
@ -363,11 +391,16 @@ struct customoption_t
|
|||
#define CUPCACHE_SPECIAL (CUPCACHE_BONUS+MAXBONUSLIST)
|
||||
#define CUPCACHE_MAX (CUPCACHE_SPECIAL+1)
|
||||
|
||||
#define MAXCUPNAME 16 // includes \0, for cleaner savedata
|
||||
|
||||
struct cupheader_t
|
||||
{
|
||||
UINT16 id; ///< Cup ID
|
||||
UINT8 monitor; ///< Monitor graphic 1-9 or A-Z
|
||||
char name[15]; ///< Cup title (14 chars)
|
||||
|
||||
char name[MAXCUPNAME]; ///< Cup title
|
||||
UINT32 namehash; ///< Cup title hash
|
||||
|
||||
char icon[9]; ///< Name of the icon patch
|
||||
char *levellist[CUPCACHE_MAX]; ///< List of levels that belong to this cup
|
||||
INT16 cachedlevels[CUPCACHE_MAX]; ///< IDs in levellist, bonusgame, and specialstage
|
||||
|
|
@ -381,6 +414,18 @@ struct cupheader_t
|
|||
extern cupheader_t *kartcupheaders; // Start of cup linked list
|
||||
extern UINT16 numkartcupheaders;
|
||||
|
||||
struct unloaded_cupheader_t
|
||||
{
|
||||
char name[MAXCUPNAME];
|
||||
UINT32 namehash;
|
||||
|
||||
cupwindata_t windata[4];
|
||||
|
||||
unloaded_cupheader_t *next;
|
||||
};
|
||||
|
||||
extern unloaded_cupheader_t *unloadedcupheaders;
|
||||
|
||||
#define MAXMAPLUMPNAME 64 // includes \0, for cleaner savedata
|
||||
#define MAXSTAFF 3
|
||||
|
||||
|
|
@ -400,6 +445,7 @@ struct mapheader_t
|
|||
{
|
||||
// Core game information, not user-modifiable directly
|
||||
char *lumpname; ///< Lump name can be really long
|
||||
UINT32 lumpnamehash; ///< quickncasehash(->lumpname, MAXMAPLUMPNAME)
|
||||
lumpnum_t lumpnum; ///< Lump number for the map, used by vres_GetMap
|
||||
|
||||
void *thumbnailPic; ///< Lump data for the level select thumbnail.
|
||||
|
|
@ -411,8 +457,7 @@ struct mapheader_t
|
|||
UINT8 ghostCount; ///< Count of valid staff ghosts
|
||||
staffbrief_t *ghostBrief[MAXSTAFF]; ///< Mallocated array of names for each staff ghost
|
||||
|
||||
UINT8 mapvisited; ///< A set of flags that says what we've done in the map.
|
||||
recorddata_t *mainrecord; ///< Stores best time attack data
|
||||
recorddata_t records; ///< Stores completion/record attack data
|
||||
|
||||
cupheader_t *cup; ///< Cached cup
|
||||
|
||||
|
|
@ -496,6 +541,18 @@ struct mapheader_t
|
|||
extern mapheader_t** mapheaderinfo;
|
||||
extern INT32 nummapheaders, mapallocsize;
|
||||
|
||||
struct unloaded_mapheader_t
|
||||
{
|
||||
char *lumpname;
|
||||
UINT32 lumpnamehash;
|
||||
|
||||
recorddata_t records;
|
||||
|
||||
unloaded_mapheader_t *next;
|
||||
};
|
||||
|
||||
extern unloaded_mapheader_t *unloadedmapheaders;
|
||||
|
||||
// Gametypes
|
||||
#define NUMGAMETYPEFREESLOTS (128)
|
||||
#define MAXGAMETYPELENGTH (32)
|
||||
|
|
|
|||
662
src/g_game.c
662
src/g_game.c
|
|
@ -200,10 +200,14 @@ mapheader_t** mapheaderinfo = {NULL};
|
|||
INT32 nummapheaders = 0;
|
||||
INT32 mapallocsize = 0;
|
||||
|
||||
unloaded_mapheader_t *unloadedmapheaders = NULL;
|
||||
|
||||
// Kart cup definitions
|
||||
cupheader_t *kartcupheaders = NULL;
|
||||
UINT16 numkartcupheaders = 0;
|
||||
|
||||
unloaded_cupheader_t *unloadedcupheaders = NULL;
|
||||
|
||||
static boolean exitgame = false;
|
||||
static boolean retrying = false;
|
||||
static boolean retryingmodeattack = false;
|
||||
|
|
@ -444,44 +448,60 @@ consvar_t cv_rumble[MAXSPLITSCREENPLAYERS] = {
|
|||
char player_names[MAXPLAYERS][MAXPLAYERNAME+1];
|
||||
INT32 player_name_changes[MAXPLAYERS];
|
||||
|
||||
// Allocation for time and nights data
|
||||
void G_AllocMainRecordData(INT16 i)
|
||||
{
|
||||
if (i > nummapheaders || !mapheaderinfo[i])
|
||||
I_Error("G_AllocMainRecordData: Internal map ID %d not found (nummapheaders = %d)\n", i, nummapheaders);
|
||||
if (!mapheaderinfo[i]->mainrecord)
|
||||
mapheaderinfo[i]->mainrecord = Z_Malloc(sizeof(recorddata_t), PU_STATIC, NULL);
|
||||
memset(mapheaderinfo[i]->mainrecord, 0, sizeof(recorddata_t));
|
||||
}
|
||||
|
||||
// MAKE SURE YOU SAVE DATA BEFORE CALLING THIS
|
||||
void G_ClearRecords(void)
|
||||
{
|
||||
INT16 i;
|
||||
cupheader_t *cup;
|
||||
UINT16 i;
|
||||
|
||||
for (i = 0; i < nummapheaders; ++i)
|
||||
for (i = 0; i < numskins; i++)
|
||||
{
|
||||
if (mapheaderinfo[i]->mainrecord)
|
||||
{
|
||||
Z_Free(mapheaderinfo[i]->mainrecord);
|
||||
mapheaderinfo[i]->mainrecord = NULL;
|
||||
}
|
||||
memset(&skins[i].records, 0, sizeof(skins[i].records));
|
||||
}
|
||||
|
||||
for (i = 0; i < nummapheaders; i++)
|
||||
{
|
||||
memset(&mapheaderinfo[i]->records, 0, sizeof(recorddata_t));
|
||||
}
|
||||
|
||||
cupheader_t *cup;
|
||||
for (cup = kartcupheaders; cup; cup = cup->next)
|
||||
{
|
||||
memset(&cup->windata, 0, sizeof(cup->windata));
|
||||
}
|
||||
|
||||
unloaded_skin_t *unloadedskin, *nextunloadedskin = NULL;
|
||||
for (unloadedskin = unloadedskins; unloadedskin; unloadedskin = nextunloadedskin)
|
||||
{
|
||||
nextunloadedskin = unloadedskin->next;
|
||||
Z_Free(unloadedskin);
|
||||
}
|
||||
unloadedskins = NULL;
|
||||
|
||||
unloaded_mapheader_t *unloadedmap, *nextunloadedmap = NULL;
|
||||
for (unloadedmap = unloadedmapheaders; unloadedmap; unloadedmap = nextunloadedmap)
|
||||
{
|
||||
nextunloadedmap = unloadedmap->next;
|
||||
Z_Free(unloadedmap->lumpname);
|
||||
Z_Free(unloadedmap);
|
||||
}
|
||||
unloadedmapheaders = NULL;
|
||||
|
||||
unloaded_cupheader_t *unloadedcup, *nextunloadedcup = NULL;
|
||||
for (unloadedcup = unloadedcupheaders; unloadedcup; unloadedcup = nextunloadedcup)
|
||||
{
|
||||
nextunloadedcup = unloadedcup->next;
|
||||
Z_Free(unloadedcup);
|
||||
}
|
||||
unloadedcupheaders = NULL;
|
||||
}
|
||||
|
||||
// For easy retrieval of records
|
||||
tic_t G_GetBestTime(INT16 map)
|
||||
{
|
||||
if (!mapheaderinfo[map] || !mapheaderinfo[map]->mainrecord || mapheaderinfo[map]->mainrecord->time <= 0)
|
||||
if (!mapheaderinfo[map] || mapheaderinfo[map]->records.time <= 0)
|
||||
return (tic_t)UINT32_MAX;
|
||||
|
||||
return mapheaderinfo[map]->mainrecord->time;
|
||||
return mapheaderinfo[map]->records.time;
|
||||
}
|
||||
|
||||
// BE RIGHT BACK
|
||||
|
|
@ -490,10 +510,10 @@ tic_t G_GetBestTime(INT16 map)
|
|||
/*
|
||||
tic_t G_GetBestLap(INT16 map)
|
||||
{
|
||||
if (!mapheaderinfo[map] || !mapheaderinfo[map]->mainrecord || mapheaderinfo[map]->mainrecord->lap <= 0)
|
||||
if (!mapheaderinfo[map] || mapheaderinfo[map]->records.lap <= 0)
|
||||
return (tic_t)UINT32_MAX;
|
||||
|
||||
return mapheaderinfo[map]->mainrecord->lap;
|
||||
return mapheaderinfo[map]->records.lap;
|
||||
}
|
||||
*/
|
||||
|
||||
|
|
@ -621,32 +641,28 @@ void G_UpdateRecords(void)
|
|||
{
|
||||
UINT8 earnedEmblems;
|
||||
|
||||
// Record new best time
|
||||
if (!mapheaderinfo[gamemap-1]->mainrecord)
|
||||
G_AllocMainRecordData(gamemap-1);
|
||||
|
||||
if (modeattacking & ATTACKING_TIME)
|
||||
{
|
||||
tic_t time = players[consoleplayer].realtime;
|
||||
if (players[consoleplayer].pflags & PF_NOCONTEST)
|
||||
time = UINT32_MAX;
|
||||
if (((mapheaderinfo[gamemap-1]->mainrecord->time == 0) || (time < mapheaderinfo[gamemap-1]->mainrecord->time))
|
||||
if (((mapheaderinfo[gamemap-1]->records.time == 0) || (time < mapheaderinfo[gamemap-1]->records.time))
|
||||
&& (time < UINT32_MAX)) // DNF
|
||||
mapheaderinfo[gamemap-1]->mainrecord->time = time;
|
||||
mapheaderinfo[gamemap-1]->records.time = time;
|
||||
}
|
||||
else
|
||||
{
|
||||
mapheaderinfo[gamemap-1]->mainrecord->time = 0;
|
||||
mapheaderinfo[gamemap-1]->records.time = 0;
|
||||
}
|
||||
|
||||
if (modeattacking & ATTACKING_LAP)
|
||||
{
|
||||
if ((mapheaderinfo[gamemap-1]->mainrecord->lap == 0) || (bestlap < mapheaderinfo[gamemap-1]->mainrecord->lap))
|
||||
mapheaderinfo[gamemap-1]->mainrecord->lap = bestlap;
|
||||
if ((mapheaderinfo[gamemap-1]->records.lap == 0) || (bestlap < mapheaderinfo[gamemap-1]->records.lap))
|
||||
mapheaderinfo[gamemap-1]->records.lap = bestlap;
|
||||
}
|
||||
else
|
||||
{
|
||||
mapheaderinfo[gamemap-1]->mainrecord->lap = 0;
|
||||
mapheaderinfo[gamemap-1]->records.lap = 0;
|
||||
}
|
||||
|
||||
// Check emblems when level data is updated
|
||||
|
|
@ -807,9 +823,13 @@ INT32 G_MapNumber(const char * name)
|
|||
#endif
|
||||
{
|
||||
INT32 map;
|
||||
UINT32 hash = quickncasehash(name, MAXMAPLUMPNAME);
|
||||
|
||||
for (map = 0; map < nummapheaders; ++map)
|
||||
{
|
||||
if (hash != mapheaderinfo[map]->lumpnamehash)
|
||||
continue;
|
||||
|
||||
if (strcasecmp(mapheaderinfo[map]->lumpname, name) != 0)
|
||||
continue;
|
||||
|
||||
|
|
@ -3982,16 +4002,16 @@ static void G_UpdateVisited(void)
|
|||
return;
|
||||
|
||||
// Update visitation flags
|
||||
mapheaderinfo[prevmap]->mapvisited |= MV_BEATEN;
|
||||
mapheaderinfo[prevmap]->records.mapvisited |= MV_BEATEN;
|
||||
|
||||
if (encoremode == true)
|
||||
{
|
||||
mapheaderinfo[prevmap]->mapvisited |= MV_ENCORE;
|
||||
mapheaderinfo[prevmap]->records.mapvisited |= MV_ENCORE;
|
||||
}
|
||||
|
||||
if (modeattacking & ATTACKING_SPB)
|
||||
{
|
||||
mapheaderinfo[prevmap]->mapvisited |= MV_SPBATTACK;
|
||||
mapheaderinfo[prevmap]->records.mapvisited |= MV_SPBATTACK;
|
||||
}
|
||||
|
||||
if (modeattacking)
|
||||
|
|
@ -4446,6 +4466,7 @@ static void G_DoCompleted(void)
|
|||
|
||||
grandprixinfo.rank.prisons += numtargets;
|
||||
grandprixinfo.rank.position = MAXPLAYERS;
|
||||
grandprixinfo.rank.skin = MAXSKINS;
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
|
|
@ -4475,7 +4496,12 @@ static void G_DoCompleted(void)
|
|||
|
||||
if (players[i].bot == false)
|
||||
{
|
||||
grandprixinfo.rank.position = min(grandprixinfo.rank.position, K_GetPodiumPosition(&players[i]));
|
||||
UINT8 podiumposition = K_GetPodiumPosition(&players[i]);
|
||||
if (podiumposition <= grandprixinfo.rank.position)
|
||||
{
|
||||
grandprixinfo.rank.position = podiumposition;
|
||||
grandprixinfo.rank.skin = players[i].skin;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4746,7 +4772,7 @@ void G_LoadGameSettings(void)
|
|||
}
|
||||
|
||||
#define GD_VERSIONCHECK 0xBA5ED123 // Change every major version, as usual
|
||||
#define GD_VERSIONMINOR 2 // Change every format update
|
||||
#define GD_VERSIONMINOR 3 // Change every format update
|
||||
|
||||
static const char *G_GameDataFolder(void)
|
||||
{
|
||||
|
|
@ -4767,7 +4793,13 @@ void G_LoadGameData(void)
|
|||
boolean gridunusable = false;
|
||||
savebuffer_t save = {0};
|
||||
|
||||
UINT16 emblemreadcount = MAXEMBLEMS;
|
||||
UINT16 unlockreadcount = MAXUNLOCKABLES;
|
||||
UINT16 conditionreadcount = MAXCONDITIONSETS;
|
||||
size_t unlockreadsize = sizeof(UINT16);
|
||||
|
||||
//For records
|
||||
UINT32 numgamedataskins;
|
||||
UINT32 numgamedatamapheaders;
|
||||
UINT32 numgamedatacups;
|
||||
|
||||
|
|
@ -4819,6 +4851,12 @@ void G_LoadGameData(void)
|
|||
P_SaveBufferFree(&save);
|
||||
I_Error("Game data is from the future! (expected %d, got %d)\nRename or delete %s (maybe in %s) and try again.", GD_VERSIONMINOR, versionMinor, gamedatafilename, gdfolder);
|
||||
}
|
||||
else if (versionMinor < GD_VERSIONMINOR)
|
||||
{
|
||||
// We're converting - let'd create a backup.
|
||||
FIL_WriteFile(va("%s" PATHSEP "%s.bak", srb2home, gamedatafilename), save.buffer, save.size);
|
||||
}
|
||||
|
||||
if ((versionMinor == 0 || versionMinor == 1)
|
||||
#ifdef DEVELOP
|
||||
|| M_CheckParm("-resetchallengegrid")
|
||||
|
|
@ -4846,7 +4884,16 @@ void G_LoadGameData(void)
|
|||
|
||||
gamedata->pendingkeyrounds = READUINT32(save.p);
|
||||
gamedata->pendingkeyroundoffset = READUINT8(save.p);
|
||||
gamedata->keyspending = READUINT8(save.p);
|
||||
|
||||
if (versionMinor < 3)
|
||||
{
|
||||
gamedata->keyspending = READUINT8(save.p);
|
||||
}
|
||||
else
|
||||
{
|
||||
gamedata->keyspending = READUINT16(save.p);
|
||||
}
|
||||
|
||||
gamedata->chaokeys = READUINT16(save.p);
|
||||
|
||||
gamedata->everloadedaddon = (boolean)READUINT8(save.p);
|
||||
|
|
@ -4870,32 +4917,39 @@ void G_LoadGameData(void)
|
|||
}
|
||||
}
|
||||
|
||||
if (versionMinor < 3)
|
||||
{
|
||||
emblemreadcount = 512;
|
||||
unlockreadcount = conditionreadcount = UINT8_MAX;
|
||||
unlockreadsize = sizeof(UINT8);
|
||||
}
|
||||
|
||||
// To save space, use one bit per collected/achieved/unlocked flag
|
||||
for (i = 0; i < MAXEMBLEMS;)
|
||||
for (i = 0; i < emblemreadcount;)
|
||||
{
|
||||
rtemp = READUINT8(save.p);
|
||||
for (j = 0; j < 8 && j+i < MAXEMBLEMS; ++j)
|
||||
for (j = 0; j < 8 && j+i < emblemreadcount; ++j)
|
||||
gamedata->collected[j+i] = ((rtemp >> j) & 1);
|
||||
i += j;
|
||||
}
|
||||
for (i = 0; i < MAXUNLOCKABLES;)
|
||||
for (i = 0; i < unlockreadcount;)
|
||||
{
|
||||
rtemp = READUINT8(save.p);
|
||||
for (j = 0; j < 8 && j+i < MAXUNLOCKABLES; ++j)
|
||||
for (j = 0; j < 8 && j+i < unlockreadcount; ++j)
|
||||
gamedata->unlocked[j+i] = ((rtemp >> j) & 1);
|
||||
i += j;
|
||||
}
|
||||
for (i = 0; i < MAXUNLOCKABLES;)
|
||||
for (i = 0; i < unlockreadcount;)
|
||||
{
|
||||
rtemp = READUINT8(save.p);
|
||||
for (j = 0; j < 8 && j+i < MAXUNLOCKABLES; ++j)
|
||||
for (j = 0; j < 8 && j+i < unlockreadcount; ++j)
|
||||
gamedata->unlockpending[j+i] = ((rtemp >> j) & 1);
|
||||
i += j;
|
||||
}
|
||||
for (i = 0; i < MAXCONDITIONSETS;)
|
||||
for (i = 0; i < conditionreadcount;)
|
||||
{
|
||||
rtemp = READUINT8(save.p);
|
||||
for (j = 0; j < 8 && j+i < MAXCONDITIONSETS; ++j)
|
||||
for (j = 0; j < 8 && j+i < conditionreadcount; ++j)
|
||||
gamedata->achieved[j+i] = ((rtemp >> j) & 1);
|
||||
i += j;
|
||||
}
|
||||
|
|
@ -4904,7 +4958,7 @@ void G_LoadGameData(void)
|
|||
{
|
||||
UINT16 burn = READUINT16(save.p); // Previous challengegridwidth
|
||||
UINT8 height = (versionMinor > 0) ? CHALLENGEGRIDHEIGHT : 5;
|
||||
save.p += (burn * height * sizeof(UINT8)); // Step over previous grid data
|
||||
save.p += (burn * height * unlockreadsize); // Step over previous grid data
|
||||
|
||||
gamedata->challengegridwidth = 0;
|
||||
Z_Free(gamedata->challengegrid);
|
||||
|
|
@ -4917,11 +4971,23 @@ void G_LoadGameData(void)
|
|||
if (gamedata->challengegridwidth)
|
||||
{
|
||||
gamedata->challengegrid = Z_Malloc(
|
||||
(gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT * sizeof(UINT8)),
|
||||
(gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT * sizeof(UINT16)),
|
||||
PU_STATIC, NULL);
|
||||
for (i = 0; i < (gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT); i++)
|
||||
if (unlockreadsize == sizeof(UINT8))
|
||||
{
|
||||
gamedata->challengegrid[i] = READUINT8(save.p);
|
||||
for (i = 0; i < (gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT); i++)
|
||||
{
|
||||
gamedata->challengegrid[i] = READUINT8(save.p);
|
||||
if (gamedata->challengegrid[i] == unlockreadcount)
|
||||
gamedata->challengegrid[i] = MAXUNLOCKABLES;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < (gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT); i++)
|
||||
{
|
||||
gamedata->challengegrid[i] = READUINT16(save.p);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -4933,44 +4999,129 @@ void G_LoadGameData(void)
|
|||
gamedata->timesBeaten = READUINT32(save.p);
|
||||
|
||||
// Main records
|
||||
|
||||
skinreference_t *tempskinreferences = NULL;
|
||||
|
||||
if (versionMinor < 3)
|
||||
{
|
||||
gamedata->importprofilewins = true;
|
||||
numgamedataskins = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
numgamedataskins = READUINT32(save.p);
|
||||
|
||||
if (numgamedataskins)
|
||||
{
|
||||
tempskinreferences = Z_Malloc(
|
||||
numgamedataskins * sizeof (skinreference_t),
|
||||
PU_STATIC,
|
||||
NULL
|
||||
);
|
||||
|
||||
for (i = 0; i < numgamedataskins; i++)
|
||||
{
|
||||
char skinname[SKINNAMESIZE+1];
|
||||
INT32 skin;
|
||||
|
||||
READSTRINGN(save.p, skinname, SKINNAMESIZE);
|
||||
skin = R_SkinAvailable(skinname);
|
||||
|
||||
skinrecord_t dummyrecord;
|
||||
|
||||
dummyrecord.wins = READUINT32(save.p);
|
||||
dummyrecord._saveid = i;
|
||||
|
||||
CONS_Printf(" (TEMPORARY DISPLAY) skinname is \"%s\", has %u wins\n", skinname, dummyrecord.wins);
|
||||
|
||||
tempskinreferences[i].id = MAXSKINS;
|
||||
|
||||
if (skin != -1)
|
||||
{
|
||||
// We found a skin, so assign the win.
|
||||
|
||||
M_Memcpy(&skins[skin].records, &dummyrecord, sizeof(skinrecord_t));
|
||||
|
||||
tempskinreferences[i].id = skin;
|
||||
tempskinreferences[i].unloaded = NULL;
|
||||
}
|
||||
else if (dummyrecord.wins)
|
||||
{
|
||||
// Invalid, but we don't want to lose all the juicy statistics.
|
||||
// Instead, update a FILO linked list of "unloaded skins".
|
||||
|
||||
unloaded_skin_t *unloadedskin =
|
||||
Z_Malloc(
|
||||
sizeof(unloaded_skin_t),
|
||||
PU_STATIC, NULL
|
||||
);
|
||||
|
||||
// Establish properties, for later retrieval on file add.
|
||||
strlcpy(unloadedskin->name, skinname, sizeof(unloadedskin->name));
|
||||
unloadedskin->namehash = quickncasehash(unloadedskin->name, SKINNAMESIZE);
|
||||
|
||||
// Insert at the head, just because it's convenient.
|
||||
unloadedskin->next = unloadedskins;
|
||||
unloadedskins = unloadedskin;
|
||||
|
||||
// Finally, copy into.
|
||||
M_Memcpy(&unloadedskin->records, &dummyrecord, sizeof(skinrecord_t));
|
||||
|
||||
tempskinreferences[i].unloaded = unloadedskin;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
numgamedatamapheaders = READUINT32(save.p);
|
||||
if (numgamedatamapheaders >= NEXTMAP_SPECIAL)
|
||||
goto datacorrupt;
|
||||
|
||||
for (i = 0; i < numgamedatamapheaders; i++)
|
||||
{
|
||||
char mapname[MAXMAPLUMPNAME];
|
||||
INT16 mapnum;
|
||||
tic_t rectime;
|
||||
tic_t reclap;
|
||||
|
||||
READSTRINGN(save.p, mapname, sizeof(mapname));
|
||||
READSTRINGL(save.p, mapname, MAXMAPLUMPNAME);
|
||||
mapnum = G_MapNumber(mapname);
|
||||
|
||||
rtemp = READUINT8(save.p);
|
||||
rectime = (tic_t)READUINT32(save.p);
|
||||
reclap = (tic_t)READUINT32(save.p);
|
||||
recorddata_t dummyrecord;
|
||||
|
||||
dummyrecord.mapvisited = READUINT8(save.p);
|
||||
dummyrecord.time = (tic_t)READUINT32(save.p);
|
||||
dummyrecord.lap = (tic_t)READUINT32(save.p);
|
||||
|
||||
if (mapnum < nummapheaders && mapheaderinfo[mapnum])
|
||||
{
|
||||
// Valid mapheader, time to populate with record data.
|
||||
|
||||
if ((mapheaderinfo[mapnum]->mapvisited = rtemp) & ~MV_MAX)
|
||||
goto datacorrupt;
|
||||
|
||||
if (rectime || reclap)
|
||||
{
|
||||
G_AllocMainRecordData((INT16)i);
|
||||
mapheaderinfo[i]->mainrecord->time = rectime;
|
||||
mapheaderinfo[i]->mainrecord->lap = reclap;
|
||||
//CONS_Printf("ID %d, Time = %d, Lap = %d\n", i, rectime/35, reclap/35);
|
||||
}
|
||||
dummyrecord.mapvisited &= MV_MAX;
|
||||
M_Memcpy(&mapheaderinfo[mapnum]->records, &dummyrecord, sizeof(recorddata_t));
|
||||
}
|
||||
else
|
||||
else if (
|
||||
((dummyrecord.mapvisited & MV_PERSISTUNLOADED) != 0
|
||||
&& (dummyrecord.mapvisited & MV_BEATEN) != 0)
|
||||
|| dummyrecord.time != 0
|
||||
|| dummyrecord.lap != 0
|
||||
)
|
||||
{
|
||||
// Since it's not worth declaring the entire gamedata
|
||||
// corrupt over extra maps, we report and move on.
|
||||
CONS_Alert(CONS_WARNING, "Map with lumpname %s does not exist, time record data will be discarded\n", mapname);
|
||||
// Invalid, but we don't want to lose all the juicy statistics.
|
||||
// Instead, update a FILO linked list of "unloaded mapheaders".
|
||||
|
||||
unloaded_mapheader_t *unloadedmap =
|
||||
Z_Malloc(
|
||||
sizeof(unloaded_mapheader_t),
|
||||
PU_STATIC, NULL
|
||||
);
|
||||
|
||||
// Establish properties, for later retrieval on file add.
|
||||
unloadedmap->lumpname = Z_StrDup(mapname);
|
||||
unloadedmap->lumpnamehash = quickncasehash(unloadedmap->lumpname, MAXMAPLUMPNAME);
|
||||
|
||||
// Insert at the head, just because it's convenient.
|
||||
unloadedmap->next = unloadedmapheaders;
|
||||
unloadedmapheaders = unloadedmap;
|
||||
|
||||
// Finally, copy into.
|
||||
M_Memcpy(&unloadedmap->records, &dummyrecord, sizeof(recorddata_t));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4980,15 +5131,22 @@ void G_LoadGameData(void)
|
|||
|
||||
for (i = 0; i < numgamedatacups; i++)
|
||||
{
|
||||
char cupname[16];
|
||||
char cupname[MAXCUPNAME];
|
||||
cupheader_t *cup;
|
||||
|
||||
cupwindata_t dummywindata[4];
|
||||
|
||||
// Find the relevant cup.
|
||||
READSTRINGN(save.p, cupname, sizeof(cupname));
|
||||
READSTRINGL(save.p, cupname, sizeof(cupname));
|
||||
UINT32 hash = quickncasehash(cupname, MAXCUPNAME);
|
||||
for (cup = kartcupheaders; cup; cup = cup->next)
|
||||
{
|
||||
if (cup->namehash != hash)
|
||||
continue;
|
||||
|
||||
if (strcmp(cup->name, cupname))
|
||||
continue;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -4997,23 +5155,92 @@ void G_LoadGameData(void)
|
|||
{
|
||||
rtemp = READUINT8(save.p);
|
||||
|
||||
// ...but only record it if we actually found the associated cup.
|
||||
if (cup)
|
||||
{
|
||||
cup->windata[j].best_placement = (rtemp & 0x0F);
|
||||
cup->windata[j].best_grade = (rtemp & 0x70)>>4;
|
||||
if (rtemp & 0x80)
|
||||
{
|
||||
if (j == 0)
|
||||
goto datacorrupt;
|
||||
dummywindata[j].best_placement = (rtemp & 0x0F);
|
||||
dummywindata[j].best_grade = (rtemp & 0x70)>>4;
|
||||
dummywindata[j].got_emerald = !!(rtemp & 0x80);
|
||||
|
||||
cup->windata[j].got_emerald = true;
|
||||
dummywindata[j].best_skin.id = MAXSKINS;
|
||||
dummywindata[j].best_skin.unloaded = NULL;
|
||||
if (versionMinor >= 3)
|
||||
{
|
||||
UINT32 _saveid = READUINT32(save.p);
|
||||
if (_saveid < numgamedataskins)
|
||||
{
|
||||
M_Memcpy(&dummywindata[j].best_skin, &tempskinreferences[_saveid], sizeof(dummywindata[j].best_skin));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (versionMinor < 3)
|
||||
{
|
||||
// We now require backfilling of placement information.
|
||||
|
||||
cupwindata_t bestwindata;
|
||||
bestwindata.best_placement = 0;
|
||||
|
||||
j = KARTGP_MAX;
|
||||
while (j > 0)
|
||||
{
|
||||
j--;
|
||||
|
||||
if (bestwindata.best_placement == 0)
|
||||
{
|
||||
if (dummywindata[j].best_placement != 0)
|
||||
{
|
||||
M_Memcpy(&bestwindata, &dummywindata[j], sizeof(bestwindata));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dummywindata[j].best_placement != 0)
|
||||
{
|
||||
if (dummywindata[j].best_placement < bestwindata.best_placement)
|
||||
bestwindata.best_placement = dummywindata[j].best_placement;
|
||||
|
||||
if (dummywindata[j].best_grade > bestwindata.best_grade)
|
||||
bestwindata.best_grade = dummywindata[j].best_grade;
|
||||
|
||||
bestwindata.got_emerald |= dummywindata[j].got_emerald;
|
||||
}
|
||||
|
||||
M_Memcpy(&dummywindata[j], &bestwindata, sizeof(dummywindata[j]));
|
||||
}
|
||||
}
|
||||
|
||||
if (cup)
|
||||
{
|
||||
// We found a cup, so assign the windata.
|
||||
|
||||
M_Memcpy(&cup->windata, &dummywindata, sizeof(cup->windata));
|
||||
}
|
||||
else if (dummywindata[0].best_placement != 0)
|
||||
{
|
||||
// Invalid, but we don't want to lose all the juicy statistics.
|
||||
// Instead, update a FILO linked list of "unloaded cupheaders".
|
||||
|
||||
unloaded_cupheader_t *unloadedcup =
|
||||
Z_Malloc(
|
||||
sizeof(unloaded_cupheader_t),
|
||||
PU_STATIC, NULL
|
||||
);
|
||||
|
||||
// Establish properties, for later retrieval on file add.
|
||||
strlcpy(unloadedcup->name, cupname, sizeof(unloadedcup->name));
|
||||
unloadedcup->namehash = quickncasehash(unloadedcup->name, MAXCUPNAME);
|
||||
|
||||
// Insert at the head, just because it's convenient.
|
||||
unloadedcup->next = unloadedcupheaders;
|
||||
unloadedcupheaders = unloadedcup;
|
||||
|
||||
// Finally, copy into.
|
||||
M_Memcpy(&unloadedcup->windata, &dummywindata, sizeof(unloadedcup->windata));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tempskinreferences)
|
||||
Z_Free(tempskinreferences);
|
||||
|
||||
// done
|
||||
P_SaveBufferFree(&save);
|
||||
|
||||
|
|
@ -5074,7 +5301,7 @@ void G_DirtyGameData(void)
|
|||
void G_SaveGameData(void)
|
||||
{
|
||||
size_t length;
|
||||
INT32 i, j, numcups;
|
||||
INT32 i, j;
|
||||
cupheader_t *cup;
|
||||
UINT8 btemp;
|
||||
savebuffer_t save = {0};
|
||||
|
|
@ -5095,7 +5322,7 @@ void G_SaveGameData(void)
|
|||
length = (4+1+1+
|
||||
4+4+
|
||||
(4*GDGT_MAX)+
|
||||
4+1+1+2+
|
||||
4+1+2+2+
|
||||
1+1+1+
|
||||
4+
|
||||
(MAXEMBLEMS+(MAXUNLOCKABLES*2)+MAXCONDITIONSETS)+
|
||||
|
|
@ -5103,16 +5330,105 @@ void G_SaveGameData(void)
|
|||
|
||||
if (gamedata->challengegrid)
|
||||
{
|
||||
length += gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT;
|
||||
length += (gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT) * 2;
|
||||
}
|
||||
length += 4 + (nummapheaders * (MAXMAPLUMPNAME+1+4+4));
|
||||
|
||||
numcups = 0;
|
||||
|
||||
UINT32 numgamedataskins = 0;
|
||||
unloaded_skin_t *unloadedskin;
|
||||
|
||||
for (i = 0; i < numskins; i++)
|
||||
{
|
||||
// It's safe to assume a skin with no wins will have no other data worth keeping
|
||||
if (skins[i].records.wins == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
numgamedataskins++;
|
||||
}
|
||||
|
||||
for (unloadedskin = unloadedskins; unloadedskin; unloadedskin = unloadedskin->next)
|
||||
{
|
||||
// Ditto, with the exception that we should warn about it.
|
||||
if (unloadedskin->records.wins == 0)
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, "Unloaded skin \"%s\" has no wins!\n", unloadedskin->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
numgamedataskins++;
|
||||
}
|
||||
|
||||
length += 4 + (numgamedataskins * (SKINNAMESIZE+4));
|
||||
|
||||
|
||||
UINT32 numgamedatamapheaders = 0;
|
||||
unloaded_mapheader_t *unloadedmap;
|
||||
|
||||
for (i = 0; i < nummapheaders; i++)
|
||||
{
|
||||
// It's safe to assume a level with no mapvisited will have no other data worth keeping, since you get MV_VISITED just for opening it.
|
||||
if (!(mapheaderinfo[i]->records.mapvisited & MV_MAX))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
numgamedatamapheaders++;
|
||||
}
|
||||
|
||||
for (unloadedmap = unloadedmapheaders; unloadedmap; unloadedmap = unloadedmap->next)
|
||||
{
|
||||
// Ditto, with the exception that we should warn about it.
|
||||
if (!(unloadedmap->records.mapvisited & MV_MAX))
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, "Unloaded map \"%s\" has no mapvisited!\n", unloadedmap->lumpname);
|
||||
continue;
|
||||
}
|
||||
|
||||
// It's far off on the horizon, beyond many memory limits, but prevent a potential misery moment of losing ALL your data.
|
||||
if (++numgamedatamapheaders == UINT32_MAX)
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, "Some unloaded map record data has been dropped due to datatype limitations.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
length += 4 + (numgamedatamapheaders * (MAXMAPLUMPNAME+1+4+4));
|
||||
|
||||
|
||||
UINT32 numgamedatacups = 0;
|
||||
unloaded_cupheader_t *unloadedcup;
|
||||
|
||||
for (cup = kartcupheaders; cup; cup = cup->next)
|
||||
{
|
||||
numcups++;
|
||||
// Results are populated downwards, so no Easy win
|
||||
// means there's no important player data to save.
|
||||
if (cup->windata[0].best_placement == 0)
|
||||
continue;
|
||||
|
||||
numgamedatacups++;
|
||||
}
|
||||
length += 4 + (numcups * (4+16));
|
||||
|
||||
for (unloadedcup = unloadedcupheaders; unloadedcup; unloadedcup = unloadedcup->next)
|
||||
{
|
||||
// Ditto, with the exception that we should warn about it.
|
||||
if (unloadedcup->windata[0].best_placement == 0)
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, "Unloaded cup \"%s\" has no windata!\n", unloadedcup->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
// It's far off on the horizon, beyond many memory limits, but prevent a potential misery moment of losing ALL your data.
|
||||
if (++numgamedatacups == UINT32_MAX)
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, "Some unloaded cup standings data has been dropped due to datatype limitations.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
length += 4 + (numgamedatacups * (MAXCUPNAME + 4*(1+4)));
|
||||
|
||||
|
||||
if (P_SaveBufferAlloc(&save, length) == false)
|
||||
{
|
||||
|
|
@ -5141,7 +5457,7 @@ void G_SaveGameData(void)
|
|||
|
||||
WRITEUINT32(save.p, gamedata->pendingkeyrounds); // 4
|
||||
WRITEUINT8(save.p, gamedata->pendingkeyroundoffset); // 1
|
||||
WRITEUINT8(save.p, gamedata->keyspending); // 1
|
||||
WRITEUINT16(save.p, gamedata->keyspending); // 2
|
||||
WRITEUINT16(save.p, gamedata->chaokeys); // 2
|
||||
|
||||
WRITEUINT8(save.p, gamedata->everloadedaddon); // 1
|
||||
|
|
@ -5187,12 +5503,12 @@ void G_SaveGameData(void)
|
|||
i += j;
|
||||
}
|
||||
|
||||
if (gamedata->challengegrid) // 2 + gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT
|
||||
if (gamedata->challengegrid) // 2 + (gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT) * 2
|
||||
{
|
||||
WRITEUINT16(save.p, gamedata->challengegridwidth);
|
||||
for (i = 0; i < (gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT); i++)
|
||||
{
|
||||
WRITEUINT8(save.p, gamedata->challengegrid[i]);
|
||||
WRITEUINT16(save.p, gamedata->challengegrid[i]);
|
||||
}
|
||||
}
|
||||
else // 2
|
||||
|
|
@ -5203,45 +5519,161 @@ void G_SaveGameData(void)
|
|||
WRITEUINT32(save.p, gamedata->timesBeaten); // 4
|
||||
|
||||
// Main records
|
||||
WRITEUINT32(save.p, nummapheaders); // 4
|
||||
|
||||
for (i = 0; i < nummapheaders; i++) // nummapheaders * (255+1+4+4)
|
||||
WRITEUINT32(save.p, numgamedataskins); // 4
|
||||
|
||||
{
|
||||
// For figuring out which header to assign it to on load
|
||||
WRITESTRINGN(save.p, mapheaderinfo[i]->lumpname, MAXMAPLUMPNAME);
|
||||
// numgamedataskins * (SKINNAMESIZE+4)
|
||||
|
||||
WRITEUINT8(save.p, (mapheaderinfo[i]->mapvisited & MV_MAX));
|
||||
UINT32 maxid = 0;
|
||||
|
||||
if (mapheaderinfo[i]->mainrecord)
|
||||
for (i = 0; i < numskins; i++)
|
||||
{
|
||||
WRITEUINT32(save.p, mapheaderinfo[i]->mainrecord->time);
|
||||
WRITEUINT32(save.p, mapheaderinfo[i]->mainrecord->lap);
|
||||
if (skins[i].records.wins == 0)
|
||||
continue;
|
||||
|
||||
WRITESTRINGN(save.p, skins[i].name, SKINNAMESIZE);
|
||||
|
||||
WRITEUINT32(save.p, skins[i].records.wins);
|
||||
|
||||
skins[i].records._saveid = maxid;
|
||||
if (++maxid == numgamedataskins)
|
||||
break;
|
||||
}
|
||||
else
|
||||
|
||||
if (maxid < numgamedataskins)
|
||||
{
|
||||
WRITEUINT32(save.p, 0);
|
||||
WRITEUINT32(save.p, 0);
|
||||
for (unloadedskin = unloadedskins; unloadedskin; unloadedskin = unloadedskin->next)
|
||||
{
|
||||
if (unloadedskin->records.wins == 0)
|
||||
continue;
|
||||
|
||||
WRITESTRINGN(save.p, unloadedskin->name, SKINNAMESIZE);
|
||||
|
||||
WRITEUINT32(save.p, unloadedskin->records.wins);
|
||||
|
||||
unloadedskin->records._saveid = maxid;
|
||||
if (++maxid == numgamedataskins)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WRITEUINT32(save.p, numcups); // 4
|
||||
#define GETSKINREFSAVEID(ref, var) \
|
||||
{ \
|
||||
if (ref.unloaded != NULL) \
|
||||
var = ref.unloaded->records._saveid;\
|
||||
else if (ref.id < numskins)\
|
||||
var = skins[ref.id].records._saveid; \
|
||||
else \
|
||||
var = UINT32_MAX; \
|
||||
}
|
||||
|
||||
for (cup = kartcupheaders; cup; cup = cup->next)
|
||||
WRITEUINT32(save.p, numgamedatamapheaders); // 4
|
||||
|
||||
if (numgamedatamapheaders)
|
||||
{
|
||||
// For figuring out which header to assign it to on load
|
||||
WRITESTRINGN(save.p, cup->name, 16);
|
||||
// numgamedatamapheaders * (MAXMAPLUMPNAME+1+4+4)
|
||||
|
||||
for (i = 0; i < KARTGP_MAX; i++)
|
||||
for (i = 0; i < nummapheaders; i++)
|
||||
{
|
||||
btemp = min(cup->windata[i].best_placement, 0x0F);
|
||||
btemp |= (cup->windata[i].best_grade<<4);
|
||||
if (i != 0 && cup->windata[i].got_emerald == true)
|
||||
btemp |= 0x80;
|
||||
if (!(mapheaderinfo[i]->records.mapvisited & MV_MAX))
|
||||
continue;
|
||||
|
||||
WRITEUINT8(save.p, btemp); // 4 * numcups
|
||||
WRITESTRINGL(save.p, mapheaderinfo[i]->lumpname, MAXMAPLUMPNAME);
|
||||
|
||||
UINT8 mapvisitedtemp = (mapheaderinfo[i]->records.mapvisited & MV_MAX);
|
||||
|
||||
if ((mapheaderinfo[i]->menuflags & LF2_FINISHNEEDED))
|
||||
{
|
||||
mapvisitedtemp |= MV_FINISHNEEDED;
|
||||
}
|
||||
|
||||
WRITEUINT8(save.p, mapvisitedtemp);
|
||||
|
||||
WRITEUINT32(save.p, mapheaderinfo[i]->records.time);
|
||||
WRITEUINT32(save.p, mapheaderinfo[i]->records.lap);
|
||||
|
||||
if (--numgamedatamapheaders == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (numgamedatamapheaders)
|
||||
{
|
||||
for (unloadedmap = unloadedmapheaders; unloadedmap; unloadedmap = unloadedmap->next)
|
||||
{
|
||||
if (!(unloadedmap->records.mapvisited & MV_MAX))
|
||||
continue;
|
||||
|
||||
WRITESTRINGL(save.p, unloadedmap->lumpname, MAXMAPLUMPNAME);
|
||||
|
||||
WRITEUINT8(save.p, unloadedmap->records.mapvisited);
|
||||
|
||||
WRITEUINT32(save.p, unloadedmap->records.time);
|
||||
WRITEUINT32(save.p, unloadedmap->records.lap);
|
||||
|
||||
if (--numgamedatamapheaders == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
WRITEUINT32(save.p, numgamedatacups); // 4
|
||||
|
||||
if (numgamedatacups)
|
||||
{
|
||||
// numgamedatacups * (MAXCUPNAME + 4*(1+4))
|
||||
|
||||
#define WRITECUPWINDATA(maybeunloadedcup) \
|
||||
for (i = 0; i < KARTGP_MAX; i++) \
|
||||
{ \
|
||||
btemp = min(maybeunloadedcup->windata[i].best_placement, 0x0F); \
|
||||
btemp |= (maybeunloadedcup->windata[i].best_grade<<4); \
|
||||
if (maybeunloadedcup->windata[i].got_emerald == true) \
|
||||
btemp |= 0x80; \
|
||||
\
|
||||
WRITEUINT8(save.p, btemp); \
|
||||
\
|
||||
GETSKINREFSAVEID(maybeunloadedcup->windata[i].best_skin, j); \
|
||||
\
|
||||
WRITEUINT32(save.p, j); \
|
||||
}
|
||||
|
||||
for (cup = kartcupheaders; cup; cup = cup->next)
|
||||
{
|
||||
if (cup->windata[0].best_placement == 0)
|
||||
continue;
|
||||
|
||||
WRITESTRINGL(save.p, cup->name, MAXCUPNAME);
|
||||
|
||||
WRITECUPWINDATA(cup);
|
||||
|
||||
if (--numgamedatacups == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (numgamedatacups)
|
||||
{
|
||||
for (unloadedcup = unloadedcupheaders; unloadedcup; unloadedcup = unloadedcup->next)
|
||||
{
|
||||
if (unloadedcup->windata[0].best_placement == 0)
|
||||
continue;
|
||||
|
||||
WRITESTRINGL(save.p, unloadedcup->name, MAXCUPNAME);
|
||||
|
||||
WRITECUPWINDATA(unloadedcup);
|
||||
|
||||
if (--numgamedatacups == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#undef WRITECUPWINDATA
|
||||
}
|
||||
|
||||
#undef GETSKINREFSAVEID
|
||||
|
||||
length = save.p - save.buffer;
|
||||
|
||||
FIL_WriteFile(va(pandf, srb2home, gamedatafilename), save.buffer, length);
|
||||
|
|
|
|||
|
|
@ -264,7 +264,6 @@ void G_SetGameModified(boolean silent, boolean major);
|
|||
void G_SetUsedCheats(void);
|
||||
|
||||
// Gamedata record shit
|
||||
void G_AllocMainRecordData(INT16 i);
|
||||
void G_ClearRecords(void);
|
||||
|
||||
tic_t G_GetBestTime(INT16 map);
|
||||
|
|
|
|||
|
|
@ -570,17 +570,15 @@ void HWR_InitModels(void)
|
|||
|
||||
addskinmodel:
|
||||
// add player model
|
||||
for (s = 0; s < MAXSKINS; s++)
|
||||
s = R_SkinAvailable(skinname);
|
||||
if (s != -1)
|
||||
{
|
||||
if (stricmp(skinname, skins[s].name) == 0)
|
||||
{
|
||||
md2_playermodels[s].skin = s;
|
||||
md2_playermodels[s].scale = scale;
|
||||
md2_playermodels[s].offset = offset;
|
||||
md2_playermodels[s].notfound = false;
|
||||
strcpy(md2_playermodels[s].filename, filename);
|
||||
goto modelfound;
|
||||
}
|
||||
md2_playermodels[s].skin = s;
|
||||
md2_playermodels[s].scale = scale;
|
||||
md2_playermodels[s].offset = offset;
|
||||
md2_playermodels[s].notfound = false;
|
||||
strcpy(md2_playermodels[s].filename, filename);
|
||||
goto modelfound;
|
||||
}
|
||||
|
||||
// no sprite/player skin name found?!?D
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ boolean K_FollowerUsable(INT32 skinnum)
|
|||
{
|
||||
// Unlike R_SkinUsable, not netsynced.
|
||||
// Solely used to prevent an invalid value being sent over the wire.
|
||||
UINT8 i;
|
||||
UINT16 i;
|
||||
INT32 fid;
|
||||
|
||||
if (skinnum == -1 || demo.playback)
|
||||
|
|
|
|||
|
|
@ -815,10 +815,13 @@ void K_PlayerFinishGrandPrix(player_t *player)
|
|||
grandprixinfo.wonround = true;
|
||||
|
||||
// Increase your total rings
|
||||
if (RINGTOTAL(player) > 0)
|
||||
INT32 ringtotal = RINGTOTAL(player);
|
||||
if (ringtotal > 0)
|
||||
{
|
||||
player->totalring += RINGTOTAL(player);
|
||||
grandprixinfo.rank.rings += RINGTOTAL(player);
|
||||
if (ringtotal > 20)
|
||||
ringtotal = 20;
|
||||
player->totalring += ringtotal;
|
||||
grandprixinfo.rank.rings += ringtotal;
|
||||
}
|
||||
|
||||
if (grandprixinfo.eventmode == GPEVENT_NONE)
|
||||
|
|
|
|||
11
src/k_hud.c
11
src/k_hud.c
|
|
@ -81,7 +81,7 @@ static patch_t *kp_nocontestminimap;
|
|||
static patch_t *kp_spbminimap;
|
||||
static patch_t *kp_wouldyoustillcatchmeifiwereaworm;
|
||||
static patch_t *kp_catcherminimap;
|
||||
static patch_t *kp_emeraldminimap;
|
||||
static patch_t *kp_emeraldminimap[2];
|
||||
static patch_t *kp_capsuleminimap[3];
|
||||
|
||||
static patch_t *kp_ringsticker[2];
|
||||
|
|
@ -358,7 +358,8 @@ void K_LoadKartHUDGraphics(void)
|
|||
|
||||
HU_UpdatePatch(&kp_wouldyoustillcatchmeifiwereaworm, "MINIPROG");
|
||||
HU_UpdatePatch(&kp_catcherminimap, "UFOMAP");
|
||||
HU_UpdatePatch(&kp_emeraldminimap, "EMEMAP");
|
||||
HU_UpdatePatch(&kp_emeraldminimap[0], "EMEMAP");
|
||||
HU_UpdatePatch(&kp_emeraldminimap[1], "SUPMAP");
|
||||
|
||||
HU_UpdatePatch(&kp_capsuleminimap[0], "MINICAP1");
|
||||
HU_UpdatePatch(&kp_capsuleminimap[1], "MINICAP2");
|
||||
|
|
@ -3880,7 +3881,11 @@ static void K_drawKartMinimap(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
workingPic = kp_emeraldminimap;
|
||||
UINT8 emid = 0;
|
||||
if (specialstageinfo.ufo->cvmem > 7)
|
||||
emid = 1;
|
||||
workingPic = kp_emeraldminimap[emid];
|
||||
|
||||
if (specialstageinfo.ufo->color)
|
||||
{
|
||||
colormap = R_GetTranslationColormap(TC_DEFAULT, specialstageinfo.ufo->color, GTC_CACHE);
|
||||
|
|
|
|||
|
|
@ -1189,13 +1189,13 @@ extern struct challengesmenu_s {
|
|||
tic_t ticker; // How long the menu's been open for
|
||||
INT16 offset; // To make the icons move smoothly when we transition!
|
||||
|
||||
UINT8 currentunlock;
|
||||
UINT16 currentunlock;
|
||||
char *unlockcondition;
|
||||
|
||||
tic_t unlockanim;
|
||||
|
||||
SINT8 row, hilix, focusx;
|
||||
UINT8 col, hiliy;
|
||||
INT16 row, hilix, focusx;
|
||||
UINT16 col, hiliy;
|
||||
|
||||
challengegridextradata_t *extradata;
|
||||
|
||||
|
|
@ -1205,7 +1205,7 @@ extern struct challengesmenu_s {
|
|||
|
||||
boolean requestflip;
|
||||
|
||||
UINT8 unlockcount[CC_MAX];
|
||||
UINT16 unlockcount[CC_MAX];
|
||||
|
||||
UINT8 fade;
|
||||
} challengesmenu;
|
||||
|
|
|
|||
115
src/k_menudraw.c
115
src/k_menudraw.c
|
|
@ -51,6 +51,7 @@
|
|||
#include "d_player.h" // KITEM_ constants
|
||||
#include "doomstat.h" // MAXSPLITSCREENPLAYERS
|
||||
#include "k_grandprix.h" // K_CanChangeRules
|
||||
#include "k_rank.h" // K_GetGradeColor
|
||||
|
||||
#include "y_inter.h" // Y_RoundQueueDrawer
|
||||
|
||||
|
|
@ -2298,7 +2299,6 @@ void M_DrawCupSelect(void)
|
|||
INT16 icony = 7;
|
||||
char status = 'A';
|
||||
char monitor;
|
||||
INT32 rankx = 0;
|
||||
|
||||
if (!cupgrid.builtgrid[id])
|
||||
break;
|
||||
|
|
@ -2353,7 +2353,6 @@ void M_DrawCupSelect(void)
|
|||
if (monitor == '2')
|
||||
{
|
||||
icony = 5;
|
||||
rankx = 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -2385,43 +2384,94 @@ void M_DrawCupSelect(void)
|
|||
;
|
||||
else if (windata->best_placement != 0)
|
||||
{
|
||||
char gradeChar = '?';
|
||||
const INT32 rankw = 14 + 12 + 12 + 2;
|
||||
INT32 rankx = (x + 19) - (rankw / 2);
|
||||
const INT32 ranky = 8 + (j*100) - (30*menutransition.tics);
|
||||
|
||||
switch (windata->best_grade)
|
||||
patch_t *gradePat = NULL;
|
||||
colormap = NULL;
|
||||
|
||||
const gp_rank_e grade = windata->best_grade; // (cupgrid.previewanim/TICRATE) % (GRADE_S + 1); -- testing
|
||||
UINT16 gradecolor = K_GetGradeColor(grade);
|
||||
|
||||
if (gradecolor != SKINCOLOR_NONE)
|
||||
colormap = R_GetTranslationColormap(TC_DEFAULT, gradecolor, GTC_MENUCACHE);
|
||||
|
||||
switch (grade)
|
||||
{
|
||||
case GRADE_E: { gradeChar = 'E'; break; }
|
||||
case GRADE_D: { gradeChar = 'D'; break; }
|
||||
case GRADE_C: { gradeChar = 'C'; break; }
|
||||
case GRADE_B: { gradeChar = 'B'; break; }
|
||||
case GRADE_A: { gradeChar = 'A'; break; }
|
||||
case GRADE_S: { gradeChar = 'S'; break; }
|
||||
default: { break; }
|
||||
case GRADE_E:
|
||||
gradePat = W_CachePatchName("R_CUPRNE", PU_CACHE);
|
||||
break;
|
||||
case GRADE_D:
|
||||
gradePat = W_CachePatchName("R_CUPRND", PU_CACHE);
|
||||
break;
|
||||
case GRADE_C:
|
||||
gradePat = W_CachePatchName("R_CUPRNC", PU_CACHE);
|
||||
break;
|
||||
case GRADE_B:
|
||||
gradePat = W_CachePatchName("R_CUPRNB", PU_CACHE);
|
||||
break;
|
||||
case GRADE_A:
|
||||
gradePat = W_CachePatchName("R_CUPRNA", PU_CACHE);
|
||||
break;
|
||||
case GRADE_S:
|
||||
gradePat = W_CachePatchName("R_CUPRNS", PU_CACHE);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
V_DrawCharacter(x + 5 + rankx, y + icony + 14, gradeChar, false); // rank
|
||||
if (gradePat)
|
||||
V_DrawFixedPatch((rankx)*FRACUNIT, (ranky)*FRACUNIT, FRACUNIT, 0, gradePat, colormap);
|
||||
|
||||
if (windata->got_emerald == true)
|
||||
rankx += 14 + 1;
|
||||
|
||||
patch_t *charPat = NULL;
|
||||
|
||||
if ((windata->best_skin.unloaded != NULL)
|
||||
|| (windata->best_skin.id > numskins))
|
||||
{
|
||||
colormap = NULL;
|
||||
|
||||
charPat = W_CachePatchName("HUHMAP", PU_CACHE);
|
||||
}
|
||||
else
|
||||
{
|
||||
UINT8 skin = windata->best_skin.id;
|
||||
|
||||
colormap = R_GetTranslationColormap(skin, skins[skin].prefcolor, GTC_MENUCACHE);
|
||||
|
||||
charPat = faceprefix[skin][FACE_MINIMAP];
|
||||
}
|
||||
|
||||
if (charPat)
|
||||
V_DrawFixedPatch((rankx)*FRACUNIT, (ranky)*FRACUNIT, FRACUNIT, 0, charPat, colormap);
|
||||
|
||||
if (cv_dummygpdifficulty.value > 0
|
||||
&& windata->got_emerald == true)
|
||||
{
|
||||
rankx += 12 + 1;
|
||||
|
||||
if (templevelsearch.cup->emeraldnum == 0)
|
||||
V_DrawCharacter(x + 26 - rankx, y + icony + 14, '*', false); // rank
|
||||
V_DrawCharacter(rankx+2, ranky+2, '+', false);
|
||||
else
|
||||
{
|
||||
UINT16 col = SKINCOLOR_CHAOSEMERALD1 + (templevelsearch.cup->emeraldnum-1) % 7;
|
||||
patch_t *em;
|
||||
colormap = NULL;
|
||||
|
||||
colormap = R_GetTranslationColormap(TC_DEFAULT, col, GTC_MENUCACHE);
|
||||
if (!(cupgrid.previewanim & 1))
|
||||
{
|
||||
UINT16 col = SKINCOLOR_CHAOSEMERALD1 + (templevelsearch.cup->emeraldnum-1) % 7;
|
||||
|
||||
if (templevelsearch.cup->emeraldnum > 7)
|
||||
{
|
||||
em = W_CachePatchName("K_SUPER1", PU_CACHE);
|
||||
rankx += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
em = W_CachePatchName("K_EMERC", PU_CACHE);
|
||||
colormap = R_GetTranslationColormap(TC_DEFAULT, col, GTC_MENUCACHE);
|
||||
}
|
||||
|
||||
V_DrawFixedPatch((x + 26 - rankx)*FRACUNIT, (y + icony + 13)*FRACUNIT, FRACUNIT, 0, em, colormap);
|
||||
const char *emname = va(
|
||||
"%sMAP%c",
|
||||
(templevelsearch.cup->emeraldnum > 7) ? "SUP" : "EME",
|
||||
colormap ? '\0' : 'B'
|
||||
);
|
||||
|
||||
V_DrawFixedPatch((rankx)*FRACUNIT, (ranky)*FRACUNIT, FRACUNIT, 0, W_CachePatchName(emname, PU_CACHE), colormap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2640,11 +2690,8 @@ void M_DrawTimeAttack(void)
|
|||
if ((minimap = mapheaderinfo[map]->minimapPic))
|
||||
V_DrawScaledPatch(24-t, 82, 0, minimap);
|
||||
|
||||
if (mapheaderinfo[map]->mainrecord)
|
||||
{
|
||||
timerec = mapheaderinfo[map]->mainrecord->time;
|
||||
laprec = mapheaderinfo[map]->mainrecord->lap;
|
||||
}
|
||||
timerec = mapheaderinfo[map]->records.time;
|
||||
laprec = mapheaderinfo[map]->records.lap;
|
||||
|
||||
if ((gametypes[levellist.newgametype]->rules & GTR_CIRCUIT)
|
||||
&& (mapheaderinfo[map]->numlaps != 1))
|
||||
|
|
@ -4613,7 +4660,7 @@ static void M_DrawChallengeTile(INT16 i, INT16 j, INT32 x, INT32 y, boolean hili
|
|||
patch_t *pat = missingpat;
|
||||
UINT8 *colormap = NULL, *bgmap = NULL;
|
||||
fixed_t siz, accordion;
|
||||
UINT8 id, num;
|
||||
UINT16 id, num;
|
||||
boolean unlockedyet;
|
||||
boolean categoryside;
|
||||
|
||||
|
|
@ -5779,13 +5826,13 @@ void M_DrawStatistics(void)
|
|||
if (!mapheaderinfo[i] || (mapheaderinfo[i]->menuflags & (LF2_NOTIMEATTACK|LF2_HIDEINSTATS|LF2_HIDEINMENU)))
|
||||
continue;
|
||||
|
||||
if (!mapheaderinfo[i]->mainrecord || mapheaderinfo[i]->mainrecord->time <= 0)
|
||||
if (mapheaderinfo[i]->records.time <= 0)
|
||||
{
|
||||
mapsunfinished++;
|
||||
continue;
|
||||
}
|
||||
|
||||
besttime += mapheaderinfo[i]->mainrecord->time;
|
||||
besttime += mapheaderinfo[i]->records.time;
|
||||
}
|
||||
|
||||
V_DrawThinString(20, 60, V_6WIDTHSPACE|V_ALLOWLOWERCASE, "Combined time records:");
|
||||
|
|
|
|||
|
|
@ -303,7 +303,7 @@ void K_FinishCeremony(void)
|
|||
--------------------------------------------------*/
|
||||
void K_ResetCeremony(void)
|
||||
{
|
||||
UINT8 i;
|
||||
SINT8 i;
|
||||
|
||||
memset(&podiumData, 0, sizeof(struct podiumData_s));
|
||||
|
||||
|
|
@ -324,22 +324,43 @@ void K_ResetCeremony(void)
|
|||
// Write grade, position, and emerald-having-ness for later sessions!
|
||||
i = (grandprixinfo.masterbots) ? KARTGP_MASTER : grandprixinfo.gamespeed;
|
||||
|
||||
if ((grandprixinfo.cup->windata[i].best_placement == 0) // First run
|
||||
|| (podiumData.rank.position < grandprixinfo.cup->windata[i].best_placement)) // Later, better run
|
||||
// All results populate downwards in difficulty. This prevents someone
|
||||
// who's just won on Normal from feeling obligated to complete Easy too.
|
||||
for (; i >= 0; i--)
|
||||
{
|
||||
grandprixinfo.cup->windata[i].best_placement = podiumData.rank.position;
|
||||
boolean anymerit = false;
|
||||
|
||||
// The following will not occour in unmodified builds, but pre-emptively sanitise gamedata if someone just changes MAXPLAYERS and calls it a day
|
||||
if (grandprixinfo.cup->windata[i].best_placement > 0x0F)
|
||||
grandprixinfo.cup->windata[i].best_placement = 0x0F;
|
||||
if ((grandprixinfo.cup->windata[i].best_placement == 0) // First run
|
||||
|| (podiumData.rank.position <= grandprixinfo.cup->windata[i].best_placement)) // Later, better run
|
||||
{
|
||||
grandprixinfo.cup->windata[i].best_placement = podiumData.rank.position;
|
||||
|
||||
// The following will not occur in unmodified builds, but pre-emptively sanitise gamedata if someone just changes MAXPLAYERS and calls it a day
|
||||
if (grandprixinfo.cup->windata[i].best_placement > 0x0F)
|
||||
grandprixinfo.cup->windata[i].best_placement = 0x0F;
|
||||
|
||||
anymerit = true;
|
||||
}
|
||||
|
||||
if (podiumData.grade >= grandprixinfo.cup->windata[i].best_grade)
|
||||
{
|
||||
grandprixinfo.cup->windata[i].best_grade = podiumData.grade;
|
||||
anymerit = true;
|
||||
}
|
||||
|
||||
if (podiumData.rank.specialWon == true)
|
||||
{
|
||||
grandprixinfo.cup->windata[i].got_emerald = true;
|
||||
anymerit = true;
|
||||
}
|
||||
|
||||
if (anymerit == true)
|
||||
{
|
||||
grandprixinfo.cup->windata[i].best_skin.id = podiumData.rank.skin;
|
||||
grandprixinfo.cup->windata[i].best_skin.unloaded = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (podiumData.grade > grandprixinfo.cup->windata[i].best_grade)
|
||||
grandprixinfo.cup->windata[i].best_grade = podiumData.grade;
|
||||
|
||||
if (i != KARTSPEED_EASY && podiumData.rank.specialWon == true)
|
||||
grandprixinfo.cup->windata[i].got_emerald = true;
|
||||
|
||||
// Save before playing the noise
|
||||
G_SaveGameData();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -329,6 +329,11 @@ void PR_LoadProfiles(void)
|
|||
P_SaveBufferFree(&save);
|
||||
I_Error("Existing %s is from the future! (expected %d, got %d)", PROFILESFILE, PROFILEVER, version);
|
||||
}
|
||||
else if (version < PROFILEVER)
|
||||
{
|
||||
// We're converting - let'd create a backup.
|
||||
FIL_WriteFile(va("%s" PATHSEP "%s.bak", srb2home, PROFILESFILE), save.buffer, save.size);
|
||||
}
|
||||
|
||||
numprofiles = READUINT8(save.p);
|
||||
if (numprofiles > MAXPROFILES)
|
||||
|
|
|
|||
28
src/k_rank.c
28
src/k_rank.c
|
|
@ -417,3 +417,31 @@ gp_rank_e K_CalculateGPGrade(gpRank_t *rankData)
|
|||
|
||||
return retGrade;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
UINT16 K_GetGradeColor(gp_rank_e grade)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
UINT16 K_GetGradeColor(gp_rank_e grade)
|
||||
{
|
||||
switch (grade)
|
||||
{
|
||||
case GRADE_E:
|
||||
return SKINCOLOR_BLUE;
|
||||
case GRADE_D:
|
||||
return SKINCOLOR_TURTLE;
|
||||
case GRADE_C:
|
||||
return SKINCOLOR_ORANGE;
|
||||
case GRADE_B:
|
||||
return SKINCOLOR_RED;
|
||||
case GRADE_A:
|
||||
return SKINCOLOR_MAGENTA;
|
||||
case GRADE_S:
|
||||
return SKINCOLOR_PIGEON;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return SKINCOLOR_NONE;
|
||||
}
|
||||
|
|
|
|||
15
src/k_rank.h
15
src/k_rank.h
|
|
@ -26,6 +26,7 @@ struct gpRank_t
|
|||
UINT8 totalPlayers;
|
||||
|
||||
UINT8 position;
|
||||
UINT8 skin;
|
||||
|
||||
UINT32 winPoints;
|
||||
UINT32 totalPoints;
|
||||
|
|
@ -81,6 +82,20 @@ void K_InitGrandPrixRank(gpRank_t *rankData);
|
|||
gp_rank_e K_CalculateGPGrade(gpRank_t *rankData);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
UINT16 K_GetGradeColor(gp_rank_e grade)
|
||||
|
||||
Maps grades to skincolors for HUD purposes.
|
||||
|
||||
Input Arguments:-
|
||||
grade - gp_rank_e representing an achieved ranking.
|
||||
|
||||
Return:-
|
||||
skincolor ID representing the achieved grade.
|
||||
--------------------------------------------------*/
|
||||
UINT16 K_GetGradeColor(gp_rank_e grade);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -98,7 +98,16 @@ void SV_LoadStats(void)
|
|||
|
||||
save.p += headerlen;
|
||||
UINT8 version = READUINT8(save.p);
|
||||
(void)version; // for now
|
||||
if (version > SERVERSTATSVER)
|
||||
{
|
||||
P_SaveBufferFree(&save);
|
||||
I_Error("Existing %s is from the future! (expected %d, got %d)", SERVERSTATSFILE, SERVERSTATSVER, version);
|
||||
}
|
||||
else if (version < SERVERSTATSVER)
|
||||
{
|
||||
// We're converting - let'd create a backup.
|
||||
FIL_WriteFile(va("%s" PATHSEP "%s.bak", srb2home, SERVERSTATSFILE), save.buffer, save.size);
|
||||
}
|
||||
|
||||
numtracked = READUINT32(save.p);
|
||||
|
||||
|
|
|
|||
|
|
@ -386,10 +386,8 @@ static int libd_getSprite2Patch(lua_State *L)
|
|||
else // find skin by name
|
||||
{
|
||||
const char *name = luaL_checkstring(L, 1);
|
||||
for (i = 0; i < numskins; i++)
|
||||
if (fastcmp(skins[i].name, name))
|
||||
break;
|
||||
if (i >= numskins)
|
||||
i = R_SkinAvailable(name);
|
||||
if (i == -1)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -662,17 +662,16 @@ static int mobj_set(lua_State *L)
|
|||
break;
|
||||
case mobj_skin: // set skin by name
|
||||
{
|
||||
INT32 i;
|
||||
char skin[SKINNAMESIZE+1]; // all skin names are limited to this length
|
||||
strlcpy(skin, luaL_checkstring(L, 3), sizeof skin);
|
||||
strlwr(skin); // all skin names are lowercase
|
||||
for (i = 0; i < numskins; i++)
|
||||
if (fastcmp(skins[i].name, skin))
|
||||
{
|
||||
if (!mo->player || R_SkinUsable(mo->player-players, i, false))
|
||||
mo->skin = &skins[i];
|
||||
return 0;
|
||||
}
|
||||
const char *name = luaL_checkstring(L, 3);
|
||||
INT32 skin = R_SkinAvailable(name);
|
||||
|
||||
if (skin != -1)
|
||||
{
|
||||
if (!mo->player || R_SkinUsable(mo->player-players, skin, false))
|
||||
mo->skin = &skins[skin];
|
||||
|
||||
return 0;
|
||||
}
|
||||
return luaL_error(L, "mobj.skin '%s' not found!", skin);
|
||||
}
|
||||
case mobj_color:
|
||||
|
|
|
|||
|
|
@ -196,12 +196,12 @@ static int lib_getSkin(lua_State *L)
|
|||
}
|
||||
|
||||
// find skin by name
|
||||
for (i = 0; i < numskins; i++)
|
||||
if (fastcmp(skins[i].name, field))
|
||||
{
|
||||
LUA_PushUserdata(L, &skins[i], META_SKIN);
|
||||
return 1;
|
||||
}
|
||||
i = R_SkinAvailable(field);
|
||||
if (i != -1)
|
||||
{
|
||||
LUA_PushUserdata(L, &skins[i], META_SKIN);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ typedef struct
|
|||
// Cheat responders
|
||||
static UINT8 cheatf_warp(void)
|
||||
{
|
||||
UINT8 i;
|
||||
UINT16 i;
|
||||
boolean success = false;
|
||||
|
||||
/*if (modifiedgame)
|
||||
|
|
@ -98,7 +98,7 @@ static UINT8 cheatf_warp(void)
|
|||
#ifdef DEVELOP
|
||||
static UINT8 cheatf_devmode(void)
|
||||
{
|
||||
UINT8 i;
|
||||
UINT16 i;
|
||||
|
||||
if (modifiedgame)
|
||||
return 0;
|
||||
|
|
|
|||
67
src/m_cond.c
67
src/m_cond.c
|
|
@ -60,7 +60,7 @@ void M_PopulateChallengeGrid(void)
|
|||
{
|
||||
UINT16 i, j;
|
||||
UINT16 numunlocks = 0, nummajorunlocks = 0, numempty = 0;
|
||||
UINT8 selection[2][MAXUNLOCKABLES + (CHALLENGEGRIDHEIGHT-1)];
|
||||
UINT16 selection[2][MAXUNLOCKABLES + (CHALLENGEGRIDHEIGHT-1)];
|
||||
UINT16 majorcompact = 2;
|
||||
|
||||
if (gamedata->challengegrid != NULL)
|
||||
|
|
@ -98,7 +98,7 @@ void M_PopulateChallengeGrid(void)
|
|||
if (nummajorunlocks)
|
||||
{
|
||||
// Getting the number of 2-highs you can fit into two adjacent columns.
|
||||
UINT8 majorpad = (CHALLENGEGRIDHEIGHT/2);
|
||||
UINT16 majorpad = (CHALLENGEGRIDHEIGHT/2);
|
||||
numempty = nummajorunlocks%majorpad;
|
||||
majorpad = (nummajorunlocks+(majorpad-1))/majorpad;
|
||||
|
||||
|
|
@ -128,7 +128,7 @@ void M_PopulateChallengeGrid(void)
|
|||
}
|
||||
|
||||
gamedata->challengegrid = Z_Malloc(
|
||||
(gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT * sizeof(UINT8)),
|
||||
(gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT * sizeof(UINT16)),
|
||||
PU_STATIC, NULL);
|
||||
|
||||
if (!gamedata->challengegrid)
|
||||
|
|
@ -136,9 +136,10 @@ void M_PopulateChallengeGrid(void)
|
|||
I_Error("M_PopulateChallengeGrid: was not able to allocate grid");
|
||||
}
|
||||
|
||||
memset(gamedata->challengegrid,
|
||||
MAXUNLOCKABLES,
|
||||
(gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT * sizeof(UINT8)));
|
||||
for (i = 0; i < (gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT); ++i)
|
||||
{
|
||||
gamedata->challengegrid[i] = MAXUNLOCKABLES;
|
||||
}
|
||||
|
||||
// Attempt to place all large tiles first.
|
||||
if (nummajorunlocks)
|
||||
|
|
@ -212,7 +213,7 @@ quickcheckagain:
|
|||
#if (CHALLENGEGRIDHEIGHT == 4)
|
||||
while (nummajorunlocks > 0)
|
||||
{
|
||||
UINT8 unlocktomoveup = MAXUNLOCKABLES;
|
||||
UINT16 unlocktomoveup = MAXUNLOCKABLES;
|
||||
|
||||
j = gamedata->challengegridwidth-1;
|
||||
|
||||
|
|
@ -313,7 +314,7 @@ quickcheckagain:
|
|||
|
||||
void M_UpdateChallengeGridExtraData(challengegridextradata_t *extradata)
|
||||
{
|
||||
UINT8 i, j, num, id, tempid, work;
|
||||
UINT16 i, j, num, id, tempid, work;
|
||||
boolean idchange;
|
||||
|
||||
if (gamedata->challengegrid == NULL)
|
||||
|
|
@ -478,7 +479,7 @@ void M_UpdateChallengeGridExtraData(challengegridextradata_t *extradata)
|
|||
}
|
||||
}
|
||||
|
||||
void M_AddRawCondition(UINT8 set, UINT8 id, conditiontype_t c, INT32 r, INT16 x1, INT16 x2, char *stringvar)
|
||||
void M_AddRawCondition(UINT16 set, UINT8 id, conditiontype_t c, INT32 r, INT16 x1, INT16 x2, char *stringvar)
|
||||
{
|
||||
condition_t *cond;
|
||||
UINT32 num, wnum;
|
||||
|
|
@ -500,7 +501,7 @@ void M_AddRawCondition(UINT8 set, UINT8 id, conditiontype_t c, INT32 r, INT16 x1
|
|||
cond[wnum].stringvar = stringvar;
|
||||
}
|
||||
|
||||
void M_ClearConditionSet(UINT8 set)
|
||||
void M_ClearConditionSet(UINT16 set)
|
||||
{
|
||||
if (conditionSets[set].numconditions)
|
||||
{
|
||||
|
|
@ -531,17 +532,14 @@ void M_ClearStats(void)
|
|||
gamedata->everseenspecial = false;
|
||||
gamedata->evercrashed = false;
|
||||
gamedata->musicflags = 0;
|
||||
|
||||
gamedata->importprofilewins = false;
|
||||
}
|
||||
|
||||
void M_ClearSecrets(void)
|
||||
{
|
||||
INT32 i;
|
||||
|
||||
for (i = 0; i < nummapheaders; ++i)
|
||||
{
|
||||
mapheaderinfo[i]->mapvisited = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAXEMBLEMS; ++i)
|
||||
gamedata->collected[i] = false;
|
||||
for (i = 0; i < MAXUNLOCKABLES; ++i)
|
||||
|
|
@ -702,7 +700,7 @@ boolean M_CheckCondition(condition_t *cn, player_t *player)
|
|||
|
||||
return ((cn->requirement < nummapheaders)
|
||||
&& (mapheaderinfo[cn->requirement])
|
||||
&& ((mapheaderinfo[cn->requirement]->mapvisited & mvtype) == mvtype));
|
||||
&& ((mapheaderinfo[cn->requirement]->records.mapvisited & mvtype) == mvtype));
|
||||
}
|
||||
case UC_MAPTIME: // Requires time on map <= x
|
||||
return (G_GetBestTime(cn->extrainfo1) <= (unsigned)cn->requirement);
|
||||
|
|
@ -932,7 +930,7 @@ static char *M_BuildConditionTitle(UINT16 map)
|
|||
|
||||
if (((mapheaderinfo[map]->menuflags & LF2_FINISHNEEDED)
|
||||
// the following is intentionally not MV_BEATEN, just in case the title is for "Finish a round on X"
|
||||
&& !(mapheaderinfo[map]->mapvisited & MV_VISITED))
|
||||
&& !(mapheaderinfo[map]->records.mapvisited & MV_VISITED))
|
||||
|| M_MapLocked(map+1))
|
||||
return Z_StrDup("???");
|
||||
|
||||
|
|
@ -1398,7 +1396,7 @@ static const char *M_GetConditionString(condition_t *cn)
|
|||
#undef BUILDCONDITIONTITLE
|
||||
}
|
||||
|
||||
char *M_BuildConditionSetString(UINT8 unlockid)
|
||||
char *M_BuildConditionSetString(UINT16 unlockid)
|
||||
{
|
||||
conditionset_t *c = NULL;
|
||||
UINT32 lastID = 0;
|
||||
|
|
@ -1654,7 +1652,7 @@ boolean M_UpdateUnlockablesAndExtraEmblems(boolean loud, boolean doall)
|
|||
|
||||
UINT16 M_GetNextAchievedUnlock(void)
|
||||
{
|
||||
UINT8 i;
|
||||
UINT16 i;
|
||||
|
||||
// Go through unlockables
|
||||
for (i = 0; i < MAXUNLOCKABLES; ++i)
|
||||
|
|
@ -1686,14 +1684,14 @@ UINT16 M_GetNextAchievedUnlock(void)
|
|||
}
|
||||
|
||||
// Emblem unlocking shit
|
||||
UINT8 M_CheckLevelEmblems(void)
|
||||
UINT16 M_CheckLevelEmblems(void)
|
||||
{
|
||||
INT32 i;
|
||||
INT32 valToReach;
|
||||
INT16 tag;
|
||||
INT16 levelnum;
|
||||
UINT8 res;
|
||||
UINT8 somethingUnlocked = 0;
|
||||
boolean res;
|
||||
UINT16 somethingUnlocked = 0;
|
||||
|
||||
// Update Score, Time, Rings emblems
|
||||
for (i = 0; i < numemblems; ++i)
|
||||
|
|
@ -1739,13 +1737,13 @@ UINT8 M_CheckLevelEmblems(void)
|
|||
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.
|
||||
UINT16 M_CompletionEmblems(void) // Bah! Duplication sucks, but it's for a separate print when awarding emblems and it's sorta different enough.
|
||||
{
|
||||
INT32 i;
|
||||
INT32 embtype;
|
||||
INT16 levelnum;
|
||||
UINT8 res;
|
||||
UINT8 somethingUnlocked = 0;
|
||||
boolean res;
|
||||
UINT16 somethingUnlocked = 0;
|
||||
UINT8 flags;
|
||||
|
||||
for (i = 0; i < numemblems; ++i)
|
||||
|
|
@ -1770,7 +1768,7 @@ UINT8 M_CompletionEmblems(void) // Bah! Duplication sucks, but it's for a separa
|
|||
if (embtype & ME_SPBATTACK)
|
||||
flags |= MV_SPBATTACK;
|
||||
|
||||
res = ((mapheaderinfo[levelnum]->mapvisited & flags) == flags);
|
||||
res = ((mapheaderinfo[levelnum]->records.mapvisited & flags) == flags);
|
||||
|
||||
gamedata->collected[i] = res;
|
||||
if (res)
|
||||
|
|
@ -1784,7 +1782,7 @@ UINT8 M_CompletionEmblems(void) // Bah! Duplication sucks, but it's for a separa
|
|||
// Quick unlock checks
|
||||
// -------------------
|
||||
|
||||
boolean M_CheckNetUnlockByID(UINT8 unlockid)
|
||||
boolean M_CheckNetUnlockByID(UINT16 unlockid)
|
||||
{
|
||||
if (unlockid >= MAXUNLOCKABLES
|
||||
|| !unlockables[unlockid].conditionset)
|
||||
|
|
@ -1827,7 +1825,7 @@ boolean M_SecretUnlocked(INT32 type, boolean local)
|
|||
|
||||
boolean M_CupLocked(cupheader_t *cup)
|
||||
{
|
||||
UINT8 i;
|
||||
UINT16 i;
|
||||
|
||||
// Don't lock maps in dedicated servers.
|
||||
// That just makes hosts' lives hell.
|
||||
|
|
@ -1855,7 +1853,7 @@ boolean M_CupLocked(cupheader_t *cup)
|
|||
|
||||
boolean M_MapLocked(UINT16 mapnum)
|
||||
{
|
||||
UINT8 i;
|
||||
UINT16 i;
|
||||
|
||||
// Don't lock maps in dedicated servers.
|
||||
// That just makes hosts' lives hell.
|
||||
|
|
@ -1921,7 +1919,7 @@ INT32 M_CountMedals(boolean all, boolean extraonly)
|
|||
|
||||
// Theoretically faster than using M_CountMedals()
|
||||
// Stops when it reaches the target number of medals.
|
||||
UINT8 M_GotEnoughMedals(INT32 number)
|
||||
boolean M_GotEnoughMedals(INT32 number)
|
||||
{
|
||||
INT32 i, gottenmedals = 0;
|
||||
for (i = 0; i < numemblems; ++i)
|
||||
|
|
@ -1945,7 +1943,7 @@ UINT8 M_GotEnoughMedals(INT32 number)
|
|||
return false;
|
||||
}
|
||||
|
||||
UINT8 M_GotLowEnoughTime(INT32 tictime)
|
||||
boolean M_GotLowEnoughTime(INT32 tictime)
|
||||
{
|
||||
INT32 curtics = 0;
|
||||
INT32 i;
|
||||
|
|
@ -1955,9 +1953,9 @@ UINT8 M_GotLowEnoughTime(INT32 tictime)
|
|||
if (!mapheaderinfo[i] || (mapheaderinfo[i]->menuflags & LF2_NOTIMEATTACK))
|
||||
continue;
|
||||
|
||||
if (!mapheaderinfo[i]->mainrecord || !mapheaderinfo[i]->mainrecord->time)
|
||||
if (!mapheaderinfo[i]->records.time)
|
||||
return false;
|
||||
else if ((curtics += mapheaderinfo[i]->mainrecord->time) > tictime)
|
||||
if ((curtics += mapheaderinfo[i]->records.time) > tictime)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
|
@ -2064,9 +2062,10 @@ cupheader_t *M_UnlockableCup(unlockable_t *unlock)
|
|||
if (unlock->stringVarCache == -1)
|
||||
{
|
||||
// Get the cup from the string.
|
||||
UINT32 hash = quickncasehash(unlock->stringVar, MAXCUPNAME);
|
||||
while (cup)
|
||||
{
|
||||
if (!strcmp(cup->name, unlock->stringVar))
|
||||
if (hash == cup->namehash && !strcmp(cup->name, unlock->stringVar))
|
||||
break;
|
||||
cup = cup->next;
|
||||
}
|
||||
|
|
|
|||
29
src/m_cond.h
29
src/m_cond.h
|
|
@ -159,7 +159,7 @@ struct unlockable_t
|
|||
char name[64];
|
||||
char *icon;
|
||||
UINT16 color;
|
||||
UINT8 conditionset;
|
||||
UINT16 conditionset;
|
||||
INT16 type;
|
||||
INT16 variable;
|
||||
char *stringVar;
|
||||
|
|
@ -206,8 +206,8 @@ typedef enum
|
|||
|
||||
// If you have more secrets than these variables allow in your game,
|
||||
// you seriously need to get a life.
|
||||
#define MAXCONDITIONSETS UINT8_MAX
|
||||
#define MAXEMBLEMS 512
|
||||
#define MAXCONDITIONSETS 1024
|
||||
#define MAXEMBLEMS (MAXCONDITIONSETS*2)
|
||||
#define MAXUNLOCKABLES MAXCONDITIONSETS
|
||||
|
||||
#define CHALLENGEGRIDHEIGHT 4
|
||||
|
|
@ -260,7 +260,7 @@ struct gamedata_t
|
|||
|
||||
// CHALLENGE GRID
|
||||
UINT16 challengegridwidth;
|
||||
UINT8 *challengegrid;
|
||||
UINT16 *challengegrid;
|
||||
|
||||
// # OF TIMES THE GAME HAS BEEN BEATEN
|
||||
UINT32 timesBeaten;
|
||||
|
|
@ -273,7 +273,7 @@ struct gamedata_t
|
|||
// Chao Key condition bypass
|
||||
UINT32 pendingkeyrounds;
|
||||
UINT8 pendingkeyroundoffset;
|
||||
UINT8 keyspending;
|
||||
UINT16 keyspending;
|
||||
UINT16 chaokeys;
|
||||
|
||||
// SPECIFIC SPECIAL EVENTS
|
||||
|
|
@ -282,6 +282,9 @@ struct gamedata_t
|
|||
boolean everseenspecial;
|
||||
boolean evercrashed;
|
||||
UINT8 musicflags;
|
||||
|
||||
// BACKWARDS COMPAT ASSIST
|
||||
boolean importprofilewins;
|
||||
};
|
||||
|
||||
extern gamedata_t *gamedata;
|
||||
|
|
@ -314,15 +317,15 @@ void M_UpdateChallengeGridExtraData(challengegridextradata_t *extradata);
|
|||
#define CHE_CONNECTEDUP (1<<2)
|
||||
#define CHE_DONTDRAW (CHE_CONNECTEDLEFT|CHE_CONNECTEDUP)
|
||||
|
||||
char *M_BuildConditionSetString(UINT8 unlockid);
|
||||
char *M_BuildConditionSetString(UINT16 unlockid);
|
||||
#define DESCRIPTIONWIDTH 170
|
||||
|
||||
// Condition set setup
|
||||
void M_AddRawCondition(UINT8 set, UINT8 id, conditiontype_t c, INT32 r, INT16 x1, INT16 x2, char *stringvar);
|
||||
void M_AddRawCondition(UINT16 set, UINT8 id, conditiontype_t c, INT32 r, INT16 x1, INT16 x2, char *stringvar);
|
||||
void M_UpdateConditionSetsPending(void);
|
||||
|
||||
// Clearing secrets
|
||||
void M_ClearConditionSet(UINT8 set);
|
||||
void M_ClearConditionSet(UINT16 set);
|
||||
void M_ClearSecrets(void);
|
||||
void M_ClearStats(void);
|
||||
|
||||
|
|
@ -335,11 +338,11 @@ boolean M_UpdateUnlockablesAndExtraEmblems(boolean loud, boolean doall);
|
|||
#define PENDING_CHAOKEYS (UINT16_MAX-1)
|
||||
UINT16 M_GetNextAchievedUnlock(void);
|
||||
|
||||
UINT8 M_CheckLevelEmblems(void);
|
||||
UINT8 M_CompletionEmblems(void);
|
||||
UINT16 M_CheckLevelEmblems(void);
|
||||
UINT16 M_CompletionEmblems(void);
|
||||
|
||||
// Checking unlockable status
|
||||
boolean M_CheckNetUnlockByID(UINT8 unlockid);
|
||||
boolean M_CheckNetUnlockByID(UINT16 unlockid);
|
||||
boolean M_SecretUnlocked(INT32 type, boolean local);
|
||||
boolean M_CupLocked(cupheader_t *cup);
|
||||
boolean M_MapLocked(UINT16 mapnum);
|
||||
|
|
@ -353,8 +356,8 @@ const char *M_GetEmblemPatch(emblem_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_GotEnoughMedals(INT32 number);
|
||||
UINT8 M_GotLowEnoughTime(INT32 tictime);
|
||||
boolean M_GotEnoughMedals(INT32 number);
|
||||
boolean M_GotLowEnoughTime(INT32 tictime);
|
||||
|
||||
INT32 M_UnlockableSkinNum(unlockable_t *unlock);
|
||||
INT32 M_UnlockableFollowerNum(unlockable_t *unlock);
|
||||
|
|
|
|||
|
|
@ -53,8 +53,8 @@ struct challengesmenu_s challengesmenu;
|
|||
|
||||
static void M_ChallengesAutoFocus(UINT16 unlockid, boolean fresh)
|
||||
{
|
||||
UINT8 i;
|
||||
SINT8 work;
|
||||
UINT16 i;
|
||||
INT16 work;
|
||||
|
||||
if (unlockid >= MAXUNLOCKABLES && gamedata->pendingkeyrounds > 0
|
||||
&& (gamedata->chaokeys < GDMAX_CHAOKEYS))
|
||||
|
|
@ -62,8 +62,8 @@ static void M_ChallengesAutoFocus(UINT16 unlockid, boolean fresh)
|
|||
|
||||
if (fresh && unlockid >= MAXUNLOCKABLES)
|
||||
{
|
||||
UINT8 selection[MAXUNLOCKABLES];
|
||||
UINT8 numunlocks = 0;
|
||||
UINT16 selection[MAXUNLOCKABLES];
|
||||
UINT16 numunlocks = 0;
|
||||
|
||||
// Get a random available unlockable.
|
||||
for (i = 0; i < MAXUNLOCKABLES; i++)
|
||||
|
|
@ -512,7 +512,7 @@ void M_ChallengesTick(void)
|
|||
boolean M_ChallengesInputs(INT32 ch)
|
||||
{
|
||||
const UINT8 pid = 0;
|
||||
UINT8 i;
|
||||
UINT16 i;
|
||||
const boolean start = M_MenuButtonPressed(pid, MBT_START);
|
||||
const boolean move = (menucmd[pid].dpad_ud != 0 || menucmd[pid].dpad_lr != 0);
|
||||
(void) ch;
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ static boolean M_StatisticsAddMap(UINT16 map, cupheader_t *cup, boolean *headere
|
|||
|
||||
// Check for completion
|
||||
if ((mapheaderinfo[map]->menuflags & LF2_FINISHNEEDED)
|
||||
&& !(mapheaderinfo[map]->mapvisited & MV_BEATEN))
|
||||
&& !(mapheaderinfo[map]->records.mapvisited & MV_BEATEN))
|
||||
return false;
|
||||
|
||||
// Check for unlock
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ menuitem_t OPTIONS_DataErase[] =
|
|||
{IT_STRING | IT_CALL, "Erase Statistics Data", "Be careful! What's deleted is gone forever!",
|
||||
NULL, {.routine = M_EraseData}, EC_STATISTICS, 0},
|
||||
|
||||
{IT_STRING | IT_CALL, "Erase GP & Time Attack Data", "Be careful! What's deleted is gone forever!",
|
||||
{IT_STRING | IT_CALL, "Erase GP & Record Data", "Be careful! What's deleted is gone forever!",
|
||||
NULL, {.routine = M_EraseData}, EC_TIMEATTACK, 0},
|
||||
|
||||
{IT_STRING | IT_CALL, "\x85\x45rase all Game Data", "Be careful! What's deleted is gone forever!",
|
||||
|
|
@ -89,7 +89,7 @@ void M_EraseData(INT32 choice)
|
|||
else if (optionsmenu.erasecontext == EC_STATISTICS)
|
||||
eschoice = M_GetText("Statistics data");
|
||||
else if (optionsmenu.erasecontext == EC_TIMEATTACK)
|
||||
eschoice = M_GetText("GP & Time Attack data");
|
||||
eschoice = M_GetText("GP & Record data");
|
||||
else if (optionsmenu.erasecontext == EC_ALLGAME)
|
||||
eschoice = M_GetText("ALL game data");
|
||||
else
|
||||
|
|
|
|||
|
|
@ -404,6 +404,8 @@ void M_CharacterSelectInit(void)
|
|||
memset(setup_explosions, 0, sizeof(setup_explosions));
|
||||
setup_animcounter = 0;
|
||||
|
||||
UINT32 localskinhash[MAXSPLITSCREENPLAYERS];
|
||||
|
||||
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
|
||||
{
|
||||
// Default to no follower / match colour.
|
||||
|
|
@ -414,6 +416,9 @@ void M_CharacterSelectInit(void)
|
|||
// Set default selected profile to the last used profile for each player:
|
||||
// (Make sure we don't overshoot it somehow if we deleted profiles or whatnot)
|
||||
setup_player[i].profilen = min(cv_lastprofile[i].value, PR_GetNumProfiles());
|
||||
|
||||
// Assistant for comparisons.
|
||||
localskinhash[i] = quickncasehash(cv_skin[i].string, SKINNAMESIZE);
|
||||
}
|
||||
|
||||
for (i = 0; i < numskins; i++)
|
||||
|
|
@ -436,7 +441,14 @@ void M_CharacterSelectInit(void)
|
|||
|
||||
for (j = 0; j < MAXSPLITSCREENPLAYERS; j++)
|
||||
{
|
||||
if (!strcmp(cv_skin[j].string, skins[i].name))
|
||||
// See also R_SkinAvailable
|
||||
|
||||
if (localskinhash[j] != skins[i].namehash)
|
||||
continue;
|
||||
|
||||
if (!stricmp(cv_skin[j].string, skins[i].name))
|
||||
continue;
|
||||
|
||||
{
|
||||
setup_player[j].gridx = x;
|
||||
setup_player[j].gridy = y;
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ boolean M_CanShowLevelInList(INT16 mapnum, levelsearch_t *levelsearch)
|
|||
{
|
||||
// Check for completion
|
||||
if ((mapheaderinfo[mapnum]->menuflags & LF2_FINISHNEEDED)
|
||||
&& !(mapheaderinfo[mapnum]->mapvisited & MV_BEATEN))
|
||||
&& !(mapheaderinfo[mapnum]->records.mapvisited & MV_BEATEN))
|
||||
return false;
|
||||
|
||||
// Check for unlock
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
#define UFO_NUMARMS (3)
|
||||
#define UFO_ARMDELTA (ANGLE_MAX / UFO_NUMARMS)
|
||||
|
||||
#define ufo_emeraldnum(o) ((o)->cvmem)
|
||||
#define ufo_waypoint(o) ((o)->extravalue1)
|
||||
#define ufo_distancetofinish(o) ((o)->extravalue2)
|
||||
#define ufo_speed(o) ((o)->watertop)
|
||||
|
|
@ -1005,7 +1006,7 @@ static mobj_t *InitSpecialUFO(waypoint_t *start)
|
|||
overlay = P_SpawnMobjFromMobj(ufo, 0, 0, 0, MT_OVERLAY);
|
||||
|
||||
ufo->color = SKINCOLOR_CHAOSEMERALD1;
|
||||
i = P_GetNextEmerald();
|
||||
i = ufo_emeraldnum(ufo) = P_GetNextEmerald();
|
||||
if (i > 0)
|
||||
{
|
||||
ufo->color += (i - 1) % 7;
|
||||
|
|
|
|||
|
|
@ -446,9 +446,7 @@ static void P_ClearSingleMapHeaderInfo(INT16 num)
|
|||
P_DeleteHeaderFollowers(num);
|
||||
#endif
|
||||
|
||||
mapheaderinfo[num]->mapvisited = 0;
|
||||
Z_Free(mapheaderinfo[num]->mainrecord);
|
||||
mapheaderinfo[num]->mainrecord = NULL;
|
||||
memset(&mapheaderinfo[num]->records, 0, sizeof(recorddata_t));
|
||||
|
||||
mapheaderinfo[num]->justPlayed = 0;
|
||||
mapheaderinfo[num]->anger = 0;
|
||||
|
|
@ -506,7 +504,6 @@ void P_AllocMapHeader(INT16 i)
|
|||
mapheaderinfo[i]->minimapPic = NULL;
|
||||
mapheaderinfo[i]->ghostCount = 0;
|
||||
mapheaderinfo[i]->cup = NULL;
|
||||
mapheaderinfo[i]->mainrecord = NULL;
|
||||
mapheaderinfo[i]->followers = NULL;
|
||||
nummapheaders++;
|
||||
}
|
||||
|
|
@ -8309,7 +8306,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
|
|||
|
||||
if (!demo.playback)
|
||||
{
|
||||
mapheaderinfo[gamemap-1]->mapvisited |= MV_VISITED;
|
||||
mapheaderinfo[gamemap-1]->records.mapvisited |= MV_VISITED;
|
||||
|
||||
M_UpdateUnlockablesAndExtraEmblems(true, true);
|
||||
G_SaveGameData();
|
||||
|
|
|
|||
16
src/p_user.c
16
src/p_user.c
|
|
@ -1355,11 +1355,19 @@ void P_DoPlayerExit(player_t *player, pflags_t flags)
|
|||
G_UpdateRecords();
|
||||
}
|
||||
|
||||
profile_t *pr = PR_GetPlayerProfile(player);
|
||||
if (pr != NULL && !losing)
|
||||
if (!losing)
|
||||
{
|
||||
pr->wins++;
|
||||
PR_SaveProfiles();
|
||||
profile_t *pr = PR_GetPlayerProfile(player);
|
||||
if (pr != NULL)
|
||||
{
|
||||
pr->wins++;
|
||||
PR_SaveProfiles();
|
||||
}
|
||||
|
||||
if (P_IsLocalPlayer(player) && player->skin < numskins)
|
||||
{
|
||||
skins[player->skin].records.wins++;
|
||||
}
|
||||
}
|
||||
|
||||
player->karthud[khud_cardanimation] = 0; // srb2kart: reset battle animation
|
||||
|
|
|
|||
212
src/r_skins.c
212
src/r_skins.c
|
|
@ -41,6 +41,8 @@
|
|||
INT32 numskins = 0;
|
||||
skin_t skins[MAXSKINS];
|
||||
|
||||
unloaded_skin_t *unloadedskins = NULL;
|
||||
|
||||
// FIXTHIS: don't work because it must be inistilised before the config load
|
||||
//#define SKINVALUES
|
||||
#ifdef SKINVALUES
|
||||
|
|
@ -125,6 +127,8 @@ static void Sk_SetDefaultValue(skin_t *skin)
|
|||
|
||||
skin->highresscale = FRACUNIT;
|
||||
|
||||
// no specific memset for skinrecord_t as it's already nuked by the full skin_t wipe
|
||||
|
||||
for (i = 0; i < sfx_skinsoundslot0; i++)
|
||||
if (S_sfx[i].skinsound != -1)
|
||||
skin->soundsid[S_sfx[i].skinsound] = i;
|
||||
|
|
@ -183,7 +187,8 @@ void R_InitSkins(void)
|
|||
|
||||
UINT8 *R_GetSkinAvailabilities(boolean demolock, boolean forbots)
|
||||
{
|
||||
UINT8 i, shif, byte;
|
||||
UINT16 i;
|
||||
UINT8 shif, byte;
|
||||
INT32 skinid;
|
||||
static UINT8 responsebuffer[MAXAVAILABILITY];
|
||||
UINT8 defaultbotskin = R_BotDefaultSkin();
|
||||
|
|
@ -221,7 +226,7 @@ boolean R_SkinUsable(INT32 playernum, INT32 skinnum, boolean demoskins)
|
|||
{
|
||||
boolean needsunlocked = false;
|
||||
boolean useplayerstruct = (Playing() && playernum != -1);
|
||||
UINT8 i;
|
||||
UINT16 i;
|
||||
INT32 skinid;
|
||||
|
||||
if (skinnum == -1)
|
||||
|
|
@ -314,12 +319,17 @@ UINT32 R_GetLocalRandomSkin(void)
|
|||
INT32 R_SkinAvailable(const char *name)
|
||||
{
|
||||
INT32 i;
|
||||
UINT32 hash = quickncasehash(name, SKINNAMESIZE);
|
||||
|
||||
for (i = 0; i < numskins; i++)
|
||||
{
|
||||
// search in the skin list
|
||||
if (stricmp(skins[i].name,name)==0)
|
||||
return i;
|
||||
if (skins[i].namehash != hash)
|
||||
continue;
|
||||
|
||||
if (stricmp(skins[i].name,name)!=0)
|
||||
continue;
|
||||
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -727,9 +737,59 @@ static void R_LoadSkinSprites(UINT16 wadnum, UINT16 *lump, UINT16 *lastlump, ski
|
|||
// returns whether found appropriate property
|
||||
static boolean R_ProcessPatchableFields(skin_t *skin, char *stoken, char *value)
|
||||
{
|
||||
if (!stricmp(stoken, "rivals"))
|
||||
{
|
||||
size_t len = strlen(value);
|
||||
size_t i;
|
||||
char rivalname[SKINNAMESIZE+1] = "";
|
||||
UINT8 pos = 0;
|
||||
UINT8 numrivals = 0;
|
||||
|
||||
// Can't use strtok, because the above function's already using it.
|
||||
// Using it causes it to upset the saved pointer,
|
||||
// corrupting the reading for the rest of the file.
|
||||
|
||||
// So instead we get to crawl through the value, character by character,
|
||||
// and write it down as we go, until we hit a comma or the end of the string.
|
||||
// Yaaay.
|
||||
|
||||
for (i = 0; i <= len; i++)
|
||||
{
|
||||
if (numrivals >= SKINRIVALS)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (value[i] == ',' || i == len)
|
||||
{
|
||||
if (pos == 0)
|
||||
continue;
|
||||
|
||||
STRBUFCPY(skin->rivals[numrivals], rivalname);
|
||||
strlwr(skin->rivals[numrivals]);
|
||||
numrivals++;
|
||||
|
||||
if (i == len)
|
||||
break;
|
||||
|
||||
for (; pos > 0; pos--)
|
||||
{
|
||||
rivalname[pos] = '\0';
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
rivalname[pos] = value[i];
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
|
||||
// custom translation table
|
||||
if (!stricmp(stoken, "startcolor"))
|
||||
else if (!stricmp(stoken, "startcolor"))
|
||||
{
|
||||
skin->starttranscolor = atoi(value);
|
||||
}
|
||||
|
||||
#define FULLPROCESS(field) else if (!stricmp(stoken, #field)) skin->field = get_number(value);
|
||||
// character type identification
|
||||
|
|
@ -917,45 +977,6 @@ void R_AddSkins(UINT16 wadnum, boolean mainfile)
|
|||
STRBUFCPY(skin->realname, value);
|
||||
SYMBOLCONVERT(skin->realname)
|
||||
}
|
||||
else if (!stricmp(stoken, "rivals"))
|
||||
{
|
||||
size_t len = strlen(value);
|
||||
size_t i;
|
||||
char rivalname[SKINNAMESIZE] = "";
|
||||
UINT8 pos = 0;
|
||||
UINT8 numrivals = 0;
|
||||
|
||||
// Can't use strtok, because this function's already using it.
|
||||
// Using it causes it to upset the saved pointer,
|
||||
// corrupting the reading for the rest of the file.
|
||||
|
||||
// So instead we get to crawl through the value, character by character,
|
||||
// and write it down as we go, until we hit a comma or the end of the string.
|
||||
// Yaaay.
|
||||
|
||||
for (i = 0; i <= len; i++)
|
||||
{
|
||||
if (numrivals >= SKINRIVALS)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (value[i] == ',' || i == len)
|
||||
{
|
||||
STRBUFCPY(skin->rivals[numrivals], rivalname);
|
||||
strlwr(skin->rivals[numrivals]);
|
||||
numrivals++;
|
||||
|
||||
memset(rivalname, 0, sizeof (rivalname));
|
||||
pos = 0;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
rivalname[pos] = value[i];
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
else if (!R_ProcessPatchableFields(skin, stoken, value))
|
||||
CONS_Debug(DBG_SETUP, "R_AddSkins: Unknown keyword '%s' in S_SKIN lump #%d (WAD %s)\n", stoken, lump, wadfiles[wadnum]->filename);
|
||||
|
||||
|
|
@ -987,6 +1008,68 @@ next_token:
|
|||
HWR_AddPlayerModel(numskins);
|
||||
#endif
|
||||
|
||||
// Finally, conclude by setting up final properties.
|
||||
skin->namehash = quickncasehash(skin->name, SKINNAMESIZE);
|
||||
|
||||
{
|
||||
// Check to see if we have any custom skin wins data that we could substitute in.
|
||||
unloaded_skin_t *unloadedskin, *unloadedprev = NULL;
|
||||
for (unloadedskin = unloadedskins; unloadedskin; unloadedprev = unloadedskin, unloadedskin = unloadedskin->next)
|
||||
{
|
||||
if (unloadedskin->namehash != skin->namehash)
|
||||
continue;
|
||||
|
||||
if (strcasecmp(skin->name, unloadedskin->name) != 0)
|
||||
continue;
|
||||
|
||||
// Copy in wins, etc.
|
||||
M_Memcpy(&skin->records, &unloadedskin->records, sizeof(skin->records));
|
||||
|
||||
// Remove this entry from the chain.
|
||||
if (unloadedprev)
|
||||
{
|
||||
unloadedprev->next = unloadedskin->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
unloadedskins = unloadedskin->next;
|
||||
}
|
||||
|
||||
// Now... we assign everything which used this pointer the new skin id.
|
||||
UINT8 i;
|
||||
|
||||
cupheader_t *cup;
|
||||
for (cup = kartcupheaders; cup; cup = cup->next)
|
||||
{
|
||||
for (i = 0; i < KARTGP_MAX; i++)
|
||||
{
|
||||
if (cup->windata[i].best_skin.unloaded != unloadedskin)
|
||||
continue;
|
||||
cup->windata[i].best_skin.id = numskins;
|
||||
cup->windata[i].best_skin.unloaded = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
unloaded_cupheader_t *unloadedcup;
|
||||
for (unloadedcup = unloadedcupheaders; unloadedcup; unloadedcup = unloadedcup->next)
|
||||
{
|
||||
for (i = 0; i < KARTGP_MAX; i++)
|
||||
{
|
||||
if (unloadedcup->windata[i].best_skin.unloaded != unloadedskin)
|
||||
continue;
|
||||
unloadedcup->windata[i].best_skin.id = numskins;
|
||||
unloadedcup->windata[i].best_skin.unloaded = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, free.
|
||||
Z_Free(unloadedskin);
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
numskins++;
|
||||
}
|
||||
return;
|
||||
|
|
@ -1073,45 +1156,6 @@ void R_PatchSkins(UINT16 wadnum, boolean mainfile)
|
|||
STRBUFCPY(skin->realname, value);
|
||||
SYMBOLCONVERT(skin->realname)
|
||||
}
|
||||
else if (!stricmp(stoken, "rivals"))
|
||||
{
|
||||
size_t len = strlen(value);
|
||||
size_t i;
|
||||
char rivalname[SKINNAMESIZE] = "";
|
||||
UINT8 pos = 0;
|
||||
UINT8 numrivals = 0;
|
||||
|
||||
// Can't use strtok, because this function's already using it.
|
||||
// Using it causes it to upset the saved pointer,
|
||||
// corrupting the reading for the rest of the file.
|
||||
|
||||
// So instead we get to crawl through the value, character by character,
|
||||
// and write it down as we go, until we hit a comma or the end of the string.
|
||||
// Yaaay.
|
||||
|
||||
for (i = 0; i <= len; i++)
|
||||
{
|
||||
if (numrivals >= SKINRIVALS)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (value[i] == ',' || i == len)
|
||||
{
|
||||
STRBUFCPY(skin->rivals[numrivals], rivalname);
|
||||
strlwr(skin->rivals[numrivals]);
|
||||
numrivals++;
|
||||
|
||||
memset(rivalname, 0, sizeof (rivalname));
|
||||
pos = 0;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
rivalname[pos] = value[i];
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
else if (!R_ProcessPatchableFields(skin, stoken, value))
|
||||
CONS_Debug(DBG_SETUP, "R_PatchSkins: Unknown keyword '%s' in P_SKIN lump #%d (WAD %s)\n", stoken, lump, wadfiles[wadnum]->filename);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,8 @@ extern "C" {
|
|||
/// The skin_t struct
|
||||
struct skin_t
|
||||
{
|
||||
char name[SKINNAMESIZE+1]; // INT16 descriptive name of the skin
|
||||
char name[SKINNAMESIZE+1]; // descriptive name of the skin
|
||||
UINT32 namehash; // quickncasehash(->name, SKINNAMESIZE)
|
||||
UINT16 wadnum;
|
||||
skinflags_t flags;
|
||||
|
||||
|
|
@ -58,6 +59,8 @@ struct skin_t
|
|||
|
||||
fixed_t highresscale; // scale of highres, default is 0.5
|
||||
|
||||
skinrecord_t records;
|
||||
|
||||
char rivals[SKINRIVALS][SKINNAMESIZE+1]; // Your top 3 rivals for GP mode. Uses names so that you can reference skins that aren't added
|
||||
|
||||
// specific sounds per skin
|
||||
|
|
|
|||
|
|
@ -1534,7 +1534,7 @@ static boolean S_SoundTestDefLocked(musicdef_t *def)
|
|||
|
||||
// Is the level tied to SP progression?
|
||||
if ((mapheaderinfo[def->sequence.map]->menuflags & LF2_FINISHNEEDED)
|
||||
&& !(mapheaderinfo[def->sequence.map]->mapvisited & MV_BEATEN))
|
||||
&& !(mapheaderinfo[def->sequence.map]->records.mapvisited & MV_BEATEN))
|
||||
return true;
|
||||
|
||||
// Finally, do a full-fat map check.
|
||||
|
|
|
|||
|
|
@ -113,6 +113,9 @@ TYPEDEF (skincolor_t);
|
|||
|
||||
// doomstat.h
|
||||
TYPEDEF (precipprops_t);
|
||||
TYPEDEF (skinrecord_t);
|
||||
TYPEDEF (unloaded_skin_t);
|
||||
TYPEDEF (skinreference_t);
|
||||
TYPEDEF (recorddata_t);
|
||||
TYPEDEF (cupwindata_t);
|
||||
TYPEDEF (scene_t);
|
||||
|
|
@ -125,8 +128,10 @@ TYPEDEF (customoption_t);
|
|||
TYPEDEF (gametype_t);
|
||||
TYPEDEF (staffbrief_t);
|
||||
TYPEDEF (mapheader_t);
|
||||
TYPEDEF (unloaded_mapheader_t);
|
||||
TYPEDEF (tolinfo_t);
|
||||
TYPEDEF (cupheader_t);
|
||||
TYPEDEF (unloaded_cupheader_t);
|
||||
|
||||
// font.h
|
||||
TYPEDEF (font_t);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue