From fb8795c8da9372fe2a8313c1424eff7124c675b3 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 19 Aug 2023 12:21:15 +0100 Subject: [PATCH 01/21] M_FinaliseGameData Creates a central landing point where gamedata loads/creates can be finalised properly. In addition, gamedata wipes caused by data erase or custom SOC gamedata can no longer be saved in a partway corrupted state if they were to crash midway through. --- src/deh_soc.c | 1 + src/dehacked.c | 2 +- src/g_game.c | 9 +-------- src/m_cond.c | 15 +++++++++++++++ src/m_cond.h | 5 ++++- src/menus/options-data-erase-1.c | 5 ++++- 6 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/deh_soc.c b/src/deh_soc.c index 7e5613444..0194af15c 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -3007,6 +3007,7 @@ void readmaincfg(MYFILE *f, boolean mainfile) strlwr(gamedatafilename); savemoddata = true; majormods = false; + gamedata->loaded = false; // Also save a time attack folder filenamelen = strlen(gamedatafilename)-4; // Strip off the extension diff --git a/src/dehacked.c b/src/dehacked.c index c63ab376b..6d44b87fb 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -607,7 +607,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile) if (gamedataadded) G_LoadGameData(); - if (gamestate == GS_TITLESCREEN) + if (gamestate == GS_MENU || gamestate == GS_TITLESCREEN) { if (introchanged) { diff --git a/src/g_game.c b/src/g_game.c index 550324341..f90b1aaec 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4863,14 +4863,7 @@ void G_LoadGameData(void) finalisegamedata: { - // Don't consider loaded until it's a success! - // It used to do this much earlier, but this would cause the gamedata to - // save over itself when it I_Errors from the corruption landing point below, - // which can accidentally delete players' legitimate data if the code ever has any tiny mistakes! - gamedata->loaded = true; - - // Silent update unlockables in case they're out of sync with conditions - M_UpdateUnlockablesAndExtraEmblems(false, true); + M_FinaliseGameData(); return; } diff --git a/src/m_cond.c b/src/m_cond.c index b66ee1af8..de7a032e0 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -640,6 +640,21 @@ void M_ClearSecrets(void) gamedata->chaokeys = 3; // Start with 3 !! } +void M_FinaliseGameData(void) +{ + //M_PopulateChallengeGrid(); -- This can be done lazily when we actually need it + + // Don't consider loaded until it's a success! + // It used to do this much earlier, but this would cause the gamedata + // to save over itself when it I_Errors from corruption, which can + // accidentally delete players' legitimate data if the code ever has + // any tiny mistakes! + gamedata->loaded = true; + + // Silent update unlockables in case they're out of sync with conditions + M_UpdateUnlockablesAndExtraEmblems(false, true); +} + // ---------------------- // Condition set checking // ---------------------- diff --git a/src/m_cond.h b/src/m_cond.h index e93ef7857..b08ff611e 100644 --- a/src/m_cond.h +++ b/src/m_cond.h @@ -257,6 +257,8 @@ struct gamedata_t { // WHENEVER OR NOT WE'RE READY TO SAVE boolean loaded; + + // DEFERRED EVENTS RELATING TO CHALLENGE PROCESSING boolean deferredsave; boolean deferredconditioncheck; @@ -338,10 +340,11 @@ char *M_BuildConditionSetString(UINT16 unlockid); void M_AddRawCondition(UINT16 set, UINT8 id, conditiontype_t c, INT32 r, INT16 x1, INT16 x2, char *stringvar); void M_UpdateConditionSetsPending(void); -// Clearing secrets +// Gamedata clear/init void M_ClearConditionSet(UINT16 set); void M_ClearSecrets(void); void M_ClearStats(void); +void M_FinaliseGameData(void); boolean M_NotFreePlay(void); UINT16 M_CheckCupEmeralds(UINT8 difficulty); diff --git a/src/menus/options-data-erase-1.c b/src/menus/options-data-erase-1.c index a4a75202c..ac31e16e2 100644 --- a/src/menus/options-data-erase-1.c +++ b/src/menus/options-data-erase-1.c @@ -60,6 +60,9 @@ static void M_EraseDataResponse(INT32 ch) // Delete the data // see also G_LoadGameData // We do these in backwards order to prevent things from being immediately re-unlocked. + + gamedata->loaded = false; + if (optionsmenu.erasecontext & EC_TIMEATTACK) G_ClearRecords(); if (optionsmenu.erasecontext & EC_STATISTICS) @@ -67,7 +70,7 @@ static void M_EraseDataResponse(INT32 ch) if (optionsmenu.erasecontext & EC_CHALLENGES) M_ClearSecrets(); - M_UpdateUnlockablesAndExtraEmblems(false, true); + M_FinaliseGameData(); // Don't softlock the Stereo on if you won't be able to access it anymore!? if (soundtest.playing && M_SecretUnlocked(SECRET_SOUNDTEST, true) == false) From be1d3e49e88424ea111e723707586d13d658eab2 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 19 Aug 2023 14:44:01 +0100 Subject: [PATCH 02/21] Change indentation/bracketing on gamedata load for map records To make the next commit less painful to parse. Also fixes signedness of mapnum from INT16 to UINT16 --- src/g_game.c | 83 ++++++++++++++++++++++++++++------------------------ 1 file changed, 44 insertions(+), 39 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index f90b1aaec..19f203995 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4680,53 +4680,58 @@ void G_LoadGameData(void) numgamedatamapheaders = READUINT32(save.p); - for (i = 0; i < numgamedatamapheaders; i++) + if (numgamedatamapheaders) { - char mapname[MAXMAPLUMPNAME]; - INT16 mapnum; - READSTRINGL(save.p, mapname, MAXMAPLUMPNAME); - mapnum = G_MapNumber(mapname); - - 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]) + for (i = 0; i < numgamedatamapheaders; i++) { - // Valid mapheader, time to populate with record data. + char mapname[MAXMAPLUMPNAME]; + UINT16 mapnum; - dummyrecord.mapvisited &= MV_MAX; - M_Memcpy(&mapheaderinfo[mapnum]->records, &dummyrecord, sizeof(recorddata_t)); - } - else if ( - ((dummyrecord.mapvisited & MV_PERSISTUNLOADED) != 0 - && (dummyrecord.mapvisited & MV_BEATEN) != 0) - || dummyrecord.time != 0 - || dummyrecord.lap != 0 - ) - { - // Invalid, but we don't want to lose all the juicy statistics. - // Instead, update a FILO linked list of "unloaded mapheaders". + READSTRINGL(save.p, mapname, MAXMAPLUMPNAME); + mapnum = G_MapNumber(mapname); - 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); + recorddata_t dummyrecord; - // Insert at the head, just because it's convenient. - unloadedmap->next = unloadedmapheaders; - unloadedmapheaders = unloadedmap; + dummyrecord.mapvisited = READUINT8(save.p); + dummyrecord.time = (tic_t)READUINT32(save.p); + dummyrecord.lap = (tic_t)READUINT32(save.p); - // Finally, copy into. - M_Memcpy(&unloadedmap->records, &dummyrecord, sizeof(recorddata_t)); + if (mapnum < nummapheaders && mapheaderinfo[mapnum]) + { + // Valid mapheader, time to populate with record data. + + dummyrecord.mapvisited &= MV_MAX; + M_Memcpy(&mapheaderinfo[mapnum]->records, &dummyrecord, sizeof(recorddata_t)); + } + else if ( + ((dummyrecord.mapvisited & MV_PERSISTUNLOADED) != 0 + && (dummyrecord.mapvisited & MV_BEATEN) != 0) + || dummyrecord.time != 0 + || dummyrecord.lap != 0 + ) + { + // 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)); + } } } From 1d06637a3880845bafcf03563ea1f961de80cda3 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 19 Aug 2023 15:06:36 +0100 Subject: [PATCH 03/21] First pass at assigning unique spraycans to level headers Increments gamedata minor version, be aware - M_AssignSpraycans - Called in M_FinaliseGameData. - Attaches a hardcoded set of colours to all race maps in cup order, stopping once we run out. - The colours are shuffled, with some "freebies" always at the head of the list. - Integrates partial lists pretty well. - In DEVELOP builds, I_Errors if it produces corrupted state. - G_LoadGameData, G_SaveGameData - Save & Load is implemented for these assignments --- src/deh_soc.c | 7 ++ src/deh_tables.c | 1 + src/doomdef.h | 4 +- src/doomstat.h | 3 + src/g_game.c | 88 +++++++++++++++++++++- src/k_menudraw.c | 24 +++++- src/m_cond.c | 188 +++++++++++++++++++++++++++++++++++++++++++++-- src/m_cond.h | 10 +++ src/p_setup.c | 2 + src/typedef.h | 1 + 10 files changed, 315 insertions(+), 13 deletions(-) diff --git a/src/deh_soc.c b/src/deh_soc.c index 0194af15c..a748747c1 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -216,6 +216,13 @@ void clear_levels(void) } } + if (gamedata) + { + UINT16 i; + for (i = 1; i < MAXCANCOLORS; i++) + gamedata->spraycans[i].map = 0; + } + // Exit the current gamemap as a safeguard if (Playing()) COM_BufAddText("exitgame"); // Command_ExitGame_f() but delayed diff --git a/src/deh_tables.c b/src/deh_tables.c index 97a78e936..58f70bf80 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -6538,6 +6538,7 @@ struct int_const_s const INT_CONST[] = { // SKINCOLOR_ doesn't include these..! {"MAXSKINCOLORS",MAXSKINCOLORS}, + {"MAXCANCOLORS",MAXCANCOLORS}, {"FIRSTSUPERCOLOR",FIRSTSUPERCOLOR}, {"NUMSUPERCOLORS",NUMSUPERCOLORS}, diff --git a/src/doomdef.h b/src/doomdef.h index 75264bbd0..c9f8b1702 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -346,7 +346,9 @@ typedef enum SKINCOLOR_BLOSSOM, SKINCOLOR_TAFFY, - FIRSTSUPERCOLOR, + MAXCANCOLORS, + + FIRSTSUPERCOLOR = MAXCANCOLORS, // Super special awesome Super flashing colors! SKINCOLOR_SUPERSILVER1 = FIRSTSUPERCOLOR, diff --git a/src/doomstat.h b/src/doomstat.h index c4f8b37e7..eecb6d1c7 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -531,6 +531,9 @@ struct mapheader_t UINT8 precutscenenum; ///< Cutscene number to play BEFORE a level starts. UINT8 cutscenenum; ///< Cutscene number to use, 0 for none. + UINT32 _saveid; ///< Purely assistive in gamedata save processes + UINT16 cachedcan; ///< Cached Spraycan ID + // Lua information UINT8 numCustomOptions; ///< Internal. For Lua custom value support. customoption_t *customopts; ///< Custom options. Allocated dynamically for space reasons. Be careful. diff --git a/src/g_game.c b/src/g_game.c index 19f203995..718b7836d 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4357,7 +4357,7 @@ void G_LoadGameSettings(void) } #define GD_VERSIONCHECK 0xBA5ED123 // Change every major version, as usual -#define GD_VERSIONMINOR 5 // Change every format update +#define GD_VERSIONMINOR 6 // Change every format update typedef enum { @@ -4678,10 +4678,17 @@ void G_LoadGameData(void) } } + UINT16 *tempmapidreferences = NULL; + numgamedatamapheaders = READUINT32(save.p); if (numgamedatamapheaders) { + tempmapidreferences = Z_Malloc( + numgamedatamapheaders * sizeof (UINT16), + PU_STATIC, + NULL + ); for (i = 0; i < numgamedatamapheaders; i++) { @@ -4691,6 +4698,7 @@ void G_LoadGameData(void) READSTRINGL(save.p, mapname, MAXMAPLUMPNAME); mapnum = G_MapNumber(mapname); + tempmapidreferences[i] = (UINT16)mapnum; recorddata_t dummyrecord; @@ -4735,6 +4743,49 @@ void G_LoadGameData(void) } } + if (versionMinor > 5) + { + UINT16 numgamedatacans = READUINT32(save.p); + + if (numgamedatacans != MAXCANCOLORS - 1) + { + save.p += (1 + 4) * numgamedatacans; + } + else + { + for (i = 1; i < MAXCANCOLORS; i++) + { + gamedata->spraycans[i].got = (boolean)READUINT8(save.p); + gamedata->spraycans[i].map = 0; + + UINT32 _saveid = READUINT32(save.p); + + if (_saveid >= numgamedatamapheaders) + { + //CONS_Printf("LOAD - Color %s - id %u, map 0 (invalid id)\n", skincolors[i].name, _saveid); + continue; + } + + UINT16 map = tempmapidreferences[_saveid]; + if (map >= nummapheaders || !mapheaderinfo[map]) + { + //CONS_Printf("LOAD - Color %s - id %u, map 0 (unloaded header)\n", skincolors[i].name, _saveid); + continue; + } + + //CONS_Printf("LOAD - Color %s - id %u, map %d\n", skincolors[i].name, _saveid, map+1); + + gamedata->spraycans[i].map = map+1; + mapheaderinfo[map]->cachedcan = i; + + numgamedatacans--; // this one was successfully placed + } + + gamedata->allspraycansplaced = (numgamedatacans == 0); + //CONS_Printf("CCC - all spray cans placed? %c\n", gamedata->allspraycansplaced ? 'Y' : 'N'); + } + } + if (versionMinor > 1) { numgamedatacups = READUINT32(save.p); @@ -4862,6 +4913,8 @@ void G_LoadGameData(void) if (tempskinreferences) Z_Free(tempskinreferences); + if (tempmapidreferences) + Z_Free(tempmapidreferences); // done P_SaveBufferFree(&save); @@ -4983,12 +5036,16 @@ void G_SaveGameData(void) for (i = 0; i < nummapheaders; i++) { + // No spraycan attached. + if (mapheaderinfo[i]->cachedcan == 0 // 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)) + && !(mapheaderinfo[i]->records.mapvisited & MV_MAX)) { + mapheaderinfo[i]->_saveid = UINT32_MAX; continue; } + mapheaderinfo[i]->_saveid = numgamedatamapheaders; numgamedatamapheaders++; } @@ -5012,6 +5069,9 @@ void G_SaveGameData(void) length += 4 + (numgamedatamapheaders * (MAXMAPLUMPNAME+1+4+4)); + length += 4 + ((MAXCANCOLORS - 1) * (1 + 4)); + + UINT32 numgamedatacups = 0; unloaded_cupheader_t *unloadedcup; @@ -5206,7 +5266,8 @@ void G_SaveGameData(void) for (i = 0; i < nummapheaders; i++) { - if (!(mapheaderinfo[i]->records.mapvisited & MV_MAX)) + if (mapheaderinfo[i]->cachedcan == 0 + && !(mapheaderinfo[i]->records.mapvisited & MV_MAX)) continue; WRITESTRINGL(save.p, mapheaderinfo[i]->lumpname, MAXMAPLUMPNAME); @@ -5247,6 +5308,27 @@ void G_SaveGameData(void) } } + WRITEUINT32(save.p, MAXCANCOLORS - 1); // 4 + + // (MAXCANCOLORS - 1) * (1 + 4) + + for (i = 1; i < MAXCANCOLORS; i++) + { + WRITEUINT8(save.p, gamedata->spraycans[i].got); + + UINT32 _saveid = UINT32_MAX; + + UINT16 map = gamedata->spraycans[i].map; + + if (map > 0 && map <= nummapheaders && mapheaderinfo[map - 1]) + { + _saveid = mapheaderinfo[map - 1]->_saveid; + } + + //CONS_Printf("SAVE - Color %s - id %u, map %d\n", skincolors[i].name, _saveid, map); + + WRITEUINT32(save.p, _saveid); + } WRITEUINT32(save.p, numgamedatacups); // 4 diff --git a/src/k_menudraw.c b/src/k_menudraw.c index b789a97f4..6b7b6fa7f 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -6049,6 +6049,26 @@ challengedesc: static void M_DrawMapMedals(INT32 mapnum, INT32 x, INT32 y) { UINT8 lasttype = UINT8_MAX, curtype; + + boolean start = false; + + if (mapheaderinfo[mapnum]->cachedcan != 0 && mapheaderinfo[mapnum]->cachedcan < MAXCANCOLORS) + { + V_DrawSmallMappedPatch(x, y, 0, W_CachePatchName("GOTITA", PU_CACHE), + R_GetTranslationColormap(TC_RAINBOW, mapheaderinfo[mapnum]->cachedcan, GTC_MENUCACHE)); + //V_DrawRightAlignedThinString(x - 2, y, 0, skincolors[mapheaderinfo[mapnum]->cachedcan].name); + x -= 8; + + start = true; + } + + // Shift over if emblem is of a different discipline + if (start) + x -= 4; + + // M_GetLevelEmblems is ONE-indexed, urgh + mapnum++; + emblem_t *emblem = M_GetLevelEmblems(mapnum); while (emblem) @@ -6091,7 +6111,7 @@ static void M_DrawMapMedals(INT32 mapnum, INT32 x, INT32 y) if (gamedata->collected[emblem-emblemlocations]) V_DrawSmallMappedPatch(x, y, 0, W_CachePatchName(M_GetEmblemPatch(emblem, false), PU_CACHE), - R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(emblem), GTC_MENUCACHE)); + R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(emblem), GTC_MENUCACHE)); else V_DrawSmallScaledPatch(x, y, 0, W_CachePatchName("NEEDIT", PU_CACHE)); @@ -6246,7 +6266,7 @@ static void M_DrawStatsMaps(void) } } - M_DrawMapMedals(mnum+1, medalspos - 8, y); + M_DrawMapMedals(mnum, medalspos - 8, y); if (mapheaderinfo[mnum]->menuttl[0]) { diff --git a/src/m_cond.c b/src/m_cond.c index de7a032e0..ae8143b2d 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -621,14 +621,23 @@ void M_ClearStats(void) void M_ClearSecrets(void) { - INT32 i; + memset(gamedata->collected, 0, sizeof(gamedata->collected)); + memset(gamedata->unlocked, 0, sizeof(gamedata->unlocked)); + memset(gamedata->unlockpending, 0, sizeof(gamedata->unlockpending)); + if (!dedicated) + memset(netUnlocked, 0, sizeof(netUnlocked)); + memset(gamedata->achieved, 0, sizeof(gamedata->achieved)); - for (i = 0; i < MAXEMBLEMS; ++i) - gamedata->collected[i] = false; - for (i = 0; i < MAXUNLOCKABLES; ++i) - gamedata->unlocked[i] = gamedata->unlockpending[i] = netUnlocked[i] = false; - for (i = 0; i < MAXCONDITIONSETS; ++i) - gamedata->achieved[i] = false; + gamedata->allspraycansplaced = false; + memset(gamedata->spraycans, 0, sizeof(gamedata->spraycans)); + + INT32 i; + for (i = 0; i < nummapheaders; i++) + { + if (!mapheaderinfo[i]) + continue; + mapheaderinfo[i]->cachedcan = 0; + } Z_Free(gamedata->challengegrid); gamedata->challengegrid = NULL; @@ -640,10 +649,175 @@ void M_ClearSecrets(void) gamedata->chaokeys = 3; // Start with 3 !! } +// For lack of a better idea on where to put this +static void M_Shuffle_UINT16(UINT16 *list, size_t len) +{ + size_t i; + UINT16 temp; + while (--len > 1) // no need to swap on == + { + i = M_RandomKey(len); + temp = list[i]; + list[i] = list[len]; + list[len] = temp; + } +} + +static void M_AssignSpraycans(void) +{ + // Very convenient I'm programming this on + // the release date of "Bomb Rush Cyberfunk". + // ~toast 180823 (committed a day later) + + if (gamedata->allspraycansplaced) + return; + + // Init ordered list of skincolors + UINT16 tempcanlist[MAXCANCOLORS]; + size_t listlen = 0; + + // Todo one of these should be a freebie + UINT16 prependlist[] = + { + SKINCOLOR_RED, + SKINCOLOR_ORANGE, + SKINCOLOR_YELLOW, + SKINCOLOR_GREEN, + SKINCOLOR_BLUE, + SKINCOLOR_PURPLE, + 0 + }; + + UINT16 i; + + for (i = 0; prependlist[i]; i++) + { + if (gamedata->spraycans[prependlist[i]].map > 0 + && gamedata->spraycans[prependlist[i]].map <= nummapheaders) + continue; + + CONS_Printf("DDD - Prepending %d\n", prependlist[i]); + + tempcanlist[listlen] = prependlist[i]; + gamedata->spraycans[prependlist[i]].got = 2; // invalid set to detect in below loop, rather than having to iterate over prependlist again + listlen++; + } + + size_t prepend = listlen; + + for (i = 1; i < MAXCANCOLORS; i++) + { + if (gamedata->spraycans[i].map > 0 + && gamedata->spraycans[i].map <= nummapheaders) + continue; + + if (gamedata->spraycans[i].got == 2) + { + // re-make valid, reject duplicating prepended + gamedata->spraycans[i].got = false; + continue; + } + + CONS_Printf("DDD - Adding %d\n", i); + + tempcanlist[listlen] = i; + listlen++; + } + + if (!listlen) + goto cansdone; + + if (prepend > 0) + { + // Swap the prepend for random order + M_Shuffle_UINT16(tempcanlist, prepend); + } + + if (listlen > prepend) + { + // Swap everything else for random order + M_Shuffle_UINT16(tempcanlist + prepend, listlen - prepend); + } + + i = 0; + + cupheader_t *cup; + + UINT16 level; + + for (cup = kartcupheaders; cup; cup = cup->next) + { + UINT8 j; + for (j = 0; j < cup->numlevels; j++) + { + level = cup->cachedlevels[j]; + + if (level > nummapheaders) + continue; + + if (mapheaderinfo[level]->cachedcan != 0) + continue; + + gamedata->spraycans[tempcanlist[i]].map = level + 1; + mapheaderinfo[level]->cachedcan = tempcanlist[i]; + + if (++i < listlen) + continue; + + goto cansdone; + } + } + + for (level = 0; level < nummapheaders; level++) + { + if (!mapheaderinfo[level] + || !(mapheaderinfo[level]->typeoflevel & TOL_RACE) + || mapheaderinfo[level]->cachedcan != 0) + continue; + + gamedata->spraycans[tempcanlist[i]].map = level + 1; + mapheaderinfo[level]->cachedcan = tempcanlist[i]; + + if (++i < listlen) + continue; + + goto cansdone; + } + +cansdone: + +#ifdef PARANOIA + for (i = 1; i < MAXCANCOLORS; i++) + { + if (gamedata->spraycans[i].map == 0) + I_Error("CANPROBLEM - BAD MAP FOR CAN %d\n", i); + if (gamedata->spraycans[i].map > nummapheaders) + I_Error("CANPROBLEM - TOO BIG MAP FOR CAN %d\n", i); + if (mapheaderinfo[gamedata->spraycans[i].map-1]->cachedcan != i) + I_Error("CANPROBLEM - MAP AND CAN DISAGREE FOR %d (%d)\n", i, mapheaderinfo[gamedata->spraycans[i].map-1]->cachedcan); + } + + for (i = 0; i < nummapheaders; i++) + { + if (!mapheaderinfo[i] || mapheaderinfo[i]->cachedcan == 0) + continue; + if (mapheaderinfo[i]->cachedcan > MAXCANCOLORS) + I_Error("MAPPROBLEM - BAD CAN FOR MAP %d\n", i); + if (gamedata->spraycans[mapheaderinfo[i]->cachedcan].map-1 != i) + I_Error("MAPPROBLEM - CAN AND MAP DISAGREE FOR %d (%d)\n", i, gamedata->spraycans[mapheaderinfo[i]->cachedcan].map-1); + } +#endif + + gamedata->allspraycansplaced = true; +} + void M_FinaliseGameData(void) { //M_PopulateChallengeGrid(); -- This can be done lazily when we actually need it + // Place the spraycans, which CAN'T be done lazily. + M_AssignSpraycans(); + // Don't consider loaded until it's a success! // It used to do this much earlier, but this would cause the gamedata // to save over itself when it I_Errors from corruption, which can diff --git a/src/m_cond.h b/src/m_cond.h index b08ff611e..e01c1b2d9 100644 --- a/src/m_cond.h +++ b/src/m_cond.h @@ -251,6 +251,12 @@ typedef enum { GDGT_MAX } roundsplayed_t; +struct candata_t +{ + UINT16 map; + boolean got; +}; + // GAMEDATA STRUCTURE // Everything that would get saved in gamedata.dat struct gamedata_t @@ -272,6 +278,10 @@ struct gamedata_t boolean unlocked[MAXUNLOCKABLES]; boolean unlockpending[MAXUNLOCKABLES]; + // SPRAYCANS COLLECTED + boolean allspraycansplaced; + candata_t spraycans[MAXCANCOLORS]; + // CHALLENGE GRID UINT16 challengegridwidth; UINT16 *challengegrid; diff --git a/src/p_setup.c b/src/p_setup.c index 3f9bfcd2e..b687cd347 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -460,6 +460,8 @@ static void P_ClearSingleMapHeaderInfo(INT16 num) mapheaderinfo[num]->justPlayed = 0; mapheaderinfo[num]->anger = 0; + mapheaderinfo[num]->cachedcan = 0; + mapheaderinfo[num]->customopts = NULL; mapheaderinfo[num]->numCustomOptions = 0; } diff --git a/src/typedef.h b/src/typedef.h index 7bbc232b6..a27ca364f 100644 --- a/src/typedef.h +++ b/src/typedef.h @@ -238,6 +238,7 @@ TYPEDEF (condition_t); TYPEDEF (conditionset_t); TYPEDEF (emblem_t); TYPEDEF (unlockable_t); +TYPEDEF (candata_t); TYPEDEF (gamedata_t); TYPEDEF (challengegridextradata_t); From b03c82b8b26cfd2b74d1973f991e2bf6d0b3121d Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 19 Aug 2023 15:09:18 +0100 Subject: [PATCH 04/21] Implement UC_SPRAYCAN condition Currently impossible to achieve, but will work once I draw the rest of the owl --- src/deh_soc.c | 6 ++++++ src/m_cond.c | 26 ++++++++++++++++++++++++++ src/m_cond.h | 2 ++ 3 files changed, 34 insertions(+) diff --git a/src/deh_soc.c b/src/deh_soc.c index a748747c1..a092384f6 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -2620,6 +2620,12 @@ static void readcondition(UINT16 set, UINT32 id, char *word2) stringvar = Z_StrDup(params[1]); re = -1; } + else if (fastcmp(params[0], "SPRAYCAN")) + { + PARAMCHECK(1); + ty = UC_SPRAYCAN; + re = get_skincolor(params[1]); + } else if ((offset=0) || fastcmp(params[0], "AND") || (++offset && fastcmp(params[0], "COMMA"))) { diff --git a/src/m_cond.c b/src/m_cond.c index ae8143b2d..dee2c008e 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -1059,6 +1059,14 @@ boolean M_CheckCondition(condition_t *cn, player_t *player) return false; case UC_PASSWORD: return (cn->stringvar == NULL); + case UC_SPRAYCAN: + { + if (cn->requirement <= 0 + || cn->requirement >= MAXCANCOLORS) + return false; + + return gamedata->spraycans[cn->requirement].got; + } // Just for string building case UC_AND: @@ -1511,6 +1519,24 @@ static const char *M_GetConditionString(condition_t *cn) return NULL; case UC_PASSWORD: return "enter a secret password"; + case UC_SPRAYCAN: + { + if (cn->requirement <= 0 + || cn->requirement >= MAXCANCOLORS) + return va("INVALID SPRAYCAN COLOR \"%d\"", cn->requirement); + + INT32 checkLevel = gamedata->spraycans[cn->requirement].map - 1; + + if (checkLevel < 0 || checkLevel >= nummapheaders || !mapheaderinfo[checkLevel]) + return va("INVALID SPRAYCAN MAP \"%d:%d\"", cn->requirement, checkLevel); + + title = BUILDCONDITIONTITLE(checkLevel); + + work = va("%s: grab the spraycan", title); + + Z_Free(title); + return work; + } case UC_AND: return "&"; diff --git a/src/m_cond.h b/src/m_cond.h index e01c1b2d9..09c850aa6 100644 --- a/src/m_cond.h +++ b/src/m_cond.h @@ -58,6 +58,8 @@ typedef enum UC_PASSWORD, // Type in something funny + UC_SPRAYCAN, // Grab a spraycan + // Just for string building UC_AND, UC_COMMA, From 78850c48b25c3a548a40023a9133a35fa65e964b Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 19 Aug 2023 17:16:36 +0100 Subject: [PATCH 05/21] Disable some testing prints --- src/m_cond.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/m_cond.c b/src/m_cond.c index dee2c008e..d6921a30c 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -696,7 +696,7 @@ static void M_AssignSpraycans(void) && gamedata->spraycans[prependlist[i]].map <= nummapheaders) continue; - CONS_Printf("DDD - Prepending %d\n", prependlist[i]); + //CONS_Printf("DDD - Prepending %d\n", prependlist[i]); tempcanlist[listlen] = prependlist[i]; gamedata->spraycans[prependlist[i]].got = 2; // invalid set to detect in below loop, rather than having to iterate over prependlist again @@ -718,7 +718,7 @@ static void M_AssignSpraycans(void) continue; } - CONS_Printf("DDD - Adding %d\n", i); + //CONS_Printf("DDD - Adding %d\n", i); tempcanlist[listlen] = i; listlen++; From d19e98beb836daf4ece19f7c5fe34d558629357f Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 19 Aug 2023 21:33:49 +0100 Subject: [PATCH 06/21] Proper-Nounify the Spray Cans on the Challenges descriptions --- src/m_cond.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/m_cond.c b/src/m_cond.c index d6921a30c..554cba4a6 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -1532,7 +1532,7 @@ static const char *M_GetConditionString(condition_t *cn) title = BUILDCONDITIONTITLE(checkLevel); - work = va("%s: grab the spraycan", title); + work = va("%s: grab the Spray Can", title); Z_Free(title); return work; From 3036eaf35db038da08d4ba5fbc8e822ccdb0485b Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 19 Aug 2023 22:11:56 +0100 Subject: [PATCH 07/21] MT_EMBLEM: Rework grabbable conditions, so you pass through collected ones in both offline and online for consistency --- src/p_inter.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/p_inter.c b/src/p_inter.c index fb2a7a071..9d3751395 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -596,26 +596,22 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) // Secret emblem thingy case MT_EMBLEM: { - boolean gotcollected = false; - if (!P_CanPickupEmblem(player, special->health - 1)) return; - if (P_IsLocalPlayer(player) && !gamedata->collected[special->health-1]) + if (P_IsLocalPlayer(player)) { - gamedata->collected[special->health-1] = gotcollected = true; - if (!M_UpdateUnlockablesAndExtraEmblems(true, true)) - S_StartSound(NULL, sfx_ncitem); - gamedata->deferredsave = true; + if (!gamedata->collected[special->health-1]) + { + gamedata->collected[special->health-1] = true; + if (!M_UpdateUnlockablesAndExtraEmblems(true, true)) + S_StartSound(NULL, sfx_ncitem); + gamedata->deferredsave = true; + } } - if (netgame) - { - // Don't delete the object in netgames, just fade it. - return; - } - - break; + // Don't delete the object, just fade it. + return; } // CTF Flags From dc695e7acf3dbf2b4cc74376e336c2045956385e Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 19 Aug 2023 22:21:20 +0100 Subject: [PATCH 08/21] First pass at implementing Spray Can pickups - Replaces a few D00DKart objects because the doomednum specifically replaced one of these - Reports on load if the map has too many, or if one's assigned but the object doesn't exist --- src/deh_tables.c | 28 +------ src/doomstat.h | 2 + src/g_game.c | 2 + src/info.c | 211 +++++++---------------------------------------- src/info.h | 30 ++----- src/k_menudraw.c | 32 +++---- src/p_inter.c | 37 +++++++++ src/p_local.h | 2 + src/p_mobj.c | 36 +++++++- src/p_saveg.c | 4 + src/p_setup.c | 17 ++++ 11 files changed, 156 insertions(+), 245 deletions(-) diff --git a/src/deh_tables.c b/src/deh_tables.c index 58f70bf80..130ffbf40 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -1190,6 +1190,9 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_EMBLEM25", "S_EMBLEM26", + // Spray Can + "S_SPRAYCAN", + // Chaos Emeralds "S_CHAOSEMERALD1", "S_CHAOSEMERALD2", @@ -3921,24 +3924,6 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_APPLE7", "S_APPLE8", - // D00Dkart - Fall Flowers - "S_DOOD_FLOWER1", - "S_DOOD_FLOWER2", - "S_DOOD_FLOWER3", - "S_DOOD_FLOWER4", - "S_DOOD_FLOWER5", - "S_DOOD_FLOWER6", - - // D00Dkart - Super Circuit Box - "S_DOOD_BOX1", - "S_DOOD_BOX2", - "S_DOOD_BOX3", - "S_DOOD_BOX4", - "S_DOOD_BOX5", - - // D00Dkart - Diddy Kong Racing Bumper - "S_DOOD_BALLOON", - // Chaotix Big Ring "S_BIGRING01", "S_BIGRING02", @@ -4805,6 +4790,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_REDFLAG", // Red CTF Flag "MT_BLUEFLAG", // Blue CTF Flag "MT_EMBLEM", + "MT_SPRAYCAN", "MT_EMERALD", "MT_EMERALDSPARK", "MT_EMERHUNT", // Emerald Hunt @@ -5580,12 +5566,6 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_BIGPUMA", "MT_APPLE", - "MT_DOOD_FLOWER1", - "MT_DOOD_FLOWER2", - "MT_DOOD_FLOWER3", - "MT_DOOD_FLOWER4", - "MT_DOOD_BOX", - "MT_DOOD_BALLOON", "MT_BIGRING", "MT_SNES_DONUTBUSH1", diff --git a/src/doomstat.h b/src/doomstat.h index eecb6d1c7..b1fae2b26 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -713,6 +713,8 @@ extern INT32 luabanks[NUM_LUABANKS]; extern INT32 nummaprings; //keep track of spawned rings/coins +extern UINT8 numspraycans; + extern UINT32 bluescore; ///< Blue Team Scores extern UINT32 redscore; ///< Red Team Scores diff --git a/src/g_game.c b/src/g_game.c index 718b7836d..17e5736d1 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -215,6 +215,8 @@ UINT32 bluescore, redscore; // CTF and Team Match team scores // ring count... for PERFECT! INT32 nummaprings = 0; +UINT8 numspraycans = 0; + // Elminates unnecessary searching. boolean CheckForBustableBlocks; boolean CheckForBouncySector; diff --git a/src/info.c b/src/info.c index a3d358d7e..d6fa42032 100644 --- a/src/info.c +++ b/src/info.c @@ -636,7 +636,7 @@ char sprnames[NUMSPRITES + 1][5] = "POKE", // Pokey "AUDI", // Audience members "DECO", // Old 1.0 Kart Decoratives + New misc ones - "DOOD", // All the old D00Dkart objects + "SPCN", // Spray Can replaces all the old D00Dkart objects "SNES", // Sprites for SNES remake maps "GBAS", // Sprites for GBA remake maps "SPRS", // Sapphire Coast Spring Shell @@ -1860,6 +1860,9 @@ state_t states[NUMSTATES] = {SPR_EMBM, 24, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM25 {SPR_EMBM, 25, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM26 + // Spray Can + {SPR_SPCN, FF_ANIMATE|FF_SEMIBRIGHT, -1, {NULL}, 15, 2, S_NULL}, // S_SPRAYCAN + // Chaos Emeralds {SPR_EMRC, FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_CHAOSEMERALD2}, // S_CHAOSEMERALD1 {SPR_EMRC, FF_FULLBRIGHT|FF_ADD, 1, {NULL}, 0, 0, S_CHAOSEMERALD1}, // S_CHAOSEMERALD2 @@ -4626,21 +4629,6 @@ state_t states[NUMSTATES] = {SPR_DECO, FF_FULLBRIGHT|20, 2, {NULL}, 0, 0, S_APPLE8}, //S_APPLE7 {SPR_DECO, FF_FULLBRIGHT|21, 2, {NULL}, 0, 0, S_APPLE1}, //S_APPLE8 - {SPR_DOOD, 0, -1, {NULL}, 0, 0, S_NULL}, // S_DOOD_FLOWER1 - {SPR_DOOD, 1, 14, {NULL}, 0, 0, S_DOOD_FLOWER3}, // S_DOOD_FLOWER2 - {SPR_DOOD, 2, 14, {NULL}, 0, 0, S_DOOD_FLOWER2}, // S_DOOD_FLOWER3 - {SPR_DOOD, 3, 7, {NULL}, 0, 0, S_DOOD_FLOWER5}, // S_DOOD_FLOWER4 - {SPR_DOOD, 4, 7, {NULL}, 0, 0, S_DOOD_FLOWER4}, // S_DOOD_FLOWER5 - {SPR_DOOD, 5, -1, {NULL}, 0, 0, S_NULL}, // S_DOOD_FLOWER6 - - {SPR_DOOD, 6, 2, {NULL}, 0, 0, S_DOOD_BOX2}, // S_DOOD_BOX1 - {SPR_DOOD, 7, 2, {NULL}, 0, 0, S_DOOD_BOX3}, // S_DOOD_BOX2 - {SPR_DOOD, 8, 2, {NULL}, 0, 0, S_DOOD_BOX4}, // S_DOOD_BOX3 - {SPR_DOOD, 9, 2, {NULL}, 0, 0, S_DOOD_BOX5}, // S_DOOD_BOX4 - {SPR_DOOD, 10, 2, {NULL}, 0, 0, S_DOOD_BOX1}, // S_DOOD_BOX5 - - {SPR_DOOD, 11, -1, {NULL}, 0, 0, S_NULL}, // S_DOOD_BALLOON - {SPR_BRNG, 0, 2, {NULL}, 0, 0, S_BIGRING02}, // S_BIGRING01 {SPR_BRNG, 1, 2, {NULL}, 0, 0, S_BIGRING03}, // S_BIGRING02 {SPR_BRNG, 2, 2, {NULL}, 0, 0, S_BIGRING04}, // S_BIGRING03 @@ -8272,7 +8260,34 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 4, // mass 0, // damage sfx_None, // activesound - MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags + MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + + { // MT_SPRAYCAN + 2807, // doomednum + S_SPRAYCAN, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 30*FRACUNIT, // radius + 80*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -25673,168 +25688,6 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, - { // MT_DOOD_FLOWER1 - 2805, // doomednum - S_DOOD_FLOWER1, // spawnstate - 1000, // spawnhealth - S_NULL, // seestate - sfx_None, // seesound - 8, // reactiontime - sfx_None, // attacksound - S_NULL, // painstate - 0, // painchance - sfx_None, // painsound - S_NULL, // meleestate - S_NULL, // missilestate - S_NULL, // deathstate - S_NULL, // xdeathstate - sfx_None, // deathsound - 0, // speed - 1048576, // radius - 2097152, // height - 0, // display offset - 100, // mass - 0, // damage - sfx_None, // activesound - 33558528, // flags - S_NULL // raisestate - }, - - { // MT_DOOD_FLOWER2 - 2800, // doomednum - S_DOOD_FLOWER2, // spawnstate - 1000, // spawnhealth - S_NULL, // seestate - sfx_None, // seesound - 8, // reactiontime - sfx_None, // attacksound - S_NULL, // painstate - 0, // painchance - sfx_None, // painsound - S_NULL, // meleestate - S_NULL, // missilestate - S_NULL, // deathstate - S_NULL, // xdeathstate - sfx_None, // deathsound - 0, // speed - 1048576, // radius - 2621440, // height - 0, // display offset - 100, // mass - 0, // damage - sfx_None, // activesound - 33558528, // flags - S_NULL // raisestate - }, - - { // MT_DOOD_FLOWER3 - 2801, // doomednum - S_DOOD_FLOWER4, // spawnstate - 1000, // spawnhealth - S_NULL, // seestate - sfx_None, // seesound - 8, // reactiontime - sfx_None, // attacksound - S_NULL, // painstate - 0, // painchance - sfx_None, // painsound - S_NULL, // meleestate - S_NULL, // missilestate - S_NULL, // deathstate - S_NULL, // xdeathstate - sfx_None, // deathsound - 0, // speed - 1048576, // radius - 6291456, // height - 0, // display offset - 100, // mass - 0, // damage - sfx_None, // activesound - 33558528, // flags - S_NULL // raisestate - }, - - { // MT_DOOD_FLOWER4 - 2802, // doomednum - S_DOOD_FLOWER6, // spawnstate - 1000, // spawnhealth - S_NULL, // seestate - sfx_None, // seesound - 8, // reactiontime - sfx_None, // attacksound - S_NULL, // painstate - 0, // painchance - sfx_None, // painsound - S_NULL, // meleestate - S_NULL, // missilestate - S_NULL, // deathstate - S_NULL, // xdeathstate - sfx_None, // deathsound - 0, // speed - 524288, // radius - 2097152, // height - 0, // display offset - 100, // mass - 0, // damage - sfx_None, // activesound - 33558528, // flags - S_NULL // raisestate - }, - - { // MT_DOOD_BOX - 2809, // doomednum - S_DOOD_BOX1, // spawnstate - 1000, // spawnhealth - S_NULL, // seestate - sfx_None, // seesound - 8, // reactiontime - sfx_None, // attacksound - S_NULL, // painstate - 0, // painchance - sfx_None, // painsound - S_NULL, // meleestate - S_NULL, // missilestate - S_NULL, // deathstate - S_NULL, // xdeathstate - sfx_None, // deathsound - 0, // speed - 1048576, // radius - 2097152, // height - 0, // display offset - 100, // mass - 0, // damage - sfx_None, // activesound - 33554944, // flags - S_NULL // raisestate - }, - - { // MT_DOOD_BALLOON - 2807, // doomednum - S_DOOD_BALLOON, // spawnstate - 1000, // spawnhealth - S_NULL, // seestate - sfx_None, // seesound - 8, // reactiontime - sfx_None, // attacksound - S_NULL, // painstate - 0, // painchance - sfx_None, // painsound - S_NULL, // meleestate - S_NULL, // missilestate - S_NULL, // deathstate - S_NULL, // xdeathstate - sfx_None, // deathsound - 0, // speed - 91*FRACUNIT, // radius - 166*FRACUNIT, // height - 0, // display offset - 0, // mass - 0, // damage - sfx_None, // activesound - MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY, // flags - S_NULL // raisestate - }, - { // MT_BIGRING 2808, // doomednum S_BIGRING01, // spawnstate diff --git a/src/info.h b/src/info.h index 9dc14922b..ac593e259 100644 --- a/src/info.h +++ b/src/info.h @@ -1189,7 +1189,7 @@ typedef enum sprite SPR_POKE, // Pokey SPR_AUDI, // Audience members SPR_DECO, // Old 1.0 Kart Decoratives + New misc ones - SPR_DOOD, // All the old D00Dkart objects + SPR_SPCN, // Spray Can replaces all the old D00Dkart objects SPR_SNES, // Sprites for SNES remake maps SPR_GBAS, // Sprites for GBA remake maps SPR_SPRS, // Sapphire Coast Spring Shell @@ -2344,6 +2344,9 @@ typedef enum state S_EMBLEM25, S_EMBLEM26, + // Spray Can + S_SPRAYCAN, + // Chaos Emeralds S_CHAOSEMERALD1, S_CHAOSEMERALD2, @@ -5074,24 +5077,6 @@ typedef enum state S_APPLE7, S_APPLE8, - // D00Dkart - Fall Flowers - S_DOOD_FLOWER1, - S_DOOD_FLOWER2, - S_DOOD_FLOWER3, - S_DOOD_FLOWER4, - S_DOOD_FLOWER5, - S_DOOD_FLOWER6, - - // D00Dkart - Super Circuit Box - S_DOOD_BOX1, - S_DOOD_BOX2, - S_DOOD_BOX3, - S_DOOD_BOX4, - S_DOOD_BOX5, - - // D00Dkart - Diddy Kong Racing Bumper - S_DOOD_BALLOON, - // Chaotix Big Ring S_BIGRING01, S_BIGRING02, @@ -5994,6 +5979,7 @@ typedef enum mobj_type MT_REDFLAG, // Red CTF Flag MT_BLUEFLAG, // Blue CTF Flag MT_EMBLEM, + MT_SPRAYCAN, MT_EMERALD, MT_EMERALDSPARK, MT_EMERHUNT, // Emerald Hunt @@ -6768,12 +6754,6 @@ typedef enum mobj_type MT_BIGPUMA, MT_APPLE, - MT_DOOD_FLOWER1, - MT_DOOD_FLOWER2, - MT_DOOD_FLOWER3, - MT_DOOD_FLOWER4, - MT_DOOD_BOX, - MT_DOOD_BALLOON, MT_BIGRING, MT_SNES_DONUTBUSH1, diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 6b7b6fa7f..4899b4c06 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -6050,27 +6050,13 @@ static void M_DrawMapMedals(INT32 mapnum, INT32 x, INT32 y) { UINT8 lasttype = UINT8_MAX, curtype; - boolean start = false; - - if (mapheaderinfo[mapnum]->cachedcan != 0 && mapheaderinfo[mapnum]->cachedcan < MAXCANCOLORS) - { - V_DrawSmallMappedPatch(x, y, 0, W_CachePatchName("GOTITA", PU_CACHE), - R_GetTranslationColormap(TC_RAINBOW, mapheaderinfo[mapnum]->cachedcan, GTC_MENUCACHE)); - //V_DrawRightAlignedThinString(x - 2, y, 0, skincolors[mapheaderinfo[mapnum]->cachedcan].name); - x -= 8; - - start = true; - } - - // Shift over if emblem is of a different discipline - if (start) - x -= 4; - // M_GetLevelEmblems is ONE-indexed, urgh mapnum++; emblem_t *emblem = M_GetLevelEmblems(mapnum); + boolean hasmedals = (emblem != NULL); + while (emblem) { switch (emblem->type) @@ -6118,6 +6104,20 @@ static void M_DrawMapMedals(INT32 mapnum, INT32 x, INT32 y) emblem = M_GetLevelEmblems(-1); x -= 8; } + + // Undo offset + mapnum--; + + if (hasmedals) + x -= 4; + + if (mapheaderinfo[mapnum]->cachedcan != 0 && mapheaderinfo[mapnum]->cachedcan < MAXCANCOLORS && gamedata->spraycans[mapheaderinfo[mapnum]->cachedcan].got == true) + { + V_DrawSmallMappedPatch(x, y, 0, W_CachePatchName("GOTCAN", PU_CACHE), + R_GetTranslationColormap(TC_RAINBOW, mapheaderinfo[mapnum]->cachedcan, GTC_MENUCACHE)); + //V_DrawRightAlignedThinString(x - 2, y, 0, skincolors[mapheaderinfo[mapnum]->cachedcan].name); + x -= 8; + } } static void M_DrawStatsMaps(void) diff --git a/src/p_inter.c b/src/p_inter.c index 9d3751395..a171df1e1 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -614,6 +614,43 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) return; } + case MT_SPRAYCAN: + { + UINT16 col = mapheaderinfo[gamemap-1]->cachedcan; + + if (col == 0 || col > MAXCANCOLORS) + { + return; + } + + if (demo.playback) + { + // Never collect emblems in replays. + return; + } + + if (player->bot) + { + // Your nefarious opponent puppy can't grab these for you. + return; + } + + if (P_IsLocalPlayer(player)) + { + if (!gamedata->spraycans[col].got) + { + gamedata->spraycans[col].got = true; + if (!M_UpdateUnlockablesAndExtraEmblems(true, true)) + S_StartSound(NULL, sfx_ncitem); + gamedata->deferredsave = true; + } + } + + // Don't delete the object, just fade it. + P_SprayCanInit(special); + return; + } + // CTF Flags case MT_REDFLAG: case MT_BLUEFLAG: diff --git a/src/p_local.h b/src/p_local.h index 20ad1d5d2..fe75081d5 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -199,6 +199,8 @@ boolean P_AutoPause(void); void P_ElementalFire(player_t *player, boolean cropcircle); void P_SpawnSkidDust(player_t *player, fixed_t radius, boolean sound); +void P_SprayCanInit(mobj_t* mobj); + void P_HaltPlayerOrbit(player_t *player); void P_ExitPlayerOrbit(player_t *player); boolean P_PlayerOrbit(player_t *player); diff --git a/src/p_mobj.c b/src/p_mobj.c index 47d20059b..5f265b508 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7170,7 +7170,6 @@ static boolean P_MobjRegularThink(mobj_t *mobj) if (P_EmblemWasCollected(mobj->health - 1) || !P_CanPickupEmblem(&players[consoleplayer], mobj->health - 1)) { trans = tr_trans50; - mobj->renderflags |= (tr_trans50 << RF_TRANSSHIFT); } if (mobj->reactiontime > 0 @@ -12197,6 +12196,7 @@ fixed_t P_GetMapThingSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* mt // Ring-like items, float additional units unless args[0] is set. case MT_SPIKEBALL: case MT_EMBLEM: + case MT_SPRAYCAN: case MT_RING: case MT_BLUESPHERE: offset += mthing->args[0] ? 0 : 24*FRACUNIT; @@ -12406,6 +12406,23 @@ static boolean P_SetupEmblem(mapthing_t *mthing, mobj_t *mobj) return true; } +void P_SprayCanInit(mobj_t* mobj) +{ + UINT16 col = mapheaderinfo[gamemap-1]->cachedcan; + + if (col == 0 || col > MAXCANCOLORS) + { + mobj->renderflags = RF_DONTDRAW; + return; + } + + mobj->color = col; + + mobj->renderflags = (gamedata->spraycans[col].got) + ? (tr_trans50 << RF_TRANSSHIFT) + : 0; +} + static boolean P_SetupMace(mapthing_t *mthing, mobj_t *mobj) { fixed_t mlength, mmaxlength, mlengthset, mspeed, mphase, myaw, mpitch, mminlength, mnumspokes, mpinch, mroll, mnumnospokes, mwidth, mwidthset, mmin, msound, radiusfactor, widthfactor; @@ -12866,6 +12883,23 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj) } break; } + case MT_SPRAYCAN: + { + if (numspraycans) + { + if (numspraycans != UINT8_MAX) + numspraycans++; + + P_RemoveMobj(mobj); + return false; + } + + P_SetScale(mobj, mobj->destscale = 2*mobj->scale); + + P_SprayCanInit(mobj); + numspraycans++; + break; + } case MT_SKYBOX: { P_InitSkyboxPoint(mobj, mthing); diff --git a/src/p_saveg.c b/src/p_saveg.c index f948c7fa0..c8574c911 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -4190,6 +4190,10 @@ static thinker_t* LoadMobjThinker(savebuffer_t *save, actionf_p1 thinker) { P_InitSkyboxPoint(mobj, mobj->spawnpoint); } + else if (mobj->type == MT_SPRAYCAN) + { + P_SprayCanInit(mobj); + } if (diff2 & MD2_WAYPOINTCAP) P_SetTarget(&waypointcap, mobj); diff --git a/src/p_setup.c b/src/p_setup.c index b687cd347..4b9b1d4a8 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -813,6 +813,21 @@ static void P_SpawnMapThings(boolean spawnemblems) } Z_Free(loopends); + + if (spawnemblems) + { + if (numspraycans == 0) + { + UINT16 col = mapheaderinfo[gamemap-1]->cachedcan; + + if (col > 0 && col <= MAXCANCOLORS) + { + CONS_Alert(CONS_WARNING, "SPRAY CANS: Map has assigned Spray Cans but no pickup placed!\n"); + } + } + else if (numspraycans > 1) + CONS_Alert(CONS_ERROR, "SPRAY CANS: Map has too many Spray Cans (%d)!", numspraycans); + } } // Experimental groovy write function! @@ -7472,6 +7487,8 @@ static void P_InitLevelSettings(void) maptargets = numtargets = 0; battleprisons = false; + numspraycans = 0; + // emerald hunt hunt1 = hunt2 = hunt3 = NULL; From 3ccf668fdaf1e16beacf73d734fdae62a1d4ff4d Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 22 Aug 2023 23:03:46 +0100 Subject: [PATCH 09/21] Rename numspraycans to nummapspraycans - Consistency with nummaprings - Prevents confusion with incoming gamedata struct variable --- src/doomstat.h | 2 +- src/g_game.c | 2 +- src/p_mobj.c | 8 ++++---- src/p_setup.c | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/doomstat.h b/src/doomstat.h index bd96e3a5d..c6bbbd997 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -713,7 +713,7 @@ extern INT32 luabanks[NUM_LUABANKS]; extern INT32 nummaprings; //keep track of spawned rings/coins -extern UINT8 numspraycans; +extern UINT8 nummapspraycans; extern UINT32 bluescore; ///< Blue Team Scores extern UINT32 redscore; ///< Red Team Scores diff --git a/src/g_game.c b/src/g_game.c index a692feefc..807f58814 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -219,7 +219,7 @@ UINT32 bluescore, redscore; // CTF and Team Match team scores // ring count... for PERFECT! INT32 nummaprings = 0; -UINT8 numspraycans = 0; +UINT8 nummapspraycans = 0; // Elminates unnecessary searching. boolean CheckForBustableBlocks; diff --git a/src/p_mobj.c b/src/p_mobj.c index 5d0ec3224..a5ae4b881 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -12914,10 +12914,10 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj) } case MT_SPRAYCAN: { - if (numspraycans) + if (nummapspraycans) { - if (numspraycans != UINT8_MAX) - numspraycans++; + if (nummapspraycans != UINT8_MAX) + nummapspraycans++; P_RemoveMobj(mobj); return false; @@ -12926,7 +12926,7 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj) P_SetScale(mobj, mobj->destscale = 2*mobj->scale); P_SprayCanInit(mobj); - numspraycans++; + nummapspraycans++; break; } case MT_SKYBOX: diff --git a/src/p_setup.c b/src/p_setup.c index 23337787b..3cd7c5ef4 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -816,7 +816,7 @@ static void P_SpawnMapThings(boolean spawnemblems) if (spawnemblems) { - if (numspraycans == 0) + if (nummapspraycans == 0) { UINT16 col = mapheaderinfo[gamemap-1]->cachedcan; @@ -825,7 +825,7 @@ static void P_SpawnMapThings(boolean spawnemblems) CONS_Alert(CONS_WARNING, "SPRAY CANS: Map has assigned Spray Cans but no pickup placed!\n"); } } - else if (numspraycans > 1) + else if (nummapspraycans > 1) CONS_Alert(CONS_ERROR, "SPRAY CANS: Map has too many Spray Cans (%d)!", numspraycans); } } @@ -7425,7 +7425,7 @@ static void P_InitLevelSettings(void) maptargets = numtargets = 0; battleprisons = false; - numspraycans = 0; + nummapspraycans = 0; // emerald hunt hunt1 = hunt2 = hunt3 = NULL; From 6735868e267f5a057ddeeb5ab2251951c1d8f5b3 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 23 Aug 2023 00:31:10 +0100 Subject: [PATCH 10/21] MT_EMBLEM: Adjut to not run anything if not local --- src/p_inter.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/p_inter.c b/src/p_inter.c index 3358af6fd..a3ef26de0 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -604,15 +604,18 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (!P_CanPickupEmblem(player, special->health - 1)) return; - if (P_IsLocalPlayer(player)) + if (!P_IsLocalPlayer(player)) { - if (!gamedata->collected[special->health-1]) - { - gamedata->collected[special->health-1] = true; - if (!M_UpdateUnlockablesAndExtraEmblems(true, true)) - S_StartSound(NULL, sfx_ncitem); - gamedata->deferredsave = true; - } + // Must be party. + return; + } + + if (!gamedata->collected[special->health-1]) + { + gamedata->collected[special->health-1] = true; + if (!M_UpdateUnlockablesAndExtraEmblems(true, true)) + S_StartSound(NULL, sfx_ncitem); + gamedata->deferredsave = true; } // Don't delete the object, just fade it. From e1b7cb66cb5f88c35f1c71414238bc8a2b7593c1 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 23 Aug 2023 00:46:46 +0100 Subject: [PATCH 11/21] Rework the Spray Can system to ACTUALLY be what we want Instead of being specific to each level, Spray Cans are stored in a list on gamedata that will be stepped along each Spray Can you collect. They are only assigned to a level on collection - which prevents you from farming the same easy location for every colour in the game. In addition, this new system is one step short of dehardcoding them entirely. Now only Spray Cans specifically asked for by the existence of UC_SPRAYCAN will be put in the list, and if a secondary parameter is either "Yes" or "True", it will be put at the head of the list. This could technically support custom skincolours one day, but the author of this commit doesn't care to do the last bit of work necessary to make it happen. There's a slight extra overhead in that skincolor_t now also holds a `cache_spraycan` (renamed from `cachedcan`, which maps had previously) Currently, there's no safeguard against grabbing it on a custom course - you'll lose the Spray Can as soon as you load a fresh game again - but I consider that easy to fix (tomorrow) and necessary before merger, because the author of this commit does NOT want complaints on release because we forgot to protect users who keep on losing their skincolors. --- src/deh_lua.c | 1 + src/deh_soc.c | 8 +- src/deh_tables.c | 1 - src/doomdef.h | 5 +- src/doomstat.h | 2 +- src/g_game.c | 87 ++++++++---- src/info.c | 336 +++++++++++++++++++++++------------------------ src/k_menudraw.c | 13 +- src/m_cond.c | 230 ++++++++++++++------------------ src/m_cond.h | 7 +- src/p_inter.c | 49 ++++--- src/p_mobj.c | 27 ++-- src/p_setup.c | 23 ++-- 13 files changed, 413 insertions(+), 376 deletions(-) diff --git a/src/deh_lua.c b/src/deh_lua.c index 7b9555104..db3d4cbc5 100644 --- a/src/deh_lua.c +++ b/src/deh_lua.c @@ -142,6 +142,7 @@ static inline int lib_freeslot(lua_State *L) CONS_Printf("Skincolor SKINCOLOR_%s allocated.\n",word); FREE_SKINCOLORS[i] = Z_Malloc(strlen(word)+1, PU_STATIC, NULL); strcpy(FREE_SKINCOLORS[i],word); + skincolors[i].cache_spraycan = UINT16_MAX; numskincolors++; lua_pushinteger(L, SKINCOLOR_FIRSTFREESLOT + i); r++; diff --git a/src/deh_soc.c b/src/deh_soc.c index a092384f6..027ff2d7a 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -216,10 +216,10 @@ void clear_levels(void) } } - if (gamedata) + if (gamedata && gamedata->spraycans) { UINT16 i; - for (i = 1; i < MAXCANCOLORS; i++) + for (i = 0; i < gamedata->numspraycans; i++) gamedata->spraycans[i].map = 0; } @@ -326,6 +326,7 @@ void readfreeslots(MYFILE *f) CONS_Printf("Skincolor SKINCOLOR_%s allocated.\n",word); FREE_SKINCOLORS[i] = Z_Malloc(strlen(word)+1, PU_STATIC, NULL); strcpy(FREE_SKINCOLORS[i],word); + skincolors[i].cache_spraycan = UINT16_MAX; numskincolors++; break; } @@ -2625,6 +2626,9 @@ static void readcondition(UINT16 set, UINT32 id, char *word2) PARAMCHECK(1); ty = UC_SPRAYCAN; re = get_skincolor(params[1]); + + // Force at head of the list? + x1 = (params[2] && (params[2][0] == 'Y' || params[2][0] == 'T')) ? 1 : 0; } else if ((offset=0) || fastcmp(params[0], "AND") || (++offset && fastcmp(params[0], "COMMA"))) diff --git a/src/deh_tables.c b/src/deh_tables.c index 0149e1ea3..f20d45ee7 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -6521,7 +6521,6 @@ struct int_const_s const INT_CONST[] = { // SKINCOLOR_ doesn't include these..! {"MAXSKINCOLORS",MAXSKINCOLORS}, - {"MAXCANCOLORS",MAXCANCOLORS}, {"FIRSTSUPERCOLOR",FIRSTSUPERCOLOR}, {"NUMSUPERCOLORS",NUMSUPERCOLORS}, diff --git a/src/doomdef.h b/src/doomdef.h index c9f8b1702..9fffb78b4 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -232,6 +232,7 @@ struct skincolor_t UINT8 invshade; // Signpost color shade UINT16 chatcolor; // Chat color boolean accessible; // Accessible by the color command + setup menu + UINT16 cache_spraycan; // Cache for associated spraycan id }; #define FOLLOWERCOLOR_MATCH UINT16_MAX @@ -346,9 +347,7 @@ typedef enum SKINCOLOR_BLOSSOM, SKINCOLOR_TAFFY, - MAXCANCOLORS, - - FIRSTSUPERCOLOR = MAXCANCOLORS, + FIRSTSUPERCOLOR, // Super special awesome Super flashing colors! SKINCOLOR_SUPERSILVER1 = FIRSTSUPERCOLOR, diff --git a/src/doomstat.h b/src/doomstat.h index c6bbbd997..7d14f1d5a 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -532,7 +532,7 @@ struct mapheader_t UINT8 cutscenenum; ///< Cutscene number to use, 0 for none. UINT32 _saveid; ///< Purely assistive in gamedata save processes - UINT16 cachedcan; ///< Cached Spraycan ID + UINT16 cache_spraycan; ///< Cached Spraycan ID // Lua information UINT8 numCustomOptions; ///< Internal. For Lua custom value support. diff --git a/src/g_game.c b/src/g_game.c index 807f58814..17d16b47a 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4801,44 +4801,69 @@ void G_LoadGameData(void) if (versionMinor > 5) { - UINT16 numgamedatacans = READUINT32(save.p); + gamedata->gotspraycans = 0; + gamedata->numspraycans = READUINT16(save.p); + Z_Free(gamedata->spraycans); - if (numgamedatacans != MAXCANCOLORS - 1) + if (gamedata->numspraycans) { - save.p += (1 + 4) * numgamedatacans; - } - else - { - for (i = 1; i < MAXCANCOLORS; i++) + gamedata->spraycans = Z_Malloc( + (gamedata->numspraycans * sizeof(candata_t)), + PU_STATIC, NULL); + + for (i = 0; i < gamedata->numspraycans; i++) { - gamedata->spraycans[i].got = (boolean)READUINT8(save.p); - gamedata->spraycans[i].map = 0; + gamedata->spraycans[i].col = SKINCOLOR_NONE; + gamedata->spraycans[i].map = NEXTMAP_INVALID; + UINT16 col = READUINT16(save.p); UINT32 _saveid = READUINT32(save.p); + if (col < SKINCOLOR_FIRSTFREESLOT) + { + gamedata->spraycans[i].col = col; + skincolors[col].cache_spraycan = i; + } + if (_saveid >= numgamedatamapheaders) { - //CONS_Printf("LOAD - Color %s - id %u, map 0 (invalid id)\n", skincolors[i].name, _saveid); + // Can has not been grabbed on any map, this is intentional. continue; } UINT16 map = tempmapidreferences[_saveid]; if (map >= nummapheaders || !mapheaderinfo[map]) { - //CONS_Printf("LOAD - Color %s - id %u, map 0 (unloaded header)\n", skincolors[i].name, _saveid); + //CONS_Printf("LOAD - Can %u, color %s - id %u (unloaded header)\n", i, skincolors[col].name, _saveid); continue; } - //CONS_Printf("LOAD - Color %s - id %u, map %d\n", skincolors[i].name, _saveid, map+1); + //CONS_Printf("LOAD - Can %u, color %s - id %u, map %d\n", i, skincolors[col].name, _saveid, map); - gamedata->spraycans[i].map = map+1; - mapheaderinfo[map]->cachedcan = i; + gamedata->spraycans[i].map = map; - numgamedatacans--; // this one was successfully placed + if (gamedata->gotspraycans != i) + { + //CONS_Printf("LOAD - Swapping gotten can %u, color %s with prior ungotten can %u\n", i, skincolors[col].name, gamedata->gotspraycans); + + // All grabbed cans should be at the head of the list. + // Let's swap with the can the disjoint occoured at. + // This will prevent a gap from occouring on reload. + candata_t copycan = gamedata->spraycans[gamedata->gotspraycans]; + gamedata->spraycans[gamedata->gotspraycans] = gamedata->spraycans[i]; + gamedata->spraycans[i] = copycan; + + mapheaderinfo[copycan.map]->cache_spraycan = i; + } + + mapheaderinfo[map]->cache_spraycan = gamedata->gotspraycans; + + gamedata->gotspraycans++; } - - gamedata->allspraycansplaced = (numgamedatacans == 0); - //CONS_Printf("CCC - all spray cans placed? %c\n", gamedata->allspraycansplaced ? 'Y' : 'N'); + } + else + { + gamedata->spraycans = NULL; } } @@ -5093,7 +5118,7 @@ void G_SaveGameData(void) for (i = 0; i < nummapheaders; i++) { // No spraycan attached. - if (mapheaderinfo[i]->cachedcan == 0 + if (mapheaderinfo[i]->cache_spraycan >= gamedata->numspraycans // 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. && !(mapheaderinfo[i]->records.mapvisited & MV_MAX)) { @@ -5124,8 +5149,12 @@ void G_SaveGameData(void) length += 4 + (numgamedatamapheaders * (MAXMAPLUMPNAME+1+4+4)); + length += 2; - length += 4 + ((MAXCANCOLORS - 1) * (1 + 4)); + if (gamedata->numspraycans) + { + length += (gamedata->numspraycans * (2 + 4)); + } UINT32 numgamedatacups = 0; @@ -5322,7 +5351,7 @@ void G_SaveGameData(void) for (i = 0; i < nummapheaders; i++) { - if (mapheaderinfo[i]->cachedcan == 0 + if (mapheaderinfo[i]->cache_spraycan >= gamedata->numspraycans && !(mapheaderinfo[i]->records.mapvisited & MV_MAX)) continue; @@ -5363,25 +5392,25 @@ void G_SaveGameData(void) } } } + + WRITEUINT16(save.p, gamedata->numspraycans); // 2 - WRITEUINT32(save.p, MAXCANCOLORS - 1); // 4 + // gamedata->numspraycans * (2 + 4) - // (MAXCANCOLORS - 1) * (1 + 4) - - for (i = 1; i < MAXCANCOLORS; i++) + for (i = 0; i < gamedata->numspraycans; i++) { - WRITEUINT8(save.p, gamedata->spraycans[i].got); + WRITEUINT16(save.p, gamedata->spraycans[i].col); UINT32 _saveid = UINT32_MAX; UINT16 map = gamedata->spraycans[i].map; - if (map > 0 && map <= nummapheaders && mapheaderinfo[map - 1]) + if (map < nummapheaders && mapheaderinfo[map]) { - _saveid = mapheaderinfo[map - 1]->_saveid; + _saveid = mapheaderinfo[map]->_saveid; } - //CONS_Printf("SAVE - Color %s - id %u, map %d\n", skincolors[i].name, _saveid, map); + //CONS_Printf("SAVE - Can %u, color %s - id %u, map %d\n", i, skincolors[gamedata->spraycans[i].col].name, _saveid, map); WRITEUINT32(save.p, _saveid); } diff --git a/src/info.c b/src/info.c index b64175e49..509a84571 100644 --- a/src/info.c +++ b/src/info.c @@ -30314,189 +30314,189 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }; skincolor_t skincolors[MAXSKINCOLORS] = { - {"Default", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_NONE + {"Default", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, SKINCOLOR_NONE, 0, 0, false, UINT16_MAX}, // SKINCOLOR_NONE - {"White", { 0, 0, 0, 0, 1, 2, 5, 8, 9, 11, 14, 17, 20, 22, 25, 28}, SKINCOLOR_BLACK, 8, 0, true}, // SKINCOLOR_WHITE - {"Silver", { 0, 1, 2, 3, 5, 7, 9, 12, 13, 15, 18, 20, 23, 25, 27, 30}, SKINCOLOR_NICKEL, 8, 0, true}, // SKINCOLOR_SILVER - {"Grey", { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31}, SKINCOLOR_GREY, 8, V_LAVENDERMAP, true}, // SKINCOLOR_GREY - {"Nickel", { 3, 5, 8, 11, 15, 17, 19, 21, 23, 24, 25, 26, 27, 29, 30, 31}, SKINCOLOR_SILVER, 8, V_GRAYMAP, true}, // SKINCOLOR_NICKEL - {"Black", { 4, 7, 11, 15, 20, 22, 24, 27, 28, 28, 28, 29, 29, 30, 30, 31}, SKINCOLOR_WHITE, 8, V_GRAYMAP, true}, // SKINCOLOR_BLACK - {"Skunk", { 0, 1, 2, 3, 4, 10, 16, 21, 23, 24, 25, 26, 27, 28, 29, 31}, SKINCOLOR_VOMIT, 8, V_GRAYMAP, true}, // SKINCOLOR_SKUNK - {"Fairy", { 0, 0, 252, 252, 200, 201, 211, 14, 16, 18, 20, 22, 24, 26, 28, 31}, SKINCOLOR_ARTICHOKE, 12, V_PINKMAP, true}, // SKINCOLOR_FAIRY - {"Popcorn", { 0, 80, 80, 81, 82, 218, 240, 11, 13, 16, 18, 21, 23, 26, 28, 31}, SKINCOLOR_PIGEON, 12, V_TANMAP, true}, // SKINCOLOR_POPCORN - {"Artichoke", { 80, 88, 89, 98, 99, 91, 12, 14, 16, 18, 20, 22, 24, 26, 28, 31}, SKINCOLOR_FAIRY, 12, V_GREENMAP, true}, // SKINCOLOR_ARTICHOKE - {"Pigeon", { 0, 128, 129, 130, 146, 170, 14, 15, 17, 19, 21, 23, 25, 27, 29, 31}, SKINCOLOR_POPCORN, 12, V_SKYMAP, true}, // SKINCOLOR_PIGEON - {"Sepia", { 0, 1, 3, 5, 7, 9, 241, 242, 243, 245, 247, 249, 236, 237, 238, 239}, SKINCOLOR_LEATHER, 6, V_TANMAP, true}, // SKINCOLOR_SEPIA - {"Beige", { 0, 208, 216, 217, 240, 241, 242, 243, 245, 247, 249, 250, 251, 237, 238, 239}, SKINCOLOR_BROWN, 2, V_BROWNMAP, true}, // SKINCOLOR_BEIGE - {"Caramel", {208, 48, 216, 217, 218, 220, 221, 223, 224, 226, 228, 230, 232, 234, 236, 239}, SKINCOLOR_CERULEAN, 8, V_TANMAP, true}, // SKINCOLOR_CARAMEL - {"Peach", { 0, 208, 48, 216, 218, 221, 212, 213, 214, 215, 206, 207, 197, 198, 199, 254}, SKINCOLOR_CYAN, 8, V_TANMAP, true}, // SKINCOLOR_PEACH - {"Brown", {216, 217, 219, 221, 224, 225, 227, 229, 230, 232, 234, 235, 237, 239, 29, 30}, SKINCOLOR_BEIGE, 8, V_BROWNMAP, true}, // SKINCOLOR_BROWN - {"Leather", {218, 221, 224, 227, 229, 231, 233, 235, 237, 239, 28, 28, 29, 29, 30, 31}, SKINCOLOR_SEPIA, 8, V_BROWNMAP, true}, // SKINCOLOR_LEATHER - {"Pink", { 0, 208, 208, 209, 209, 210, 211, 211, 212, 213, 214, 215, 41, 43, 45, 46}, SKINCOLOR_PISTACHIO, 8, V_PINKMAP, true}, // SKINCOLOR_PINK - {"Rose", {209, 210, 211, 211, 212, 213, 214, 215, 41, 42, 43, 44, 45, 71, 46, 47}, SKINCOLOR_MOSS, 8, V_PINKMAP, true}, // SKINCOLOR_ROSE - {"Cinnamon", {216, 221, 224, 226, 228, 60, 61, 43, 44, 45, 71, 46, 47, 29, 30, 31}, SKINCOLOR_WRISTWATCH, 6, V_REDMAP, true}, // SKINCOLOR_CINNAMON - {"Ruby", { 0, 208, 209, 210, 211, 213, 39, 40, 41, 43, 186, 186, 169, 169, 253, 254}, SKINCOLOR_SAPPHIRE, 8, V_REDMAP, true}, // SKINCOLOR_RUBY - {"Raspberry", { 0, 208, 209, 210, 32, 33, 34, 35, 37, 39, 41, 43, 44, 45, 46, 47}, SKINCOLOR_MINT, 8, V_REDMAP, true}, // SKINCOLOR_RASPBERRY - {"Red", {209, 210, 32, 34, 36, 38, 39, 40, 41, 42, 43, 44 , 45, 71, 46, 47}, SKINCOLOR_GREEN, 6, V_REDMAP, true}, // SKINCOLOR_RED - {"Crimson", {210, 33, 35, 38, 40, 42, 43, 45, 71, 71, 46, 46, 47, 47, 30, 31}, SKINCOLOR_PINETREE, 6, V_REDMAP, true}, // SKINCOLOR_CRIMSON - {"Maroon", { 32, 33, 35, 37, 39, 41, 43, 237, 26, 26, 27, 27, 28, 29, 30, 31}, SKINCOLOR_TOXIC, 8, V_REDMAP, true}, // SKINCOLOR_MAROON - {"Lemonade", { 0, 80, 81, 82, 83, 216, 210, 211, 212, 213, 214, 215, 43, 44, 71, 47}, SKINCOLOR_THUNDER, 8, V_PINKMAP, true}, // SKINCOLOR_LEMONADE - {"Scarlet", { 48, 49, 50, 51, 53, 34, 36, 38, 184, 185, 168, 168, 169, 169, 254, 31}, SKINCOLOR_ALGAE, 10, V_REDMAP, true}, // SKINCOLOR_SCARLET - {"Ketchup", { 72, 73, 64, 51, 52, 54, 34, 36, 38, 40, 42, 43, 44, 71, 46, 47}, SKINCOLOR_MUSTARD, 10, V_REDMAP, true}, // SKINCOLOR_KETCHUP - {"Dawn", { 0, 208, 216, 209, 210, 211, 212, 57, 58, 59, 60, 61, 63, 71, 47, 31}, SKINCOLOR_DUSK, 8, V_ORANGEMAP, true}, // SKINCOLOR_DAWN - {"Sunslam", { 82, 72, 73, 64, 51, 53, 55, 213, 214, 195, 195, 173, 174, 175, 253, 254}, SKINCOLOR_MOONSET, 8, V_ORANGEMAP, true}, // SKINCOLOR_SUNSLAM - {"Creamsicle", { 0, 0, 208, 208, 48, 49, 50, 52, 53, 54, 56, 57, 58, 60, 61, 63}, SKINCOLOR_PERIWINKLE, 8, V_ORANGEMAP, true}, // SKINCOLOR_CREAMSICLE - {"Orange", {208, 48, 49, 50, 51, 52, 53, 54, 55, 57, 59, 60, 62, 44, 71, 47}, SKINCOLOR_BLUE, 8, V_ORANGEMAP, true}, // SKINCOLOR_ORANGE - {"Rosewood", { 50, 52, 55, 56, 58, 59, 60, 61, 62, 63, 44, 45, 71, 46, 47, 30}, SKINCOLOR_MIDNIGHT, 6, V_ORANGEMAP, true}, // SKINCOLOR_ROSEWOOD - {"Tangerine", { 80, 81, 82, 83, 64, 51, 52, 54, 55, 57, 58, 60, 61, 63, 71, 47}, SKINCOLOR_LIME, 8, V_ORANGEMAP, true}, // SKINCOLOR_TANGERINE - {"Tan", { 0, 80, 81, 82, 83, 84, 85, 86, 87, 245, 246, 248, 249, 251, 237, 239}, SKINCOLOR_RUST, 8, V_TANMAP, true}, // SKINCOLOR_TAN - {"Cream", { 0, 80, 80, 81, 81, 49, 51, 222, 224, 227, 230, 233, 236, 239, 29, 31}, SKINCOLOR_COPPER, 10, V_TANMAP, true}, // SKINCOLOR_CREAM - {"Gold", { 0, 80, 81, 83, 64, 65, 66, 67, 68, 215, 69, 70, 44, 71, 46, 47}, SKINCOLOR_SLATE, 8, V_GOLDMAP, true}, // SKINCOLOR_GOLD - {"Royal", { 80, 81, 83, 64, 65, 223, 229, 196, 196, 197, 197, 198, 199, 29, 30, 31}, SKINCOLOR_PLATINUM, 6, V_GOLDMAP, true}, // SKINCOLOR_ROYAL - {"Bronze", { 83, 64, 65, 66, 67, 215, 69, 70, 44, 44, 45, 71, 46, 47, 29, 31}, SKINCOLOR_STEEL, 8, V_GOLDMAP, true}, // SKINCOLOR_BRONZE - {"Copper", { 0, 82, 64, 65, 67, 68, 70, 237, 239, 28, 28, 29, 29, 30, 30, 31}, SKINCOLOR_CREAM, 6, V_GOLDMAP, true}, // SKINCOLOR_COPPER - {"Yellow", { 0, 80, 81, 82, 83, 73, 84, 74, 64, 65, 66, 67, 68, 69, 70, 71}, SKINCOLOR_AQUAMARINE, 8, V_YELLOWMAP, true}, // SKINCOLOR_YELLOW - {"Mustard", { 80, 81, 82, 83, 64, 65, 65, 76, 76, 77, 77, 78, 79, 237, 239, 29}, SKINCOLOR_KETCHUP, 8, V_YELLOWMAP, true}, // SKINCOLOR_MUSTARD - {"Banana", { 80, 81, 83, 72, 73, 74, 75, 76, 77, 78, 79, 236, 237, 238, 239, 30}, SKINCOLOR_EMERALD, 8, V_YELLOWMAP, true}, // SKINCOLOR_BANANA - {"Olive", { 80, 82, 73, 74, 75, 76, 77, 78, 79, 236, 237, 238, 239, 28, 29, 31}, SKINCOLOR_TEAL, 8, V_YELLOWMAP, true}, // SKINCOLOR_OLIVE - {"Crocodile", { 0, 80, 81, 88, 88, 188, 189, 76, 76, 77, 78, 79, 236, 237, 238, 239}, SKINCOLOR_VIOLET, 8, V_YELLOWMAP, true}, // SKINCOLOR_CROCODILE - {"Peridot", { 0, 80, 81, 88, 188, 189, 190, 191, 94, 94, 95, 95, 109, 110, 111, 31}, SKINCOLOR_NAVY, 6, V_GREENMAP, true}, // SKINCOLOR_PERIDOT - {"Vomit", { 0, 208, 216, 209, 218, 51, 65, 76, 191, 191, 126, 143, 138, 175, 169, 254}, SKINCOLOR_SKUNK, 8, V_GREENMAP, true}, // SKINCOLOR_VOMIT - {"Garden", { 81, 82, 83, 73, 64, 65, 66, 92, 92, 93, 93, 94, 95, 109, 110, 111}, SKINCOLOR_LAVENDER, 6, V_GREENMAP, true}, // SKINCOLOR_GARDEN - {"Lime", { 0, 80, 81, 88, 188, 189, 114, 114, 115, 115, 116, 116, 117, 118, 119, 111}, SKINCOLOR_TANGERINE, 8, V_GREENMAP, true}, // SKINCOLOR_LIME - {"Handheld", { 83, 72, 73, 74, 75, 76, 102, 104, 105, 106, 107, 108, 109, 110, 111, 31}, SKINCOLOR_ULTRAMARINE, 8, V_GREENMAP, true}, // SKINCOLOR_HANDHELD - {"Tea", { 0, 80, 80, 81, 88, 89, 90, 91, 92, 93, 94, 95, 109, 110, 111, 31}, SKINCOLOR_BLOSSOM, 8, V_GREENMAP, true}, // SKINCOLOR_TEA - {"Pistachio", { 0, 80, 88, 88, 89, 90, 91, 102, 103, 104, 105, 106, 107, 108, 109, 110}, SKINCOLOR_PINK, 6, V_GREENMAP, true}, // SKINCOLOR_PISTACHIO - {"Moss", { 88, 89, 90, 91, 91, 92, 93, 94, 107, 107, 108, 108, 109, 109, 110, 111}, SKINCOLOR_ROSE, 8, V_GREENMAP, true}, // SKINCOLOR_MOSS - {"Camouflage", {208, 84, 85, 240, 241, 243, 245, 94, 107, 108, 108, 109, 109, 110, 110, 111}, SKINCOLOR_CAMOUFLAGE, 8, V_GREENMAP, true}, // SKINCOLOR_CAMOUFLAGE - {"Mint", { 0, 88, 88, 89, 89, 100, 101, 102, 125, 126, 143, 143, 138, 175, 169, 254}, SKINCOLOR_RASPBERRY, 8, V_GREENMAP, true}, // SKINCOLOR_MINT - {"Green", { 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111}, SKINCOLOR_RED, 8, V_GREENMAP, true}, // SKINCOLOR_GREEN - {"Pinetree", { 97, 99, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 30, 30, 31}, SKINCOLOR_CRIMSON, 8, V_GREENMAP, true}, // SKINCOLOR_PINETREE - {"Turtle", { 96, 112, 112, 113, 113, 114, 114, 115, 115, 116, 116, 117, 117, 118, 119, 111}, SKINCOLOR_MAGENTA, 8, V_GREENMAP, true}, // SKINCOLOR_TURTLE - {"Swamp", { 96, 112, 113, 114, 115, 116, 117, 118, 119, 119, 29, 29, 30, 30, 31, 31}, SKINCOLOR_BYZANTIUM, 8, V_GREENMAP, true}, // SKINCOLOR_SWAMP - {"Dream", { 0, 0, 208, 208, 48, 89, 98, 100, 148, 148, 172, 172, 173, 173, 174, 175}, SKINCOLOR_POMEGRANATE, 8, V_GREENMAP, true}, // SKINCOLOR_DREAM - {"Plague", { 80, 88, 96, 112, 113, 124, 142, 149, 149, 173, 174, 175, 169, 253, 254, 31}, SKINCOLOR_NOVA, 8, V_GREENMAP, true}, // SKINCOLOR_PLAGUE - {"Emerald", { 0, 120, 121, 112, 113, 114, 115, 125, 125, 126, 126, 127, 138, 175, 253, 254}, SKINCOLOR_BANANA, 8, V_GREENMAP, true}, // SKINCOLOR_EMERALD - {"Algae", {128, 129, 130, 131, 132, 133, 134, 115, 115, 116, 116, 117, 118, 119, 110, 111}, SKINCOLOR_SCARLET, 10, V_GREENMAP, true}, // SKINCOLOR_ALGAE - {"Aquamarine", { 0, 128, 120, 121, 122, 123, 124, 125, 126, 126, 127, 127, 118, 118, 119, 111}, SKINCOLOR_YELLOW, 8, V_AQUAMAP, true}, // SKINCOLOR_AQUAMARINE - {"Turquoise", {128, 120, 121, 122, 123, 141, 141, 142, 142, 143, 143, 138, 138, 139, 139, 31}, SKINCOLOR_MAUVE, 10, V_AQUAMAP, true}, // SKINCOLOR_TURQUOISE - {"Teal", { 0, 120, 120, 121, 140, 141, 142, 143, 143, 138, 138, 139, 139, 254, 254, 31}, SKINCOLOR_OLIVE, 8, V_AQUAMAP, true}, // SKINCOLOR_TEAL - {"Robin", { 0, 80, 81, 82, 83, 88, 121, 140, 133, 133, 134, 135, 136, 137, 138, 139}, SKINCOLOR_THISTLE, 8, V_SKYMAP, true}, // SKINCOLOR_ROBIN - {"Cyan", { 0, 0, 128, 128, 255, 131, 132, 134, 142, 142, 143, 127, 118, 119, 110, 111}, SKINCOLOR_PEACH, 8, V_SKYMAP, true}, // SKINCOLOR_CYAN - {"Jawz", { 0, 0, 128, 128, 129, 146, 133, 134, 135, 149, 149, 173, 173, 174, 175, 31}, SKINCOLOR_LILAC, 10, V_SKYMAP, true}, // SKINCOLOR_JAWZ - {"Cerulean", { 0, 128, 129, 130, 131, 132, 133, 135, 136, 136, 137, 137, 138, 138, 139, 31}, SKINCOLOR_CARAMEL, 8, V_SKYMAP, true}, // SKINCOLOR_CERULEAN - {"Navy", {128, 129, 130, 132, 134, 135, 136, 137, 137, 138, 138, 139, 139, 29, 30, 31}, SKINCOLOR_PERIDOT, 8, V_SKYMAP, true}, // SKINCOLOR_NAVY - {"Platinum", { 0, 0, 0, 144, 144, 145, 9, 11, 14, 142, 136, 137, 138, 138, 139, 31}, SKINCOLOR_ROYAL, 8, V_GRAYMAP, true}, // SKINCOLOR_PLATINUM - {"Slate", { 0, 0, 144, 144, 144, 145, 145, 145, 170, 170, 171, 171, 172, 173, 174, 175}, SKINCOLOR_GOLD, 10, 0, true}, // SKINCOLOR_SLATE - {"Steel", { 0, 144, 144, 145, 145, 170, 170, 171, 171, 172, 172, 173, 173, 174, 175, 31}, SKINCOLOR_BRONZE, 10, V_GRAYMAP, true}, // SKINCOLOR_STEEL - {"Thunder", { 80, 81, 82, 83, 64, 65, 11, 171, 172, 173, 173, 157, 158, 159, 254, 31}, SKINCOLOR_LEMONADE, 8, V_GOLDMAP, true}, // SKINCOLOR_THUNDER - {"Nova", { 0, 83, 49, 50, 51, 32, 192, 148, 148, 172, 173, 174, 175, 29, 30, 31}, SKINCOLOR_PLAGUE, 10, V_BLUEMAP, true}, // SKINCOLOR_NOVA - {"Rust", {208, 48, 216, 217, 240, 241, 242, 171, 172, 173, 24, 25, 26, 28, 29, 31}, SKINCOLOR_TAN, 8, V_BROWNMAP, true}, // SKINCOLOR_RUST - {"Wristwatch", { 48, 218, 221, 224, 227, 231, 196, 173, 173, 174, 159, 159, 253, 253, 254, 31}, SKINCOLOR_CINNAMON, 8, V_BROWNMAP, true}, // SKINCOLOR_WRISTWATCH - {"Jet", {145, 146, 147, 148, 149, 173, 173, 174, 175, 175, 28, 28, 29, 29, 30, 31}, SKINCOLOR_TAFFY, 8, V_GRAYMAP, true}, // SKINCOLOR_JET - {"Sapphire", { 0, 128, 129, 131, 133, 135, 149, 150, 152, 154, 156, 158, 159, 253, 254, 31}, SKINCOLOR_RUBY, 6, V_SKYMAP, true}, // SKINCOLOR_SAPPHIRE - {"Ultramarine", { 0, 0, 120, 120, 121, 133, 135, 149, 149, 166, 166, 167, 168, 169, 254, 31}, SKINCOLOR_HANDHELD, 10, V_SKYMAP, true}, // SKINCOLOR_ULTRAMARINE - {"Periwinkle", { 0, 0, 144, 144, 145, 146, 147, 149, 150, 152, 154, 155, 157, 159, 253, 254}, SKINCOLOR_CREAMSICLE, 8, V_BLUEMAP, true}, // SKINCOLOR_PERIWINKLE - {"Blue", {144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 155, 156, 158, 253, 254, 31}, SKINCOLOR_ORANGE, 8, V_BLUEMAP, true}, // SKINCOLOR_BLUE - {"Midnight", {146, 148, 149, 150, 152, 153, 155, 157, 159, 253, 253, 254, 254, 31, 31, 31}, SKINCOLOR_ROSEWOOD, 8, V_BLUEMAP, true}, // SKINCOLOR_MIDNIGHT - {"Blueberry", { 0, 144, 145, 146, 147, 171, 172, 166, 166, 167, 167, 168, 168, 175, 169, 253}, SKINCOLOR_PURPLE, 8, V_BLUEMAP, true}, // SKINCOLOR_BLUEBERRY - {"Thistle", { 0, 0, 0, 252, 252, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 254}, SKINCOLOR_ROBIN, 8, V_PURPLEMAP, true}, // SKINCOLOR_THISTLE - {"Purple", { 0, 252, 160, 161, 162, 163, 164, 165, 166, 167, 168, 168, 169, 169, 253, 254}, SKINCOLOR_BLUEBERRY, 10, V_PURPLEMAP, true}, // SKINCOLOR_PURPLE - {"Pastel", { 0, 128, 128, 129, 129, 146, 170, 162, 163, 164, 165, 166, 167, 168, 169, 254}, SKINCOLOR_FUCHSIA, 11, V_PURPLEMAP, true}, // SKINCOLOR_PASTEL - {"Moonset", { 0, 144, 145, 146, 170, 162, 163, 184, 184, 207, 207, 44, 45, 46, 47, 31}, SKINCOLOR_SUNSLAM, 10, V_MAGENTAMAP, true}, // SKINCOLOR_MOONSET - {"Dusk", {252, 200, 201, 192, 193, 194, 172, 172, 173, 173, 174, 174, 175, 169, 253, 254}, SKINCOLOR_DAWN, 6, V_MAGENTAMAP, true}, // SKINCOLOR_DUSK - {"Violet", {176, 177, 178, 179, 180, 181, 182, 183, 184, 165, 165, 166, 167, 168, 169, 254}, SKINCOLOR_CROCODILE, 8, V_MAGENTAMAP, true}, // SKINCOLOR_VIOLET - {"Magenta", {252, 200, 177, 177, 178, 179, 180, 181, 182, 183, 183, 184, 185, 186, 187, 31}, SKINCOLOR_TURTLE, 8, V_MAGENTAMAP, true}, // SKINCOLOR_MAGENTA - {"Fuchsia", {208, 209, 209, 32, 33, 182, 183, 184, 185, 185, 186, 186, 187, 253, 254, 31}, SKINCOLOR_PASTEL, 11, V_MAGENTAMAP, true}, // SKINCOLOR_FUCHSIA - {"Toxic", { 0, 0, 88, 88, 89, 6, 8, 10, 193, 194, 195, 184, 185, 186, 187, 31}, SKINCOLOR_MAROON, 8, V_LAVENDERMAP, true}, // SKINCOLOR_TOXIC - {"Mauve", { 80, 81, 82, 83, 64, 50, 201, 192, 193, 194, 195, 173, 174, 175, 253, 254}, SKINCOLOR_TURQUOISE, 8, V_LAVENDERMAP, true}, // SKINCOLOR_MAUVE - {"Lavender", {252, 177, 179, 192, 193, 194, 195, 196, 196, 197, 197, 198, 198, 199, 30, 31}, SKINCOLOR_GARDEN, 6, V_LAVENDERMAP, true}, // SKINCOLOR_LAVENDER - {"Byzantium", {145, 192, 193, 194, 195, 196, 197, 198, 199, 199, 29, 29, 30, 30, 31, 31}, SKINCOLOR_SWAMP, 8, V_LAVENDERMAP, true}, // SKINCOLOR_BYZANTIUM - {"Pomegranate", {208, 209, 210, 211, 212, 213, 214, 195, 195, 196, 196, 197, 198, 199, 29, 30}, SKINCOLOR_DREAM, 8, V_LAVENDERMAP, true}, // SKINCOLOR_POMEGRANATE - {"Lilac", { 0, 0, 0, 252, 252, 176, 200, 201, 179, 192, 193, 194, 195, 196, 197, 198}, SKINCOLOR_JAWZ, 6, V_PINKMAP, true}, // SKINCOLOR_LILAC - {"Blossom", { 0, 252, 252, 176, 200, 177, 201, 202, 202, 34, 36, 38, 40, 42, 45, 46}, SKINCOLOR_TEA, 8, V_PINKMAP, true}, // SKINCOLOR_BLOSSOM - {"Taffy", { 0, 252, 252, 200, 200, 201, 202, 203, 204, 204, 205, 206, 207, 43, 45, 47}, SKINCOLOR_JET, 8, V_PINKMAP, true}, // SKINCOLOR_TAFFY + {"White", { 0, 0, 0, 0, 1, 2, 5, 8, 9, 11, 14, 17, 20, 22, 25, 28}, SKINCOLOR_BLACK, 8, 0, true, UINT16_MAX}, // SKINCOLOR_WHITE + {"Silver", { 0, 1, 2, 3, 5, 7, 9, 12, 13, 15, 18, 20, 23, 25, 27, 30}, SKINCOLOR_NICKEL, 8, 0, true, UINT16_MAX}, // SKINCOLOR_SILVER + {"Grey", { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31}, SKINCOLOR_GREY, 8, V_LAVENDERMAP, true, UINT16_MAX}, // SKINCOLOR_GREY + {"Nickel", { 3, 5, 8, 11, 15, 17, 19, 21, 23, 24, 25, 26, 27, 29, 30, 31}, SKINCOLOR_SILVER, 8, V_GRAYMAP, true, UINT16_MAX}, // SKINCOLOR_NICKEL + {"Black", { 4, 7, 11, 15, 20, 22, 24, 27, 28, 28, 28, 29, 29, 30, 30, 31}, SKINCOLOR_WHITE, 8, V_GRAYMAP, true, UINT16_MAX}, // SKINCOLOR_BLACK + {"Skunk", { 0, 1, 2, 3, 4, 10, 16, 21, 23, 24, 25, 26, 27, 28, 29, 31}, SKINCOLOR_VOMIT, 8, V_GRAYMAP, true, UINT16_MAX}, // SKINCOLOR_SKUNK + {"Fairy", { 0, 0, 252, 252, 200, 201, 211, 14, 16, 18, 20, 22, 24, 26, 28, 31}, SKINCOLOR_ARTICHOKE, 12, V_PINKMAP, true, UINT16_MAX}, // SKINCOLOR_FAIRY + {"Popcorn", { 0, 80, 80, 81, 82, 218, 240, 11, 13, 16, 18, 21, 23, 26, 28, 31}, SKINCOLOR_PIGEON, 12, V_TANMAP, true, UINT16_MAX}, // SKINCOLOR_POPCORN + {"Artichoke", { 80, 88, 89, 98, 99, 91, 12, 14, 16, 18, 20, 22, 24, 26, 28, 31}, SKINCOLOR_FAIRY, 12, V_GREENMAP, true, UINT16_MAX}, // SKINCOLOR_ARTICHOKE + {"Pigeon", { 0, 128, 129, 130, 146, 170, 14, 15, 17, 19, 21, 23, 25, 27, 29, 31}, SKINCOLOR_POPCORN, 12, V_SKYMAP, true, UINT16_MAX}, // SKINCOLOR_PIGEON + {"Sepia", { 0, 1, 3, 5, 7, 9, 241, 242, 243, 245, 247, 249, 236, 237, 238, 239}, SKINCOLOR_LEATHER, 6, V_TANMAP, true, UINT16_MAX}, // SKINCOLOR_SEPIA + {"Beige", { 0, 208, 216, 217, 240, 241, 242, 243, 245, 247, 249, 250, 251, 237, 238, 239}, SKINCOLOR_BROWN, 2, V_BROWNMAP, true, UINT16_MAX}, // SKINCOLOR_BEIGE + {"Caramel", {208, 48, 216, 217, 218, 220, 221, 223, 224, 226, 228, 230, 232, 234, 236, 239}, SKINCOLOR_CERULEAN, 8, V_TANMAP, true, UINT16_MAX}, // SKINCOLOR_CARAMEL + {"Peach", { 0, 208, 48, 216, 218, 221, 212, 213, 214, 215, 206, 207, 197, 198, 199, 254}, SKINCOLOR_CYAN, 8, V_TANMAP, true, UINT16_MAX}, // SKINCOLOR_PEACH + {"Brown", {216, 217, 219, 221, 224, 225, 227, 229, 230, 232, 234, 235, 237, 239, 29, 30}, SKINCOLOR_BEIGE, 8, V_BROWNMAP, true, UINT16_MAX}, // SKINCOLOR_BROWN + {"Leather", {218, 221, 224, 227, 229, 231, 233, 235, 237, 239, 28, 28, 29, 29, 30, 31}, SKINCOLOR_SEPIA, 8, V_BROWNMAP, true, UINT16_MAX}, // SKINCOLOR_LEATHER + {"Pink", { 0, 208, 208, 209, 209, 210, 211, 211, 212, 213, 214, 215, 41, 43, 45, 46}, SKINCOLOR_PISTACHIO, 8, V_PINKMAP, true, UINT16_MAX}, // SKINCOLOR_PINK + {"Rose", {209, 210, 211, 211, 212, 213, 214, 215, 41, 42, 43, 44, 45, 71, 46, 47}, SKINCOLOR_MOSS, 8, V_PINKMAP, true, UINT16_MAX}, // SKINCOLOR_ROSE + {"Cinnamon", {216, 221, 224, 226, 228, 60, 61, 43, 44, 45, 71, 46, 47, 29, 30, 31}, SKINCOLOR_WRISTWATCH, 6, V_REDMAP, true, UINT16_MAX}, // SKINCOLOR_CINNAMON + {"Ruby", { 0, 208, 209, 210, 211, 213, 39, 40, 41, 43, 186, 186, 169, 169, 253, 254}, SKINCOLOR_SAPPHIRE, 8, V_REDMAP, true, UINT16_MAX}, // SKINCOLOR_RUBY + {"Raspberry", { 0, 208, 209, 210, 32, 33, 34, 35, 37, 39, 41, 43, 44, 45, 46, 47}, SKINCOLOR_MINT, 8, V_REDMAP, true, UINT16_MAX}, // SKINCOLOR_RASPBERRY + {"Red", {209, 210, 32, 34, 36, 38, 39, 40, 41, 42, 43, 44 , 45, 71, 46, 47}, SKINCOLOR_GREEN, 6, V_REDMAP, true, UINT16_MAX}, // SKINCOLOR_RED + {"Crimson", {210, 33, 35, 38, 40, 42, 43, 45, 71, 71, 46, 46, 47, 47, 30, 31}, SKINCOLOR_PINETREE, 6, V_REDMAP, true, UINT16_MAX}, // SKINCOLOR_CRIMSON + {"Maroon", { 32, 33, 35, 37, 39, 41, 43, 237, 26, 26, 27, 27, 28, 29, 30, 31}, SKINCOLOR_TOXIC, 8, V_REDMAP, true, UINT16_MAX}, // SKINCOLOR_MAROON + {"Lemonade", { 0, 80, 81, 82, 83, 216, 210, 211, 212, 213, 214, 215, 43, 44, 71, 47}, SKINCOLOR_THUNDER, 8, V_PINKMAP, true, UINT16_MAX}, // SKINCOLOR_LEMONADE + {"Scarlet", { 48, 49, 50, 51, 53, 34, 36, 38, 184, 185, 168, 168, 169, 169, 254, 31}, SKINCOLOR_ALGAE, 10, V_REDMAP, true, UINT16_MAX}, // SKINCOLOR_SCARLET + {"Ketchup", { 72, 73, 64, 51, 52, 54, 34, 36, 38, 40, 42, 43, 44, 71, 46, 47}, SKINCOLOR_MUSTARD, 10, V_REDMAP, true, UINT16_MAX}, // SKINCOLOR_KETCHUP + {"Dawn", { 0, 208, 216, 209, 210, 211, 212, 57, 58, 59, 60, 61, 63, 71, 47, 31}, SKINCOLOR_DUSK, 8, V_ORANGEMAP, true, UINT16_MAX}, // SKINCOLOR_DAWN + {"Sunslam", { 82, 72, 73, 64, 51, 53, 55, 213, 214, 195, 195, 173, 174, 175, 253, 254}, SKINCOLOR_MOONSET, 8, V_ORANGEMAP, true, UINT16_MAX}, // SKINCOLOR_SUNSLAM + {"Creamsicle", { 0, 0, 208, 208, 48, 49, 50, 52, 53, 54, 56, 57, 58, 60, 61, 63}, SKINCOLOR_PERIWINKLE, 8, V_ORANGEMAP, true, UINT16_MAX}, // SKINCOLOR_CREAMSICLE + {"Orange", {208, 48, 49, 50, 51, 52, 53, 54, 55, 57, 59, 60, 62, 44, 71, 47}, SKINCOLOR_BLUE, 8, V_ORANGEMAP, true, UINT16_MAX}, // SKINCOLOR_ORANGE + {"Rosewood", { 50, 52, 55, 56, 58, 59, 60, 61, 62, 63, 44, 45, 71, 46, 47, 30}, SKINCOLOR_MIDNIGHT, 6, V_ORANGEMAP, true, UINT16_MAX}, // SKINCOLOR_ROSEWOOD + {"Tangerine", { 80, 81, 82, 83, 64, 51, 52, 54, 55, 57, 58, 60, 61, 63, 71, 47}, SKINCOLOR_LIME, 8, V_ORANGEMAP, true, UINT16_MAX}, // SKINCOLOR_TANGERINE + {"Tan", { 0, 80, 81, 82, 83, 84, 85, 86, 87, 245, 246, 248, 249, 251, 237, 239}, SKINCOLOR_RUST, 8, V_TANMAP, true, UINT16_MAX}, // SKINCOLOR_TAN + {"Cream", { 0, 80, 80, 81, 81, 49, 51, 222, 224, 227, 230, 233, 236, 239, 29, 31}, SKINCOLOR_COPPER, 10, V_TANMAP, true, UINT16_MAX}, // SKINCOLOR_CREAM + {"Gold", { 0, 80, 81, 83, 64, 65, 66, 67, 68, 215, 69, 70, 44, 71, 46, 47}, SKINCOLOR_SLATE, 8, V_GOLDMAP, true, UINT16_MAX}, // SKINCOLOR_GOLD + {"Royal", { 80, 81, 83, 64, 65, 223, 229, 196, 196, 197, 197, 198, 199, 29, 30, 31}, SKINCOLOR_PLATINUM, 6, V_GOLDMAP, true, UINT16_MAX}, // SKINCOLOR_ROYAL + {"Bronze", { 83, 64, 65, 66, 67, 215, 69, 70, 44, 44, 45, 71, 46, 47, 29, 31}, SKINCOLOR_STEEL, 8, V_GOLDMAP, true, UINT16_MAX}, // SKINCOLOR_BRONZE + {"Copper", { 0, 82, 64, 65, 67, 68, 70, 237, 239, 28, 28, 29, 29, 30, 30, 31}, SKINCOLOR_CREAM, 6, V_GOLDMAP, true, UINT16_MAX}, // SKINCOLOR_COPPER + {"Yellow", { 0, 80, 81, 82, 83, 73, 84, 74, 64, 65, 66, 67, 68, 69, 70, 71}, SKINCOLOR_AQUAMARINE, 8, V_YELLOWMAP, true, UINT16_MAX}, // SKINCOLOR_YELLOW + {"Mustard", { 80, 81, 82, 83, 64, 65, 65, 76, 76, 77, 77, 78, 79, 237, 239, 29}, SKINCOLOR_KETCHUP, 8, V_YELLOWMAP, true, UINT16_MAX}, // SKINCOLOR_MUSTARD + {"Banana", { 80, 81, 83, 72, 73, 74, 75, 76, 77, 78, 79, 236, 237, 238, 239, 30}, SKINCOLOR_EMERALD, 8, V_YELLOWMAP, true, UINT16_MAX}, // SKINCOLOR_BANANA + {"Olive", { 80, 82, 73, 74, 75, 76, 77, 78, 79, 236, 237, 238, 239, 28, 29, 31}, SKINCOLOR_TEAL, 8, V_YELLOWMAP, true, UINT16_MAX}, // SKINCOLOR_OLIVE + {"Crocodile", { 0, 80, 81, 88, 88, 188, 189, 76, 76, 77, 78, 79, 236, 237, 238, 239}, SKINCOLOR_VIOLET, 8, V_YELLOWMAP, true, UINT16_MAX}, // SKINCOLOR_CROCODILE + {"Peridot", { 0, 80, 81, 88, 188, 189, 190, 191, 94, 94, 95, 95, 109, 110, 111, 31}, SKINCOLOR_NAVY, 6, V_GREENMAP, true, UINT16_MAX}, // SKINCOLOR_PERIDOT + {"Vomit", { 0, 208, 216, 209, 218, 51, 65, 76, 191, 191, 126, 143, 138, 175, 169, 254}, SKINCOLOR_SKUNK, 8, V_GREENMAP, true, UINT16_MAX}, // SKINCOLOR_VOMIT + {"Garden", { 81, 82, 83, 73, 64, 65, 66, 92, 92, 93, 93, 94, 95, 109, 110, 111}, SKINCOLOR_LAVENDER, 6, V_GREENMAP, true, UINT16_MAX}, // SKINCOLOR_GARDEN + {"Lime", { 0, 80, 81, 88, 188, 189, 114, 114, 115, 115, 116, 116, 117, 118, 119, 111}, SKINCOLOR_TANGERINE, 8, V_GREENMAP, true, UINT16_MAX}, // SKINCOLOR_LIME + {"Handheld", { 83, 72, 73, 74, 75, 76, 102, 104, 105, 106, 107, 108, 109, 110, 111, 31}, SKINCOLOR_ULTRAMARINE, 8, V_GREENMAP, true, UINT16_MAX}, // SKINCOLOR_HANDHELD + {"Tea", { 0, 80, 80, 81, 88, 89, 90, 91, 92, 93, 94, 95, 109, 110, 111, 31}, SKINCOLOR_BLOSSOM, 8, V_GREENMAP, true, UINT16_MAX}, // SKINCOLOR_TEA + {"Pistachio", { 0, 80, 88, 88, 89, 90, 91, 102, 103, 104, 105, 106, 107, 108, 109, 110}, SKINCOLOR_PINK, 6, V_GREENMAP, true, UINT16_MAX}, // SKINCOLOR_PISTACHIO + {"Moss", { 88, 89, 90, 91, 91, 92, 93, 94, 107, 107, 108, 108, 109, 109, 110, 111}, SKINCOLOR_ROSE, 8, V_GREENMAP, true, UINT16_MAX}, // SKINCOLOR_MOSS + {"Camouflage", {208, 84, 85, 240, 241, 243, 245, 94, 107, 108, 108, 109, 109, 110, 110, 111}, SKINCOLOR_CAMOUFLAGE, 8, V_GREENMAP, true, UINT16_MAX}, // SKINCOLOR_CAMOUFLAGE + {"Mint", { 0, 88, 88, 89, 89, 100, 101, 102, 125, 126, 143, 143, 138, 175, 169, 254}, SKINCOLOR_RASPBERRY, 8, V_GREENMAP, true, UINT16_MAX}, // SKINCOLOR_MINT + {"Green", { 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111}, SKINCOLOR_RED, 8, V_GREENMAP, true, UINT16_MAX}, // SKINCOLOR_GREEN + {"Pinetree", { 97, 99, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 30, 30, 31}, SKINCOLOR_CRIMSON, 8, V_GREENMAP, true, UINT16_MAX}, // SKINCOLOR_PINETREE + {"Turtle", { 96, 112, 112, 113, 113, 114, 114, 115, 115, 116, 116, 117, 117, 118, 119, 111}, SKINCOLOR_MAGENTA, 8, V_GREENMAP, true, UINT16_MAX}, // SKINCOLOR_TURTLE + {"Swamp", { 96, 112, 113, 114, 115, 116, 117, 118, 119, 119, 29, 29, 30, 30, 31, 31}, SKINCOLOR_BYZANTIUM, 8, V_GREENMAP, true, UINT16_MAX}, // SKINCOLOR_SWAMP + {"Dream", { 0, 0, 208, 208, 48, 89, 98, 100, 148, 148, 172, 172, 173, 173, 174, 175}, SKINCOLOR_POMEGRANATE, 8, V_GREENMAP, true, UINT16_MAX}, // SKINCOLOR_DREAM + {"Plague", { 80, 88, 96, 112, 113, 124, 142, 149, 149, 173, 174, 175, 169, 253, 254, 31}, SKINCOLOR_NOVA, 8, V_GREENMAP, true, UINT16_MAX}, // SKINCOLOR_PLAGUE + {"Emerald", { 0, 120, 121, 112, 113, 114, 115, 125, 125, 126, 126, 127, 138, 175, 253, 254}, SKINCOLOR_BANANA, 8, V_GREENMAP, true, UINT16_MAX}, // SKINCOLOR_EMERALD + {"Algae", {128, 129, 130, 131, 132, 133, 134, 115, 115, 116, 116, 117, 118, 119, 110, 111}, SKINCOLOR_SCARLET, 10, V_GREENMAP, true, UINT16_MAX}, // SKINCOLOR_ALGAE + {"Aquamarine", { 0, 128, 120, 121, 122, 123, 124, 125, 126, 126, 127, 127, 118, 118, 119, 111}, SKINCOLOR_YELLOW, 8, V_AQUAMAP, true, UINT16_MAX}, // SKINCOLOR_AQUAMARINE + {"Turquoise", {128, 120, 121, 122, 123, 141, 141, 142, 142, 143, 143, 138, 138, 139, 139, 31}, SKINCOLOR_MAUVE, 10, V_AQUAMAP, true, UINT16_MAX}, // SKINCOLOR_TURQUOISE + {"Teal", { 0, 120, 120, 121, 140, 141, 142, 143, 143, 138, 138, 139, 139, 254, 254, 31}, SKINCOLOR_OLIVE, 8, V_AQUAMAP, true, UINT16_MAX}, // SKINCOLOR_TEAL + {"Robin", { 0, 80, 81, 82, 83, 88, 121, 140, 133, 133, 134, 135, 136, 137, 138, 139}, SKINCOLOR_THISTLE, 8, V_SKYMAP, true, UINT16_MAX}, // SKINCOLOR_ROBIN + {"Cyan", { 0, 0, 128, 128, 255, 131, 132, 134, 142, 142, 143, 127, 118, 119, 110, 111}, SKINCOLOR_PEACH, 8, V_SKYMAP, true, UINT16_MAX}, // SKINCOLOR_CYAN + {"Jawz", { 0, 0, 128, 128, 129, 146, 133, 134, 135, 149, 149, 173, 173, 174, 175, 31}, SKINCOLOR_LILAC, 10, V_SKYMAP, true, UINT16_MAX}, // SKINCOLOR_JAWZ + {"Cerulean", { 0, 128, 129, 130, 131, 132, 133, 135, 136, 136, 137, 137, 138, 138, 139, 31}, SKINCOLOR_CARAMEL, 8, V_SKYMAP, true, UINT16_MAX}, // SKINCOLOR_CERULEAN + {"Navy", {128, 129, 130, 132, 134, 135, 136, 137, 137, 138, 138, 139, 139, 29, 30, 31}, SKINCOLOR_PERIDOT, 8, V_SKYMAP, true, UINT16_MAX}, // SKINCOLOR_NAVY + {"Platinum", { 0, 0, 0, 144, 144, 145, 9, 11, 14, 142, 136, 137, 138, 138, 139, 31}, SKINCOLOR_ROYAL, 8, V_GRAYMAP, true, UINT16_MAX}, // SKINCOLOR_PLATINUM + {"Slate", { 0, 0, 144, 144, 144, 145, 145, 145, 170, 170, 171, 171, 172, 173, 174, 175}, SKINCOLOR_GOLD, 10, 0, true, UINT16_MAX}, // SKINCOLOR_SLATE + {"Steel", { 0, 144, 144, 145, 145, 170, 170, 171, 171, 172, 172, 173, 173, 174, 175, 31}, SKINCOLOR_BRONZE, 10, V_GRAYMAP, true, UINT16_MAX}, // SKINCOLOR_STEEL + {"Thunder", { 80, 81, 82, 83, 64, 65, 11, 171, 172, 173, 173, 157, 158, 159, 254, 31}, SKINCOLOR_LEMONADE, 8, V_GOLDMAP, true, UINT16_MAX}, // SKINCOLOR_THUNDER + {"Nova", { 0, 83, 49, 50, 51, 32, 192, 148, 148, 172, 173, 174, 175, 29, 30, 31}, SKINCOLOR_PLAGUE, 10, V_BLUEMAP, true, UINT16_MAX}, // SKINCOLOR_NOVA + {"Rust", {208, 48, 216, 217, 240, 241, 242, 171, 172, 173, 24, 25, 26, 28, 29, 31}, SKINCOLOR_TAN, 8, V_BROWNMAP, true, UINT16_MAX}, // SKINCOLOR_RUST + {"Wristwatch", { 48, 218, 221, 224, 227, 231, 196, 173, 173, 174, 159, 159, 253, 253, 254, 31}, SKINCOLOR_CINNAMON, 8, V_BROWNMAP, true, UINT16_MAX}, // SKINCOLOR_WRISTWATCH + {"Jet", {145, 146, 147, 148, 149, 173, 173, 174, 175, 175, 28, 28, 29, 29, 30, 31}, SKINCOLOR_TAFFY, 8, V_GRAYMAP, true, UINT16_MAX}, // SKINCOLOR_JET + {"Sapphire", { 0, 128, 129, 131, 133, 135, 149, 150, 152, 154, 156, 158, 159, 253, 254, 31}, SKINCOLOR_RUBY, 6, V_SKYMAP, true, UINT16_MAX}, // SKINCOLOR_SAPPHIRE + {"Ultramarine", { 0, 0, 120, 120, 121, 133, 135, 149, 149, 166, 166, 167, 168, 169, 254, 31}, SKINCOLOR_HANDHELD, 10, V_SKYMAP, true, UINT16_MAX}, // SKINCOLOR_ULTRAMARINE + {"Periwinkle", { 0, 0, 144, 144, 145, 146, 147, 149, 150, 152, 154, 155, 157, 159, 253, 254}, SKINCOLOR_CREAMSICLE, 8, V_BLUEMAP, true, UINT16_MAX}, // SKINCOLOR_PERIWINKLE + {"Blue", {144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 155, 156, 158, 253, 254, 31}, SKINCOLOR_ORANGE, 8, V_BLUEMAP, true, UINT16_MAX}, // SKINCOLOR_BLUE + {"Midnight", {146, 148, 149, 150, 152, 153, 155, 157, 159, 253, 253, 254, 254, 31, 31, 31}, SKINCOLOR_ROSEWOOD, 8, V_BLUEMAP, true, UINT16_MAX}, // SKINCOLOR_MIDNIGHT + {"Blueberry", { 0, 144, 145, 146, 147, 171, 172, 166, 166, 167, 167, 168, 168, 175, 169, 253}, SKINCOLOR_PURPLE, 8, V_BLUEMAP, true, UINT16_MAX}, // SKINCOLOR_BLUEBERRY + {"Thistle", { 0, 0, 0, 252, 252, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 254}, SKINCOLOR_ROBIN, 8, V_PURPLEMAP, true, UINT16_MAX}, // SKINCOLOR_THISTLE + {"Purple", { 0, 252, 160, 161, 162, 163, 164, 165, 166, 167, 168, 168, 169, 169, 253, 254}, SKINCOLOR_BLUEBERRY, 10, V_PURPLEMAP, true, UINT16_MAX}, // SKINCOLOR_PURPLE + {"Pastel", { 0, 128, 128, 129, 129, 146, 170, 162, 163, 164, 165, 166, 167, 168, 169, 254}, SKINCOLOR_FUCHSIA, 11, V_PURPLEMAP, true, UINT16_MAX}, // SKINCOLOR_PASTEL + {"Moonset", { 0, 144, 145, 146, 170, 162, 163, 184, 184, 207, 207, 44, 45, 46, 47, 31}, SKINCOLOR_SUNSLAM, 10, V_MAGENTAMAP, true, UINT16_MAX}, // SKINCOLOR_MOONSET + {"Dusk", {252, 200, 201, 192, 193, 194, 172, 172, 173, 173, 174, 174, 175, 169, 253, 254}, SKINCOLOR_DAWN, 6, V_MAGENTAMAP, true, UINT16_MAX}, // SKINCOLOR_DUSK + {"Violet", {176, 177, 178, 179, 180, 181, 182, 183, 184, 165, 165, 166, 167, 168, 169, 254}, SKINCOLOR_CROCODILE, 8, V_MAGENTAMAP, true, UINT16_MAX}, // SKINCOLOR_VIOLET + {"Magenta", {252, 200, 177, 177, 178, 179, 180, 181, 182, 183, 183, 184, 185, 186, 187, 31}, SKINCOLOR_TURTLE, 8, V_MAGENTAMAP, true, UINT16_MAX}, // SKINCOLOR_MAGENTA + {"Fuchsia", {208, 209, 209, 32, 33, 182, 183, 184, 185, 185, 186, 186, 187, 253, 254, 31}, SKINCOLOR_PASTEL, 11, V_MAGENTAMAP, true, UINT16_MAX}, // SKINCOLOR_FUCHSIA + {"Toxic", { 0, 0, 88, 88, 89, 6, 8, 10, 193, 194, 195, 184, 185, 186, 187, 31}, SKINCOLOR_MAROON, 8, V_LAVENDERMAP, true, UINT16_MAX}, // SKINCOLOR_TOXIC + {"Mauve", { 80, 81, 82, 83, 64, 50, 201, 192, 193, 194, 195, 173, 174, 175, 253, 254}, SKINCOLOR_TURQUOISE, 8, V_LAVENDERMAP, true, UINT16_MAX}, // SKINCOLOR_MAUVE + {"Lavender", {252, 177, 179, 192, 193, 194, 195, 196, 196, 197, 197, 198, 198, 199, 30, 31}, SKINCOLOR_GARDEN, 6, V_LAVENDERMAP, true, UINT16_MAX}, // SKINCOLOR_LAVENDER + {"Byzantium", {145, 192, 193, 194, 195, 196, 197, 198, 199, 199, 29, 29, 30, 30, 31, 31}, SKINCOLOR_SWAMP, 8, V_LAVENDERMAP, true, UINT16_MAX}, // SKINCOLOR_BYZANTIUM + {"Pomegranate", {208, 209, 210, 211, 212, 213, 214, 195, 195, 196, 196, 197, 198, 199, 29, 30}, SKINCOLOR_DREAM, 8, V_LAVENDERMAP, true, UINT16_MAX}, // SKINCOLOR_POMEGRANATE + {"Lilac", { 0, 0, 0, 252, 252, 176, 200, 201, 179, 192, 193, 194, 195, 196, 197, 198}, SKINCOLOR_JAWZ, 6, V_PINKMAP, true, UINT16_MAX}, // SKINCOLOR_LILAC + {"Blossom", { 0, 252, 252, 176, 200, 177, 201, 202, 202, 34, 36, 38, 40, 42, 45, 46}, SKINCOLOR_TEA, 8, V_PINKMAP, true, UINT16_MAX}, // SKINCOLOR_BLOSSOM + {"Taffy", { 0, 252, 252, 200, 200, 201, 202, 203, 204, 204, 205, 206, 207, 43, 45, 47}, SKINCOLOR_JET, 8, V_PINKMAP, true, UINT16_MAX}, // SKINCOLOR_TAFFY // super (todo: replace these with the kart ones) - {"Super Silver 1", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x03}, SKINCOLOR_BLACK, 15, 0, false}, // SKINCOLOR_SUPERSILVER1 - {"Super Silver 2", {0x00, 0x01, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x07}, SKINCOLOR_BLACK, 6, 0, false}, // SKINCOLOR_SUPERSILVER2 - {"Super Silver 3", {0x01, 0x02, 0x02, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x07, 0x09, 0x0b}, SKINCOLOR_BLACK, 5, 0, false}, // SKINCOLOR_SUPERSILVER3 - {"Super Silver 4", {0x02, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x07, 0x09, 0x0b, 0x0d, 0x0f, 0x11}, SKINCOLOR_BLACK, 5, V_GRAYMAP, false}, // SKINCOLOR_SUPERSILVER4 - {"Super Silver 5", {0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x07, 0x09, 0x0b, 0x0d, 0x0f, 0x11, 0x13}, SKINCOLOR_BLACK, 5, V_GRAYMAP, false}, // SKINCOLOR_SUPERSILVER5 + {"Super Silver 1", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x03}, SKINCOLOR_BLACK, 15, 0, false, UINT16_MAX}, // SKINCOLOR_SUPERSILVER1 + {"Super Silver 2", {0x00, 0x01, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x07}, SKINCOLOR_BLACK, 6, 0, false, UINT16_MAX}, // SKINCOLOR_SUPERSILVER2 + {"Super Silver 3", {0x01, 0x02, 0x02, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x07, 0x09, 0x0b}, SKINCOLOR_BLACK, 5, 0, false, UINT16_MAX}, // SKINCOLOR_SUPERSILVER3 + {"Super Silver 4", {0x02, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x07, 0x09, 0x0b, 0x0d, 0x0f, 0x11}, SKINCOLOR_BLACK, 5, V_GRAYMAP, false, UINT16_MAX}, // SKINCOLOR_SUPERSILVER4 + {"Super Silver 5", {0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x07, 0x09, 0x0b, 0x0d, 0x0f, 0x11, 0x13}, SKINCOLOR_BLACK, 5, V_GRAYMAP, false, UINT16_MAX}, // SKINCOLOR_SUPERSILVER5 - {"Super Red 1", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0xd0, 0xd1, 0xd1, 0xd2, 0xd2}, SKINCOLOR_CYAN, 15, 0, false}, // SKINCOLOR_SUPERRED1 - {"Super Red 2", {0x00, 0x00, 0x00, 0xd0, 0xd0, 0xd0, 0xd1, 0xd1, 0xd1, 0xd2, 0xd2, 0xd2, 0x20, 0x20, 0x21, 0x21}, SKINCOLOR_CYAN, 14, V_PINKMAP, false}, // SKINCOLOR_SUPERRED2 - {"Super Red 3", {0x00, 0x00, 0xd0, 0xd0, 0xd1, 0xd1, 0xd2, 0xd2, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23}, SKINCOLOR_CYAN, 13, V_REDMAP, false}, // SKINCOLOR_SUPERRED3 - {"Super Red 4", {0x00, 0xd0, 0xd1, 0xd1, 0xd2, 0xd2, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24}, SKINCOLOR_CYAN, 11, V_REDMAP, false}, // SKINCOLOR_SUPERRED4 - {"Super Red 5", {0xd0, 0xd1, 0xd2, 0xd2, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25, 0x25}, SKINCOLOR_CYAN, 10, V_REDMAP, false}, // SKINCOLOR_SUPERRED5 + {"Super Red 1", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0xd0, 0xd1, 0xd1, 0xd2, 0xd2}, SKINCOLOR_CYAN, 15, 0, false, UINT16_MAX}, // SKINCOLOR_SUPERRED1 + {"Super Red 2", {0x00, 0x00, 0x00, 0xd0, 0xd0, 0xd0, 0xd1, 0xd1, 0xd1, 0xd2, 0xd2, 0xd2, 0x20, 0x20, 0x21, 0x21}, SKINCOLOR_CYAN, 14, V_PINKMAP, false, UINT16_MAX}, // SKINCOLOR_SUPERRED2 + {"Super Red 3", {0x00, 0x00, 0xd0, 0xd0, 0xd1, 0xd1, 0xd2, 0xd2, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23}, SKINCOLOR_CYAN, 13, V_REDMAP, false, UINT16_MAX}, // SKINCOLOR_SUPERRED3 + {"Super Red 4", {0x00, 0xd0, 0xd1, 0xd1, 0xd2, 0xd2, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24}, SKINCOLOR_CYAN, 11, V_REDMAP, false, UINT16_MAX}, // SKINCOLOR_SUPERRED4 + {"Super Red 5", {0xd0, 0xd1, 0xd2, 0xd2, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25, 0x25}, SKINCOLOR_CYAN, 10, V_REDMAP, false, UINT16_MAX}, // SKINCOLOR_SUPERRED5 - {"Super Orange 1", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x30, 0x31, 0x32, 0x33, 0x34}, SKINCOLOR_SAPPHIRE, 15, 0, false}, // SKINCOLOR_SUPERORANGE1 - {"Super Orange 2", {0x00, 0x00, 0x00, 0x00, 0xd0, 0xd0, 0x30, 0x30, 0x31, 0x31, 0x32, 0x32, 0x33, 0x33, 0x34, 0x34}, SKINCOLOR_SAPPHIRE, 12, V_ORANGEMAP, false}, // SKINCOLOR_SUPERORANGE2 - {"Super Orange 3", {0x00, 0x00, 0xd0, 0xd0, 0x30, 0x30, 0x31, 0x31, 0x32, 0x32, 0x33, 0x33, 0x34, 0x34, 0x35, 0x35}, SKINCOLOR_SAPPHIRE, 9, V_ORANGEMAP, false}, // SKINCOLOR_SUPERORANGE3 - {"Super Orange 4", {0x00, 0xd0, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x44, 0x45, 0x46}, SKINCOLOR_SAPPHIRE, 4, V_ORANGEMAP, false}, // SKINCOLOR_SUPERORANGE4 - {"Super Orange 5", {0xd0, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x44, 0x45, 0x46, 0x47}, SKINCOLOR_SAPPHIRE, 3, V_ORANGEMAP, false}, // SKINCOLOR_SUPERORANGE5 + {"Super Orange 1", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x30, 0x31, 0x32, 0x33, 0x34}, SKINCOLOR_SAPPHIRE, 15, 0, false, UINT16_MAX}, // SKINCOLOR_SUPERORANGE1 + {"Super Orange 2", {0x00, 0x00, 0x00, 0x00, 0xd0, 0xd0, 0x30, 0x30, 0x31, 0x31, 0x32, 0x32, 0x33, 0x33, 0x34, 0x34}, SKINCOLOR_SAPPHIRE, 12, V_ORANGEMAP, false, UINT16_MAX}, // SKINCOLOR_SUPERORANGE2 + {"Super Orange 3", {0x00, 0x00, 0xd0, 0xd0, 0x30, 0x30, 0x31, 0x31, 0x32, 0x32, 0x33, 0x33, 0x34, 0x34, 0x35, 0x35}, SKINCOLOR_SAPPHIRE, 9, V_ORANGEMAP, false, UINT16_MAX}, // SKINCOLOR_SUPERORANGE3 + {"Super Orange 4", {0x00, 0xd0, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x44, 0x45, 0x46}, SKINCOLOR_SAPPHIRE, 4, V_ORANGEMAP, false, UINT16_MAX}, // SKINCOLOR_SUPERORANGE4 + {"Super Orange 5", {0xd0, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x44, 0x45, 0x46, 0x47}, SKINCOLOR_SAPPHIRE, 3, V_ORANGEMAP, false, UINT16_MAX}, // SKINCOLOR_SUPERORANGE5 - {"Super Gold 1", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x50, 0x51, 0x52, 0x53, 0x48}, SKINCOLOR_PERIWINKLE, 15, 0, false}, // SKINCOLOR_SUPERGOLD1 - {"Super Gold 2", {0x00, 0x50, 0x51, 0x52, 0x53, 0x53, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x40, 0x41}, SKINCOLOR_PERIWINKLE, 9, V_YELLOWMAP, false}, // SKINCOLOR_SUPERGOLD2 - {"Super Gold 3", {0x51, 0x52, 0x53, 0x53, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x40, 0x41, 0x42, 0x43}, SKINCOLOR_PERIWINKLE, 8, V_YELLOWMAP, false}, // SKINCOLOR_SUPERGOLD3 - {"Super Gold 4", {0x53, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46}, SKINCOLOR_PERIWINKLE, 8, V_YELLOWMAP, false}, // SKINCOLOR_SUPERGOLD4 - {"Super Gold 5", {0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47}, SKINCOLOR_PERIWINKLE, 8, V_YELLOWMAP, false}, // SKINCOLOR_SUPERGOLD5 + {"Super Gold 1", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x50, 0x51, 0x52, 0x53, 0x48}, SKINCOLOR_PERIWINKLE, 15, 0, false, UINT16_MAX}, // SKINCOLOR_SUPERGOLD1 + {"Super Gold 2", {0x00, 0x50, 0x51, 0x52, 0x53, 0x53, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x40, 0x41}, SKINCOLOR_PERIWINKLE, 9, V_YELLOWMAP, false, UINT16_MAX}, // SKINCOLOR_SUPERGOLD2 + {"Super Gold 3", {0x51, 0x52, 0x53, 0x53, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x40, 0x41, 0x42, 0x43}, SKINCOLOR_PERIWINKLE, 8, V_YELLOWMAP, false, UINT16_MAX}, // SKINCOLOR_SUPERGOLD3 + {"Super Gold 4", {0x53, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46}, SKINCOLOR_PERIWINKLE, 8, V_YELLOWMAP, false, UINT16_MAX}, // SKINCOLOR_SUPERGOLD4 + {"Super Gold 5", {0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47}, SKINCOLOR_PERIWINKLE, 8, V_YELLOWMAP, false, UINT16_MAX}, // SKINCOLOR_SUPERGOLD5 - {"Super Peridot 1", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x58, 0x58, 0xbc, 0xbc, 0xbc}, SKINCOLOR_BLUEBERRY, 15, 0, false}, // SKINCOLOR_SUPERPERIDOT1 - {"Super Peridot 2", {0x00, 0x58, 0x58, 0x58, 0xbc, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbe, 0xbe}, SKINCOLOR_BLUEBERRY, 4, V_GREENMAP, false}, // SKINCOLOR_SUPERPERIDOT2 - {"Super Peridot 3", {0x58, 0x58, 0xbc, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbe, 0xbe, 0xbf, 0xbf}, SKINCOLOR_BLUEBERRY, 3, V_GREENMAP, false}, // SKINCOLOR_SUPERPERIDOT3 - {"Super Peridot 4", {0x58, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbe, 0xbe, 0xbf, 0xbf, 0x5e, 0x5e, 0x5f}, SKINCOLOR_BLUEBERRY, 3, V_GREENMAP, false}, // SKINCOLOR_SUPERPERIDOT4 - {"Super Peridot 5", {0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbe, 0xbe, 0xbf, 0xbf, 0x5e, 0x5e, 0x5f, 0x77}, SKINCOLOR_BLUEBERRY, 3, V_GREENMAP, false}, // SKINCOLOR_SUPERPERIDOT5 + {"Super Peridot 1", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x58, 0x58, 0xbc, 0xbc, 0xbc}, SKINCOLOR_BLUEBERRY, 15, 0, false, UINT16_MAX}, // SKINCOLOR_SUPERPERIDOT1 + {"Super Peridot 2", {0x00, 0x58, 0x58, 0x58, 0xbc, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbe, 0xbe}, SKINCOLOR_BLUEBERRY, 4, V_GREENMAP, false, UINT16_MAX}, // SKINCOLOR_SUPERPERIDOT2 + {"Super Peridot 3", {0x58, 0x58, 0xbc, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbe, 0xbe, 0xbf, 0xbf}, SKINCOLOR_BLUEBERRY, 3, V_GREENMAP, false, UINT16_MAX}, // SKINCOLOR_SUPERPERIDOT3 + {"Super Peridot 4", {0x58, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbe, 0xbe, 0xbf, 0xbf, 0x5e, 0x5e, 0x5f}, SKINCOLOR_BLUEBERRY, 3, V_GREENMAP, false, UINT16_MAX}, // SKINCOLOR_SUPERPERIDOT4 + {"Super Peridot 5", {0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbe, 0xbe, 0xbf, 0xbf, 0x5e, 0x5e, 0x5f, 0x77}, SKINCOLOR_BLUEBERRY, 3, V_GREENMAP, false, UINT16_MAX}, // SKINCOLOR_SUPERPERIDOT5 - {"Super Sky 1", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x81, 0x82, 0x83, 0x84}, SKINCOLOR_RUST, 15, 0, false}, // SKINCOLOR_SUPERSKY1 - {"Super Sky 2", {0x00, 0x80, 0x81, 0x82, 0x83, 0x83, 0x84, 0x84, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x86, 0x86}, SKINCOLOR_RUST, 4, V_SKYMAP, false}, // SKINCOLOR_SUPERSKY2 - {"Super Sky 3", {0x81, 0x82, 0x83, 0x83, 0x84, 0x84, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x86, 0x86, 0x87, 0x87}, SKINCOLOR_RUST, 3, V_SKYMAP, false}, // SKINCOLOR_SUPERSKY3 - {"Super Sky 4", {0x83, 0x84, 0x84, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x86, 0x86, 0x87, 0x87, 0x88, 0x89, 0x8a}, SKINCOLOR_RUST, 3, V_SKYMAP, false}, // SKINCOLOR_SUPERSKY4 - {"Super Sky 5", {0x84, 0x84, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x86, 0x86, 0x87, 0x87, 0x88, 0x89, 0x8a, 0x8b}, SKINCOLOR_RUST, 3, V_SKYMAP, false}, // SKINCOLOR_SUPERSKY5 + {"Super Sky 1", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x81, 0x82, 0x83, 0x84}, SKINCOLOR_RUST, 15, 0, false, UINT16_MAX}, // SKINCOLOR_SUPERSKY1 + {"Super Sky 2", {0x00, 0x80, 0x81, 0x82, 0x83, 0x83, 0x84, 0x84, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x86, 0x86}, SKINCOLOR_RUST, 4, V_SKYMAP, false, UINT16_MAX}, // SKINCOLOR_SUPERSKY2 + {"Super Sky 3", {0x81, 0x82, 0x83, 0x83, 0x84, 0x84, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x86, 0x86, 0x87, 0x87}, SKINCOLOR_RUST, 3, V_SKYMAP, false, UINT16_MAX}, // SKINCOLOR_SUPERSKY3 + {"Super Sky 4", {0x83, 0x84, 0x84, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x86, 0x86, 0x87, 0x87, 0x88, 0x89, 0x8a}, SKINCOLOR_RUST, 3, V_SKYMAP, false, UINT16_MAX}, // SKINCOLOR_SUPERSKY4 + {"Super Sky 5", {0x84, 0x84, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x86, 0x86, 0x87, 0x87, 0x88, 0x89, 0x8a, 0x8b}, SKINCOLOR_RUST, 3, V_SKYMAP, false, UINT16_MAX}, // SKINCOLOR_SUPERSKY5 - {"Super Purple 1", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x90, 0xa0, 0xa0, 0xa1, 0xa2}, SKINCOLOR_EMERALD, 15, 0, false}, // SKINCOLOR_SUPERPURPLE1 - {"Super Purple 2", {0x00, 0x90, 0xa0, 0xa0, 0xa1, 0xa1, 0xa2, 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4, 0xa5, 0xa5}, SKINCOLOR_EMERALD, 4, V_PURPLEMAP, false}, // SKINCOLOR_SUPERPURPLE2 - {"Super Purple 3", {0xa0, 0xa0, 0xa1, 0xa1, 0xa2, 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4, 0xa5, 0xa5, 0xa6, 0xa6}, SKINCOLOR_EMERALD, 0, V_PURPLEMAP, false}, // SKINCOLOR_SUPERPURPLE3 - {"Super Purple 4", {0xa1, 0xa2, 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4, 0xa5, 0xa5, 0xa6, 0xa6, 0xa7, 0xa8, 0xa9}, SKINCOLOR_EMERALD, 0, V_PURPLEMAP, false}, // SKINCOLOR_SUPERPURPLE4 - {"Super Purple 5", {0xa2, 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4, 0xa5, 0xa5, 0xa6, 0xa6, 0xa7, 0xa8, 0xa9, 0xfd}, SKINCOLOR_EMERALD, 0, V_PURPLEMAP, false}, // SKINCOLOR_SUPERPURPLE5 + {"Super Purple 1", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x90, 0xa0, 0xa0, 0xa1, 0xa2}, SKINCOLOR_EMERALD, 15, 0, false, UINT16_MAX}, // SKINCOLOR_SUPERPURPLE1 + {"Super Purple 2", {0x00, 0x90, 0xa0, 0xa0, 0xa1, 0xa1, 0xa2, 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4, 0xa5, 0xa5}, SKINCOLOR_EMERALD, 4, V_PURPLEMAP, false, UINT16_MAX}, // SKINCOLOR_SUPERPURPLE2 + {"Super Purple 3", {0xa0, 0xa0, 0xa1, 0xa1, 0xa2, 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4, 0xa5, 0xa5, 0xa6, 0xa6}, SKINCOLOR_EMERALD, 0, V_PURPLEMAP, false, UINT16_MAX}, // SKINCOLOR_SUPERPURPLE3 + {"Super Purple 4", {0xa1, 0xa2, 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4, 0xa5, 0xa5, 0xa6, 0xa6, 0xa7, 0xa8, 0xa9}, SKINCOLOR_EMERALD, 0, V_PURPLEMAP, false, UINT16_MAX}, // SKINCOLOR_SUPERPURPLE4 + {"Super Purple 5", {0xa2, 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4, 0xa5, 0xa5, 0xa6, 0xa6, 0xa7, 0xa8, 0xa9, 0xfd}, SKINCOLOR_EMERALD, 0, V_PURPLEMAP, false, UINT16_MAX}, // SKINCOLOR_SUPERPURPLE5 - {"Super Rust 1", {0x00, 0xd0, 0xd0, 0xd0, 0x30, 0x30, 0x31, 0x32, 0x33, 0x37, 0x3a, 0x44, 0x45, 0x46, 0x47, 0x2e}, SKINCOLOR_CYAN, 14, V_ORANGEMAP, false}, // SKINCOLOR_SUPERRUST1 - {"Super Rust 2", {0x30, 0x31, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x38, 0x3a, 0x44, 0x45, 0x46, 0x47, 0x47, 0x2e}, SKINCOLOR_CYAN, 10, V_ORANGEMAP, false}, // SKINCOLOR_SUPERRUST2 - {"Super Rust 3", {0x31, 0x32, 0x33, 0x34, 0x36, 0x37, 0x38, 0x3a, 0x44, 0x45, 0x45, 0x46, 0x46, 0x47, 0x2e, 0x2e}, SKINCOLOR_CYAN, 9, V_ORANGEMAP, false}, // SKINCOLOR_SUPERRUST3 - {"Super Rust 4", {0x48, 0x40, 0x41, 0x42, 0x43, 0x44, 0x44, 0x45, 0x45, 0x46, 0x46, 0x47, 0x47, 0x2e, 0x2e, 0x2e}, SKINCOLOR_CYAN, 8, V_ORANGEMAP, false}, // SKINCOLOR_SUPERRUST4 - {"Super Rust 5", {0x41, 0x42, 0x43, 0x43, 0x44, 0x44, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xed, 0xee, 0xee, 0xef, 0xef}, SKINCOLOR_CYAN, 8, V_ORANGEMAP, false}, // SKINCOLOR_SUPERRUST5 + {"Super Rust 1", {0x00, 0xd0, 0xd0, 0xd0, 0x30, 0x30, 0x31, 0x32, 0x33, 0x37, 0x3a, 0x44, 0x45, 0x46, 0x47, 0x2e}, SKINCOLOR_CYAN, 14, V_ORANGEMAP, false, UINT16_MAX}, // SKINCOLOR_SUPERRUST1 + {"Super Rust 2", {0x30, 0x31, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x38, 0x3a, 0x44, 0x45, 0x46, 0x47, 0x47, 0x2e}, SKINCOLOR_CYAN, 10, V_ORANGEMAP, false, UINT16_MAX}, // SKINCOLOR_SUPERRUST2 + {"Super Rust 3", {0x31, 0x32, 0x33, 0x34, 0x36, 0x37, 0x38, 0x3a, 0x44, 0x45, 0x45, 0x46, 0x46, 0x47, 0x2e, 0x2e}, SKINCOLOR_CYAN, 9, V_ORANGEMAP, false, UINT16_MAX}, // SKINCOLOR_SUPERRUST3 + {"Super Rust 4", {0x48, 0x40, 0x41, 0x42, 0x43, 0x44, 0x44, 0x45, 0x45, 0x46, 0x46, 0x47, 0x47, 0x2e, 0x2e, 0x2e}, SKINCOLOR_CYAN, 8, V_ORANGEMAP, false, UINT16_MAX}, // SKINCOLOR_SUPERRUST4 + {"Super Rust 5", {0x41, 0x42, 0x43, 0x43, 0x44, 0x44, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xed, 0xee, 0xee, 0xef, 0xef}, SKINCOLOR_CYAN, 8, V_ORANGEMAP, false, UINT16_MAX}, // SKINCOLOR_SUPERRUST5 - {"Super Tan 1", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x50, 0x51, 0x51, 0x52, 0x52}, SKINCOLOR_BROWN, 14, 0, false}, // SKINCOLOR_SUPERTAN1 - {"Super Tan 2", {0x00, 0x50, 0x50, 0x51, 0x51, 0x52, 0x52, 0x52, 0x54, 0x54, 0x54, 0x54, 0x55, 0x56, 0x57, 0xf5}, SKINCOLOR_BROWN, 13, V_BROWNMAP, false}, // SKINCOLOR_SUPERTAN2 - {"Super Tan 3", {0x50, 0x51, 0x51, 0x52, 0x52, 0x52, 0x54, 0x54, 0x54, 0x54, 0x55, 0x56, 0x57, 0xf5, 0xf7, 0xf9}, SKINCOLOR_BROWN, 12, V_BROWNMAP, false}, // SKINCOLOR_SUPERTAN3 - {"Super Tan 4", {0x51, 0x52, 0x52, 0x52, 0x52, 0x54, 0x54, 0x54, 0x55, 0x56, 0x57, 0xf5, 0xf7, 0xf9, 0xfb, 0xed}, SKINCOLOR_BROWN, 11, V_BROWNMAP, false}, // SKINCOLOR_SUPERTAN4 - {"Super Tan 5", {0x52, 0x52, 0x54, 0x54, 0x54, 0x55, 0x56, 0x57, 0xf5, 0xf7, 0xf9, 0xfb, 0xed, 0xee, 0xef, 0xef}, SKINCOLOR_BROWN, 10, V_BROWNMAP, false}, // SKINCOLOR_SUPERTAN5 + {"Super Tan 1", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x50, 0x51, 0x51, 0x52, 0x52}, SKINCOLOR_BROWN, 14, 0, false, UINT16_MAX}, // SKINCOLOR_SUPERTAN1 + {"Super Tan 2", {0x00, 0x50, 0x50, 0x51, 0x51, 0x52, 0x52, 0x52, 0x54, 0x54, 0x54, 0x54, 0x55, 0x56, 0x57, 0xf5}, SKINCOLOR_BROWN, 13, V_BROWNMAP, false, UINT16_MAX}, // SKINCOLOR_SUPERTAN2 + {"Super Tan 3", {0x50, 0x51, 0x51, 0x52, 0x52, 0x52, 0x54, 0x54, 0x54, 0x54, 0x55, 0x56, 0x57, 0xf5, 0xf7, 0xf9}, SKINCOLOR_BROWN, 12, V_BROWNMAP, false, UINT16_MAX}, // SKINCOLOR_SUPERTAN3 + {"Super Tan 4", {0x51, 0x52, 0x52, 0x52, 0x52, 0x54, 0x54, 0x54, 0x55, 0x56, 0x57, 0xf5, 0xf7, 0xf9, 0xfb, 0xed}, SKINCOLOR_BROWN, 11, V_BROWNMAP, false, UINT16_MAX}, // SKINCOLOR_SUPERTAN4 + {"Super Tan 5", {0x52, 0x52, 0x54, 0x54, 0x54, 0x55, 0x56, 0x57, 0xf5, 0xf7, 0xf9, 0xfb, 0xed, 0xee, 0xef, 0xef}, SKINCOLOR_BROWN, 10, V_BROWNMAP, false, UINT16_MAX}, // SKINCOLOR_SUPERTAN5 - {"Chaos Emerald 1", { 0, 88, 188, 98, 114, 116, 117, 119, 0, 0, 0, 0, 0, 0, 0, 0}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_CHAOSEMERALD1 - {"Chaos Emerald 2", { 0, 80, 82, 74, 65, 52, 56, 60, 0, 0, 0, 0, 0, 0, 0, 0}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_CHAOSEMERALD2 - {"Chaos Emerald 3", { 0, 252, 201, 179, 182, 183, 185, 187, 0, 0, 0, 0, 0, 0, 0, 0}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_CHAOSEMERALD3 - {"Chaos Emerald 4", { 0, 144, 146, 147, 149, 165, 167, 169, 0, 0, 0, 0, 0, 0, 0, 0}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_CHAOSEMERALD4 - {"Chaos Emerald 5", { 0, 1, 144, 4, 9, 170, 14, 21, 0, 0, 0, 0, 0, 0, 0, 0}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_CHAOSEMERALD5 - {"Chaos Emerald 6", { 0, 208, 50, 32, 34, 37, 40, 44, 0, 0, 0, 0, 0, 0, 0, 0}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_CHAOSEMERALD6 - {"Chaos Emerald 7", { 0, 120, 121, 140, 133, 135, 149, 156, 0, 0, 0, 0, 0, 0, 0, 0}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_CHAOSEMERALD7 + {"Chaos Emerald 1", { 0, 88, 188, 98, 114, 116, 117, 119, 0, 0, 0, 0, 0, 0, 0, 0}, SKINCOLOR_NONE, 0, 0, false, UINT16_MAX}, // SKINCOLOR_CHAOSEMERALD1 + {"Chaos Emerald 2", { 0, 80, 82, 74, 65, 52, 56, 60, 0, 0, 0, 0, 0, 0, 0, 0}, SKINCOLOR_NONE, 0, 0, false, UINT16_MAX}, // SKINCOLOR_CHAOSEMERALD2 + {"Chaos Emerald 3", { 0, 252, 201, 179, 182, 183, 185, 187, 0, 0, 0, 0, 0, 0, 0, 0}, SKINCOLOR_NONE, 0, 0, false, UINT16_MAX}, // SKINCOLOR_CHAOSEMERALD3 + {"Chaos Emerald 4", { 0, 144, 146, 147, 149, 165, 167, 169, 0, 0, 0, 0, 0, 0, 0, 0}, SKINCOLOR_NONE, 0, 0, false, UINT16_MAX}, // SKINCOLOR_CHAOSEMERALD4 + {"Chaos Emerald 5", { 0, 1, 144, 4, 9, 170, 14, 21, 0, 0, 0, 0, 0, 0, 0, 0}, SKINCOLOR_NONE, 0, 0, false, UINT16_MAX}, // SKINCOLOR_CHAOSEMERALD5 + {"Chaos Emerald 6", { 0, 208, 50, 32, 34, 37, 40, 44, 0, 0, 0, 0, 0, 0, 0, 0}, SKINCOLOR_NONE, 0, 0, false, UINT16_MAX}, // SKINCOLOR_CHAOSEMERALD6 + {"Chaos Emerald 7", { 0, 120, 121, 140, 133, 135, 149, 156, 0, 0, 0, 0, 0, 0, 0, 0}, SKINCOLOR_NONE, 0, 0, false, UINT16_MAX}, // SKINCOLOR_CHAOSEMERALD7 - {"Invinc Flash", { 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_INVINCFLASH + {"Invinc Flash", { 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}, SKINCOLOR_NONE, 0, 0, false, UINT16_MAX}, // SKINCOLOR_INVINCFLASH - {"Position", { 8, 9, 11, 12, 14, 15, 17, 18, 20, 21, 23, 24, 26, 27, 29, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM - {"Position Win 1", {152, 152, 153, 153, 154, 154, 155, 155, 156, 156, 157, 158, 159, 253, 254, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_WIN1 - {"Position Win 2", {134, 134, 135, 135, 135, 136, 136, 136, 137, 137, 138, 138, 139, 139, 254, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_WIN2 - {"Position Win 3", {255, 255, 122, 122, 123, 123, 141, 141, 142, 142, 143, 143, 138, 139, 254, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_WIN3 - {"Position Lose 1", { 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 71, 46, 47, 29, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_LOSE1 - {"Position Lose 2", { 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 63, 44, 45, 46, 47, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_LOSE2 - {"Position Lose 3", { 73, 74, 75, 76, 76, 77, 77, 78, 78, 79, 79, 236, 237, 238, 239, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_LOSE3 - {"Position Best 1", { 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 71, 46, 47, 29, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_BEST1 - {"Position Best 2", { 73, 74, 75, 76, 76, 77, 77, 78, 78, 79, 79, 236, 237, 238, 239, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_BEST2 - {"Position Best 3", {112, 112, 113, 114, 115, 115, 116, 116, 117, 117, 118, 118, 119, 110, 111, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_BEST3 - {"Position Best 4", {255, 255, 122, 122, 123, 123, 141, 141, 142, 142, 143, 143, 138, 139, 254, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_BEST4 - {"Position Best 5", {152, 152, 153, 153, 154, 154, 155, 155, 156, 156, 157, 158, 159, 253, 254, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_BEST5 - {"Position Best 6", {181, 181, 182, 182, 183, 183, 184, 184, 185, 185, 186, 186, 187, 187, 29, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_BEST6 + {"Position", { 8, 9, 11, 12, 14, 15, 17, 18, 20, 21, 23, 24, 26, 27, 29, 30}, SKINCOLOR_NONE, 0, 0, false, UINT16_MAX}, // SKINCOLOR_POSNUM + {"Position Win 1", {152, 152, 153, 153, 154, 154, 155, 155, 156, 156, 157, 158, 159, 253, 254, 30}, SKINCOLOR_NONE, 0, 0, false, UINT16_MAX}, // SKINCOLOR_POSNUM_WIN1 + {"Position Win 2", {134, 134, 135, 135, 135, 136, 136, 136, 137, 137, 138, 138, 139, 139, 254, 30}, SKINCOLOR_NONE, 0, 0, false, UINT16_MAX}, // SKINCOLOR_POSNUM_WIN2 + {"Position Win 3", {255, 255, 122, 122, 123, 123, 141, 141, 142, 142, 143, 143, 138, 139, 254, 30}, SKINCOLOR_NONE, 0, 0, false, UINT16_MAX}, // SKINCOLOR_POSNUM_WIN3 + {"Position Lose 1", { 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 71, 46, 47, 29, 30}, SKINCOLOR_NONE, 0, 0, false, UINT16_MAX}, // SKINCOLOR_POSNUM_LOSE1 + {"Position Lose 2", { 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 63, 44, 45, 46, 47, 30}, SKINCOLOR_NONE, 0, 0, false, UINT16_MAX}, // SKINCOLOR_POSNUM_LOSE2 + {"Position Lose 3", { 73, 74, 75, 76, 76, 77, 77, 78, 78, 79, 79, 236, 237, 238, 239, 30}, SKINCOLOR_NONE, 0, 0, false, UINT16_MAX}, // SKINCOLOR_POSNUM_LOSE3 + {"Position Best 1", { 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 71, 46, 47, 29, 30}, SKINCOLOR_NONE, 0, 0, false, UINT16_MAX}, // SKINCOLOR_POSNUM_BEST1 + {"Position Best 2", { 73, 74, 75, 76, 76, 77, 77, 78, 78, 79, 79, 236, 237, 238, 239, 30}, SKINCOLOR_NONE, 0, 0, false, UINT16_MAX}, // SKINCOLOR_POSNUM_BEST2 + {"Position Best 3", {112, 112, 113, 114, 115, 115, 116, 116, 117, 117, 118, 118, 119, 110, 111, 30}, SKINCOLOR_NONE, 0, 0, false, UINT16_MAX}, // SKINCOLOR_POSNUM_BEST3 + {"Position Best 4", {255, 255, 122, 122, 123, 123, 141, 141, 142, 142, 143, 143, 138, 139, 254, 30}, SKINCOLOR_NONE, 0, 0, false, UINT16_MAX}, // SKINCOLOR_POSNUM_BEST4 + {"Position Best 5", {152, 152, 153, 153, 154, 154, 155, 155, 156, 156, 157, 158, 159, 253, 254, 30}, SKINCOLOR_NONE, 0, 0, false, UINT16_MAX}, // SKINCOLOR_POSNUM_BEST5 + {"Position Best 6", {181, 181, 182, 182, 183, 183, 184, 184, 185, 185, 186, 186, 187, 187, 29, 30}, SKINCOLOR_NONE, 0, 0, false, UINT16_MAX}, // SKINCOLOR_POSNUM_BEST6 - {"Intermission", {0,80,80,81,81,81,84,85,86,87,246,248,251,26,28,31}, SKINCOLOR_NONE, 0, 0, false} // SKINCOLOR_INTERMISSION + {"Intermission", {0,80,80,81,81,81,84,85,86,87,246,248,251,26,28,31}, SKINCOLOR_NONE, 0, 0, false, UINT16_MAX}, // SKINCOLOR_INTERMISSION }; /** Patches the mobjinfo, state, and skincolor tables. diff --git a/src/k_menudraw.c b/src/k_menudraw.c index f5b3ee3d9..3681aaeb0 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -6117,11 +6117,16 @@ static void M_DrawMapMedals(INT32 mapnum, INT32 x, INT32 y) if (hasmedals) x -= 4; - if (mapheaderinfo[mapnum]->cachedcan != 0 && mapheaderinfo[mapnum]->cachedcan < MAXCANCOLORS && gamedata->spraycans[mapheaderinfo[mapnum]->cachedcan].got == true) + if (mapheaderinfo[mapnum]->cache_spraycan < gamedata->numspraycans) { - V_DrawSmallMappedPatch(x, y, 0, W_CachePatchName("GOTCAN", PU_CACHE), - R_GetTranslationColormap(TC_RAINBOW, mapheaderinfo[mapnum]->cachedcan, GTC_MENUCACHE)); - //V_DrawRightAlignedThinString(x - 2, y, 0, skincolors[mapheaderinfo[mapnum]->cachedcan].name); + UINT16 col = gamedata->spraycans[mapheaderinfo[mapnum]->cache_spraycan].col; + + if (col < numskincolors) + { + V_DrawSmallMappedPatch(x, y, 0, W_CachePatchName("GOTCAN", PU_CACHE), + R_GetTranslationColormap(TC_RAINBOW, col, GTC_MENUCACHE)); + //V_DrawRightAlignedThinString(x - 2, y, 0, skincolors[col].name); + } x -= 8; } } diff --git a/src/m_cond.c b/src/m_cond.c index 554cba4a6..31b852c24 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -628,15 +628,22 @@ void M_ClearSecrets(void) memset(netUnlocked, 0, sizeof(netUnlocked)); memset(gamedata->achieved, 0, sizeof(gamedata->achieved)); - gamedata->allspraycansplaced = false; - memset(gamedata->spraycans, 0, sizeof(gamedata->spraycans)); + Z_Free(gamedata->spraycans); + gamedata->spraycans = NULL; + gamedata->numspraycans = 0; + gamedata->gotspraycans = 0; - INT32 i; + UINT16 i; for (i = 0; i < nummapheaders; i++) { if (!mapheaderinfo[i]) continue; - mapheaderinfo[i]->cachedcan = 0; + mapheaderinfo[i]->cache_spraycan = UINT16_MAX; + } + + for (i = 0; i < numskincolors; i++) + { + skincolors[i].cache_spraycan = UINT16_MAX; } Z_Free(gamedata->challengegrid); @@ -669,146 +676,100 @@ static void M_AssignSpraycans(void) // the release date of "Bomb Rush Cyberfunk". // ~toast 180823 (committed a day later) - if (gamedata->allspraycansplaced) + if (gamedata->numspraycans != 0) return; // Init ordered list of skincolors - UINT16 tempcanlist[MAXCANCOLORS]; - size_t listlen = 0; + UINT16 tempcanlist[MAXSKINCOLORS]; + UINT16 listlen = 0, prependlen = 0; - // Todo one of these should be a freebie - UINT16 prependlist[] = + UINT32 i, j; + conditionset_t *c; + condition_t *cn; + + const UINT16 prependoffset = MAXSKINCOLORS-1; + + // None of the following accounts for cans being removed, only added... + for (i = 0; i < MAXCONDITIONSETS; ++i) { - SKINCOLOR_RED, - SKINCOLOR_ORANGE, - SKINCOLOR_YELLOW, - SKINCOLOR_GREEN, - SKINCOLOR_BLUE, - SKINCOLOR_PURPLE, - 0 - }; - - UINT16 i; - - for (i = 0; prependlist[i]; i++) - { - if (gamedata->spraycans[prependlist[i]].map > 0 - && gamedata->spraycans[prependlist[i]].map <= nummapheaders) + c = &conditionSets[i]; + if (!c->numconditions) continue; - //CONS_Printf("DDD - Prepending %d\n", prependlist[i]); - - tempcanlist[listlen] = prependlist[i]; - gamedata->spraycans[prependlist[i]].got = 2; // invalid set to detect in below loop, rather than having to iterate over prependlist again - listlen++; - } - - size_t prepend = listlen; - - for (i = 1; i < MAXCANCOLORS; i++) - { - if (gamedata->spraycans[i].map > 0 - && gamedata->spraycans[i].map <= nummapheaders) - continue; - - if (gamedata->spraycans[i].got == 2) + for (j = 0; j < c->numconditions; ++j) { - // re-make valid, reject duplicating prepended - gamedata->spraycans[i].got = false; - continue; - } - - //CONS_Printf("DDD - Adding %d\n", i); - - tempcanlist[listlen] = i; - listlen++; - } - - if (!listlen) - goto cansdone; - - if (prepend > 0) - { - // Swap the prepend for random order - M_Shuffle_UINT16(tempcanlist, prepend); - } - - if (listlen > prepend) - { - // Swap everything else for random order - M_Shuffle_UINT16(tempcanlist + prepend, listlen - prepend); - } - - i = 0; - - cupheader_t *cup; - - UINT16 level; - - for (cup = kartcupheaders; cup; cup = cup->next) - { - UINT8 j; - for (j = 0; j < cup->numlevels; j++) - { - level = cup->cachedlevels[j]; - - if (level > nummapheaders) + cn = &c->condition[j]; + if (cn->type != UC_SPRAYCAN) continue; - if (mapheaderinfo[level]->cachedcan != 0) + // G_LoadGamedata, G_SaveGameData doesn't support custom skincolors right now. + if (cn->requirement >= SKINCOLOR_FIRSTFREESLOT) //numskincolors) continue; - gamedata->spraycans[tempcanlist[i]].map = level + 1; - mapheaderinfo[level]->cachedcan = tempcanlist[i]; - - if (++i < listlen) + if (skincolors[cn->requirement].cache_spraycan != UINT16_MAX) continue; - goto cansdone; + // Still invalid, just in case it isn't assigned one later + skincolors[cn->requirement].cache_spraycan = UINT16_MAX-1; + + if (!cn->extrainfo1) + { + //CONS_Printf("DDD - Adding standard can color %d\n", cn->requirement); + + tempcanlist[listlen] = cn->requirement; + listlen++; + continue; + } + + //CONS_Printf("DDD - Prepending early can color %d\n", cn->requirement); + + tempcanlist[prependoffset - prependlen] = cn->requirement; + prependlen++; } } - for (level = 0; level < nummapheaders; level++) + if (listlen) { - if (!mapheaderinfo[level] - || !(mapheaderinfo[level]->typeoflevel & TOL_RACE) - || mapheaderinfo[level]->cachedcan != 0) - continue; - - gamedata->spraycans[tempcanlist[i]].map = level + 1; - mapheaderinfo[level]->cachedcan = tempcanlist[i]; - - if (++i < listlen) - continue; - - goto cansdone; + // Swap the standard colours for random order + M_Shuffle_UINT16(tempcanlist, listlen); + } + else if (!prependlen) + { + return; } -cansdone: - -#ifdef PARANOIA - for (i = 1; i < MAXCANCOLORS; i++) + if (prependlen) { - if (gamedata->spraycans[i].map == 0) - I_Error("CANPROBLEM - BAD MAP FOR CAN %d\n", i); - if (gamedata->spraycans[i].map > nummapheaders) - I_Error("CANPROBLEM - TOO BIG MAP FOR CAN %d\n", i); - if (mapheaderinfo[gamedata->spraycans[i].map-1]->cachedcan != i) - I_Error("CANPROBLEM - MAP AND CAN DISAGREE FOR %d (%d)\n", i, mapheaderinfo[gamedata->spraycans[i].map-1]->cachedcan); + // Swap the early colours for random order + M_Shuffle_UINT16(tempcanlist + prependoffset - prependlen, prependlen); + + // Put at the front of the main list + // (technically reverses the prepend order, but it + // was LITERALLY just shuffled so it doesn't matter) + while (prependlen) + { + prependlen--; + tempcanlist[listlen] = tempcanlist[prependlen]; + tempcanlist[prependlen] = tempcanlist[prependoffset - prependlen]; + listlen++; + } } - for (i = 0; i < nummapheaders; i++) - { - if (!mapheaderinfo[i] || mapheaderinfo[i]->cachedcan == 0) - continue; - if (mapheaderinfo[i]->cachedcan > MAXCANCOLORS) - I_Error("MAPPROBLEM - BAD CAN FOR MAP %d\n", i); - if (gamedata->spraycans[mapheaderinfo[i]->cachedcan].map-1 != i) - I_Error("MAPPROBLEM - CAN AND MAP DISAGREE FOR %d (%d)\n", i, gamedata->spraycans[mapheaderinfo[i]->cachedcan].map-1); - } -#endif + gamedata->spraycans = Z_Realloc( + gamedata->spraycans, + sizeof(candata_t) * (gamedata->numspraycans + listlen), + PU_STATIC, + NULL); - gamedata->allspraycansplaced = true; + for (i = 0; i < listlen; i++) + { + gamedata->spraycans[gamedata->numspraycans].map = NEXTMAP_INVALID; + gamedata->spraycans[gamedata->numspraycans].col = tempcanlist[i]; + + skincolors[tempcanlist[i]].cache_spraycan = gamedata->numspraycans; + + gamedata->numspraycans++; + } } void M_FinaliseGameData(void) @@ -1062,10 +1023,15 @@ boolean M_CheckCondition(condition_t *cn, player_t *player) case UC_SPRAYCAN: { if (cn->requirement <= 0 - || cn->requirement >= MAXCANCOLORS) + || cn->requirement >= numskincolors) return false; - return gamedata->spraycans[cn->requirement].got; + UINT16 can_id = skincolors[cn->requirement].cache_spraycan; + + if (can_id >= gamedata->numspraycans) + return false; + + return (gamedata->spraycans[can_id].map < nummapheaders); } // Just for string building @@ -1522,20 +1488,24 @@ static const char *M_GetConditionString(condition_t *cn) case UC_SPRAYCAN: { if (cn->requirement <= 0 - || cn->requirement >= MAXCANCOLORS) + || cn->requirement >= numskincolors) return va("INVALID SPRAYCAN COLOR \"%d\"", cn->requirement); - INT32 checkLevel = gamedata->spraycans[cn->requirement].map - 1; + UINT16 can_id = skincolors[cn->requirement].cache_spraycan; - if (checkLevel < 0 || checkLevel >= nummapheaders || !mapheaderinfo[checkLevel]) - return va("INVALID SPRAYCAN MAP \"%d:%d\"", cn->requirement, checkLevel); + if (can_id >= gamedata->numspraycans) + return va("INVALID SPRAYCAN ID \"%d:%u\"", + cn->requirement, + skincolors[cn->requirement].cache_spraycan + ); - title = BUILDCONDITIONTITLE(checkLevel); + if (can_id == 0) + return "grab a Spray Can"; // Special case for the head of the list - work = va("%s: grab the Spray Can", title); + if (gamedata->spraycans[0].map >= nummapheaders) + return NULL; // Don't tease that there are many until you have one - Z_Free(title); - return work; + return va("grab %d Spray Cans", can_id + 1); } case UC_AND: diff --git a/src/m_cond.h b/src/m_cond.h index 09c850aa6..96cdf8c0d 100644 --- a/src/m_cond.h +++ b/src/m_cond.h @@ -255,8 +255,8 @@ typedef enum { struct candata_t { + UINT16 col; UINT16 map; - boolean got; }; // GAMEDATA STRUCTURE @@ -281,8 +281,9 @@ struct gamedata_t boolean unlockpending[MAXUNLOCKABLES]; // SPRAYCANS COLLECTED - boolean allspraycansplaced; - candata_t spraycans[MAXCANCOLORS]; + UINT16 numspraycans; + UINT16 gotspraycans; + candata_t* spraycans; // CHALLENGE GRID UINT16 challengegridwidth; diff --git a/src/p_inter.c b/src/p_inter.c index a3ef26de0..2b9542295 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -624,13 +624,6 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) case MT_SPRAYCAN: { - UINT16 col = mapheaderinfo[gamemap-1]->cachedcan; - - if (col == 0 || col > MAXCANCOLORS) - { - return; - } - if (demo.playback) { // Never collect emblems in replays. @@ -643,15 +636,41 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) return; } - if (P_IsLocalPlayer(player)) + if (!P_IsLocalPlayer(player)) { - if (!gamedata->spraycans[col].got) - { - gamedata->spraycans[col].got = true; - if (!M_UpdateUnlockablesAndExtraEmblems(true, true)) - S_StartSound(NULL, sfx_ncitem); - gamedata->deferredsave = true; - } + // Must be party. + return; + } + + UINT16 can_id = mapheaderinfo[gamemap-1]->cache_spraycan; + + if (can_id < gamedata->numspraycans) + { + // Assigned to this level, has been grabbed + return; + } + //else + { + // Unassigned, get the next grabbable colour + can_id = gamedata->gotspraycans; + } + + if (can_id >= gamedata->numspraycans) + { + // We've exhausted all the spraycans to grab. + return; + } + + if (gamedata->spraycans[can_id].map >= nummapheaders) + { + gamedata->spraycans[can_id].map = gamemap-1; + mapheaderinfo[gamemap-1]->cache_spraycan = can_id; + + gamedata->gotspraycans++; + + if (!M_UpdateUnlockablesAndExtraEmblems(true, true)) + S_StartSound(NULL, sfx_ncitem); + gamedata->deferredsave = true; } // Don't delete the object, just fade it. diff --git a/src/p_mobj.c b/src/p_mobj.c index a5ae4b881..d4823700c 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -12437,19 +12437,28 @@ static boolean P_SetupEmblem(mapthing_t *mthing, mobj_t *mobj) void P_SprayCanInit(mobj_t* mobj) { - UINT16 col = mapheaderinfo[gamemap-1]->cachedcan; + UINT16 can_id = mapheaderinfo[gamemap-1]->cache_spraycan; - if (col == 0 || col > MAXCANCOLORS) + if (can_id < gamedata->numspraycans) { - mobj->renderflags = RF_DONTDRAW; - return; + // Assigned to this level, has been grabbed + mobj->renderflags = (tr_trans50 << RF_TRANSSHIFT); + } + else + { + // Unassigned, get the next grabbable colour + can_id = gamedata->gotspraycans; + mobj->renderflags = 0; } - mobj->color = col; - - mobj->renderflags = (gamedata->spraycans[col].got) - ? (tr_trans50 << RF_TRANSSHIFT) - : 0; + if (can_id < gamedata->numspraycans) + { + mobj->color = gamedata->spraycans[can_id].col; + } + else + { + mobj->renderflags = RF_DONTDRAW; + } } static boolean P_SetupMace(mapthing_t *mthing, mobj_t *mobj) diff --git a/src/p_setup.c b/src/p_setup.c index 3cd7c5ef4..f5461fa35 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -460,7 +460,7 @@ static void P_ClearSingleMapHeaderInfo(INT16 num) mapheaderinfo[num]->justPlayed = 0; mapheaderinfo[num]->anger = 0; - mapheaderinfo[num]->cachedcan = 0; + mapheaderinfo[num]->cache_spraycan = UINT16_MAX; mapheaderinfo[num]->customopts = NULL; mapheaderinfo[num]->numCustomOptions = 0; @@ -816,17 +816,18 @@ static void P_SpawnMapThings(boolean spawnemblems) if (spawnemblems) { - if (nummapspraycans == 0) - { - UINT16 col = mapheaderinfo[gamemap-1]->cachedcan; + const UINT8 recommendedcans = +#ifdef DEVELOP + !(mapheaderinfo[gamemap-1]->typeoflevel & TOL_RACE) ? 0 : +#endif + 1; - if (col > 0 && col <= MAXCANCOLORS) - { - CONS_Alert(CONS_WARNING, "SPRAY CANS: Map has assigned Spray Cans but no pickup placed!\n"); - } - } - else if (nummapspraycans > 1) - CONS_Alert(CONS_ERROR, "SPRAY CANS: Map has too many Spray Cans (%d)!", numspraycans); + if (nummapspraycans > recommendedcans) + CONS_Alert(CONS_ERROR, "SPRAY CANS: Map has too many Spray Cans (%d)!", nummapspraycans); +#ifdef DEVELOP + else if (nummapspraycans != recommendedcans) + CONS_Alert(CONS_ERROR, "SPRAY CANS: Krew-made Race maps need a Spray Can placed!"); +#endif } } From 53549bfa2d3a87762752d29b471197866c4a35b8 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 23 Aug 2023 17:08:06 +0100 Subject: [PATCH 12/21] M_Shuffle_UINT16: Fix to not rule out half of all possible Spray Can orders --- src/m_cond.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/m_cond.c b/src/m_cond.c index 31b852c24..9335999ff 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -661,9 +661,14 @@ static void M_Shuffle_UINT16(UINT16 *list, size_t len) { size_t i; UINT16 temp; - while (--len > 1) // no need to swap on == + + while (len > 1) { i = M_RandomKey(len); + + if (i == --len) + continue; + temp = list[i]; list[i] = list[len]; list[len] = temp; From a3640110aee5ecb9468860865a99f2c7708e8bd4 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 23 Aug 2023 17:16:07 +0100 Subject: [PATCH 13/21] Only permit Spray Cans to be grabbed on base game levels I would not be so heavy handed against preventing players from grabbing Spray Cans on custom levels, but designing a system that permits unloaded headers to retain their cans is frankly overkill. There are plenty of other ways the same kind of level-scouring play can be experienced on custom levels. --- src/d_main.c | 5 +++-- src/dehacked.c | 3 +++ src/doomstat.h | 2 +- src/g_game.c | 1 + src/p_inter.c | 4 +++- src/p_mobj.c | 4 +++- src/p_setup.c | 8 ++++---- src/p_setup.h | 2 +- 8 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 9652f0d10..fd05bc3cd 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1514,7 +1514,8 @@ void D_SRB2Main(void) // // search for mainwad maps // - P_InitMapData(false); + P_InitMapData(); + basenummapheaders = nummapheaders; CON_SetLoadingProgress(LOADED_IWAD); @@ -1525,7 +1526,7 @@ void D_SRB2Main(void) // // search for pwad maps // - P_InitMapData(true); + P_InitMapData(); CON_SetLoadingProgress(LOADED_PWAD); diff --git a/src/dehacked.c b/src/dehacked.c index 6d44b87fb..66567fb05 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -605,7 +605,10 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile) } // end while if (gamedataadded) + { + basenummapheaders = nummapheaders; G_LoadGameData(); + } if (gamestate == GS_MENU || gamestate == GS_TITLESCREEN) { diff --git a/src/doomstat.h b/src/doomstat.h index 7d14f1d5a..26ea96cdb 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -551,7 +551,7 @@ struct mapheader_t #define LF2_FINISHNEEDED (1<<3) ///< Not available in Time Attack modes until you beat the level extern mapheader_t** mapheaderinfo; -extern INT32 nummapheaders, mapallocsize; +extern INT32 nummapheaders, basenummapheaders, mapallocsize; struct unloaded_mapheader_t { diff --git a/src/g_game.c b/src/g_game.c index 17d16b47a..36de12b56 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -193,6 +193,7 @@ quake_t *g_quakes = NULL; // Map Header Information mapheader_t** mapheaderinfo = {NULL}; INT32 nummapheaders = 0; +INT32 basenummapheaders = 0; INT32 mapallocsize = 0; unloaded_mapheader_t *unloadedmapheaders = NULL; diff --git a/src/p_inter.c b/src/p_inter.c index 2b9542295..0d99598dc 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -642,6 +642,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) return; } + // See also P_SprayCanInit UINT16 can_id = mapheaderinfo[gamemap-1]->cache_spraycan; if (can_id < gamedata->numspraycans) @@ -649,7 +650,8 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) // Assigned to this level, has been grabbed return; } - //else + // Prevent footguns - these won't persist when custom levels are unloaded + else if (gamemap-1 < basenummapheaders) { // Unassigned, get the next grabbable colour can_id = gamedata->gotspraycans; diff --git a/src/p_mobj.c b/src/p_mobj.c index d4823700c..76ae716a3 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -12437,6 +12437,7 @@ static boolean P_SetupEmblem(mapthing_t *mthing, mobj_t *mobj) void P_SprayCanInit(mobj_t* mobj) { + // See also P_TouchSpecialThing UINT16 can_id = mapheaderinfo[gamemap-1]->cache_spraycan; if (can_id < gamedata->numspraycans) @@ -12444,7 +12445,8 @@ void P_SprayCanInit(mobj_t* mobj) // Assigned to this level, has been grabbed mobj->renderflags = (tr_trans50 << RF_TRANSSHIFT); } - else + // Prevent footguns - these won't persist when custom levels are unloaded + else if (gamemap-1 < basenummapheaders) { // Unassigned, get the next grabbable colour can_id = gamedata->gotspraycans; diff --git a/src/p_setup.c b/src/p_setup.c index f5461fa35..f55c13b09 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -8564,7 +8564,7 @@ lumpnum_t wadnamelump = LUMPERROR; INT16 wadnamemap = 0; // gamemap based // Initialising map data (and catching replacements)... -UINT8 P_InitMapData(boolean existingmapheaders) +UINT8 P_InitMapData(void) { UINT8 ret = 0; INT32 i, j; @@ -8616,7 +8616,7 @@ UINT8 P_InitMapData(boolean existingmapheaders) if (maplump == LUMPERROR) { #ifndef DEVELOP - if (!existingmapheaders) + if (!basenummapheaders) { I_Error("P_InitMapData: Base map %s has a header but no level\n", name); } @@ -8633,7 +8633,7 @@ UINT8 P_InitMapData(boolean existingmapheaders) ret |= MAPRET_ADDED; CONS_Printf("%s\n", name); - if (existingmapheaders && mapheaderinfo[i]->lumpnum != LUMPERROR) + if (basenummapheaders && mapheaderinfo[i]->lumpnum != LUMPERROR) { G_SetGameModified(multiplayer, true); // oops, double-defined - no record attack privileges for you @@ -8950,7 +8950,7 @@ boolean P_MultiSetupWadFiles(boolean fullsetup) if (partadd_stage == 2) { - UINT8 mapsadded = P_InitMapData(true); + UINT8 mapsadded = P_InitMapData(); if (!mapsadded) CONS_Printf(M_GetText("No maps added\n")); diff --git a/src/p_setup.h b/src/p_setup.h index 1d474dd10..bcffd85b2 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -114,7 +114,7 @@ boolean P_AddWadFile(const char *wadfilename); #define MAPRET_ADDED (1) #define MAPRET_CURRENTREPLACED (1<<1) -UINT8 P_InitMapData(boolean existingmapheaders); +UINT8 P_InitMapData(void); extern lumpnum_t wadnamelump; extern INT16 wadnamemap; #define WADNAMECHECK(name) (!strncmp(name, "WADNAME", 7)) From 6d2e120e77dffb050cdff8e1241a8bd2091a4cc0 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 23 Aug 2023 17:54:09 +0100 Subject: [PATCH 14/21] M_DrawCharSelectCircle: Fix offset colour id when number of colors available is odd VS even --- src/k_menudraw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 3681aaeb0..23c989505 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -1299,7 +1299,7 @@ static void M_DrawCharSelectCircle(setup_player_t *p, INT16 x, INT16 y) if (i == 0) { - n = l = r = M_GetColorBefore(&p->colors, p->color, (numoptions/2) - 1); + n = l = r = M_GetColorBefore(&p->colors, p->color, (numoptions/2) - (numoptions & 1)); } else if (subtract) { @@ -1428,7 +1428,7 @@ static void M_DrawCharSelectCircle(setup_player_t *p, INT16 x, INT16 y) if (i == 0) { - n = l = r = M_GetColorBefore(&p->colors, p->followercolor, (numoptions/2) - 1); + n = l = r = M_GetColorBefore(&p->colors, p->followercolor, (numoptions/2) - (numoptions & 1)); } else if (subtract) { From e7dc2cda0c5bb982185b864c5d2be9f2044cb2ce Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 23 Aug 2023 17:59:01 +0100 Subject: [PATCH 15/21] d_netcmd.c: Fix default values for color cvars (and associated lastgoodcolor) to not error when we make basically all of the colours unlockables. --- src/d_netcmd.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 582f3d98d..b5a987635 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -287,12 +287,12 @@ consvar_t cv_playername[MAXSPLITSCREENPLAYERS] = { CVAR_INIT ("name4", "Knuckles", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Name4_OnChange) }; // player colors -UINT16 lastgoodcolor[MAXSPLITSCREENPLAYERS] = {SKINCOLOR_BLUE, SKINCOLOR_BLUE, SKINCOLOR_BLUE, SKINCOLOR_BLUE}; +UINT16 lastgoodcolor[MAXSPLITSCREENPLAYERS] = {SKINCOLOR_NONE, SKINCOLOR_NONE, SKINCOLOR_NONE, SKINCOLOR_NONE}; consvar_t cv_playercolor[MAXSPLITSCREENPLAYERS] = { - CVAR_INIT ("color", "Red", CV_SAVE|CV_CALL|CV_NOINIT, Color_cons_t, Color1_OnChange), - CVAR_INIT ("color2", "Orange", CV_SAVE|CV_CALL|CV_NOINIT, Color_cons_t, Color2_OnChange), - CVAR_INIT ("color3", "Blue", CV_SAVE|CV_CALL|CV_NOINIT, Color_cons_t, Color3_OnChange), - CVAR_INIT ("color4", "Red", CV_SAVE|CV_CALL|CV_NOINIT, Color_cons_t, Color4_OnChange) + CVAR_INIT ("color", "Default", CV_SAVE|CV_CALL|CV_NOINIT, Color_cons_t, Color1_OnChange), + CVAR_INIT ("color2", "Default", CV_SAVE|CV_CALL|CV_NOINIT, Color_cons_t, Color2_OnChange), + CVAR_INIT ("color3", "Default", CV_SAVE|CV_CALL|CV_NOINIT, Color_cons_t, Color3_OnChange), + CVAR_INIT ("color4", "Default", CV_SAVE|CV_CALL|CV_NOINIT, Color_cons_t, Color4_OnChange) }; // player's skin, saved for commodity, when using a favorite skins wad.. consvar_t cv_skin[MAXSPLITSCREENPLAYERS] = { @@ -1516,7 +1516,7 @@ static void SendNameAndColor(const UINT8 n) CV_StealthSetValue(&cv_playercolor[n], SKINCOLOR_NONE); } - sendColor = cv_playercolor[n].value; + lastgoodcolor[playernum] = sendColor = cv_playercolor[n].value; } // ditto for follower colour: From b0ee900422b43c28ab4213a74c8fec8e881765de Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 23 Aug 2023 18:24:45 +0100 Subject: [PATCH 16/21] d_netcmd.c: Fix errors with multiple _OnChange functions - Skin_OnChange - Now always checks for cheats for any machine-local player skin change in non-netgame, non-K_CanChangeRules contexts - Previously applied only to consoleplayer in Time Trial - Color_OnChange - Fixes straight up incorrect condition that prevented honest players from changing color mid-game via the developer console --- src/d_netcmd.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index b5a987635..80eea8703 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -6833,14 +6833,11 @@ static void Skin_OnChange(const UINT8 p) return; } - if (p == 0) + if (!CV_CheatsEnabled() && !(netgame || K_CanChangeRules(false)) + && (gamestate != GS_WAITINGPLAYERS)) // allows command line -warp x +skin y { - if (!CV_CheatsEnabled() && !(multiplayer || netgame) // In single player. - && (gamestate != GS_WAITINGPLAYERS)) // allows command line -warp x +skin y - { - CV_StealthSet(&cv_skin[p], skins[players[g_localplayers[p]].skin].name); - return; - } + CV_StealthSet(&cv_skin[p], skins[players[g_localplayers[p]].skin].name); + return; } if (CanChangeSkin(g_localplayers[p])) @@ -6890,7 +6887,7 @@ static void Color_OnChange(const UINT8 p) UINT16 color = cv_playercolor[p].value; boolean colorisgood = (color == SKINCOLOR_NONE || K_ColorUsable(color, false, true) == true); - if (Playing() && splitscreen < p) + if (Playing() && p <= splitscreen) { if (P_PlayerMoving(g_localplayers[p]) == true) { From b9a6f7362ba011baba8b65033565f85544ab9e79 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 23 Aug 2023 18:54:28 +0100 Subject: [PATCH 17/21] M_UpdateConditionSetsPending: Fix invalid character names returning the entire loop early --- src/m_cond.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/m_cond.c b/src/m_cond.c index 9335999ff..2b4aba4de 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -826,7 +826,7 @@ void M_UpdateConditionSetsPending(void) if (cn->requirement < 0) { CONS_Alert(CONS_WARNING, "UCRP_ISCHARACTER: Invalid character %s for condition ID %d", cn->stringvar, cn->id+1); - return; + continue; } Z_Free(cn->stringvar); From 595b3d67d53f24e524591f1928efdd827cf8da0e Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 23 Aug 2023 18:58:10 +0100 Subject: [PATCH 18/21] Add UC_CHARACTERWINS Just in case I don't get to do a major pass on adding a ton of extra unlockable conditions later, this is an easy, quick add featuring a stat gamedata and the statistics menu has been tracking for a while. --- src/deh_soc.c | 26 ++++++++++---------------- src/m_cond.c | 22 +++++++++++++++++++++- src/m_cond.h | 2 ++ 3 files changed, 33 insertions(+), 17 deletions(-) diff --git a/src/deh_soc.c b/src/deh_soc.c index 027ff2d7a..bdff40b1c 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -2542,6 +2542,14 @@ static void readcondition(UINT16 set, UINT32 id, char *word2) return; } } + else if (fastcmp(params[0], "CHARACTERWINS")) + { + PARAMCHECK(2); + ty = UC_CHARACTERWINS; + stringvar = Z_StrDup(params[1]); + re = -1; + x1 = atoi(params[2]); + } else if ((offset=0) || fastcmp(params[0], "ALLCHAOS") || (++offset && fastcmp(params[0], "ALLSUPER")) || (++offset && fastcmp(params[0], "ALLEMERALDS"))) @@ -2662,22 +2670,8 @@ static void readcondition(UINT16 set, UINT32 id, char *word2) { PARAMCHECK(1); ty = UCRP_ISCHARACTER; -#if 0 - { - re = R_SkinAvailable(params[1]); - - if (re < 0) - { - deh_warning("Invalid character %s for condition ID %d", params[1], id+1); - return; - } - } -#else - { - stringvar = Z_StrDup(params[1]); - re = -1; - } -#endif + stringvar = Z_StrDup(params[1]); + re = -1; } else if (fastcmp(params[0], "ISENGINECLASS")) { diff --git a/src/m_cond.c b/src/m_cond.c index 2b4aba4de..e0bf2d9cb 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -819,13 +819,14 @@ void M_UpdateConditionSetsPending(void) switch (cn->type) { + case UC_CHARACTERWINS: case UCRP_ISCHARACTER: { cn->requirement = R_SkinAvailable(cn->stringvar); if (cn->requirement < 0) { - CONS_Alert(CONS_WARNING, "UCRP_ISCHARACTER: Invalid character %s for condition ID %d", cn->stringvar, cn->id+1); + CONS_Alert(CONS_WARNING, "UC TYPE %u: Invalid character %s for condition ID %d", cn->type, cn->stringvar, cn->id+1); continue; } @@ -981,6 +982,12 @@ boolean M_CheckCondition(condition_t *cn, player_t *player) case UC_MAPTIME: // Requires time on map <= x return (G_GetBestTime(cn->extrainfo1) <= (unsigned)cn->requirement); + case UC_CHARACTERWINS: + if (cn->requirement < 0) + return false; + + return (skins[cn->requirement].records.wins >= (UINT32)cn->extrainfo1); + case UC_ALLCHAOS: case UC_ALLSUPER: case UC_ALLEMERALDS: @@ -1353,6 +1360,19 @@ static const char *M_GetConditionString(condition_t *cn) return work; } + case UC_CHARACTERWINS: + { + if (cn->requirement < 0 || !skins[cn->requirement].realname[0]) + return va("INVALID CHAR CONDITION \"%d:%d:%d\"", cn->type, cn->requirement, cn->extrainfo1); + work = (R_SkinUsable(-1, cn->requirement, false)) + ? skins[cn->requirement].realname + : "???"; + return va("win %d Round%s as %s", + cn->extrainfo1, + cn->extrainfo1 == 1 ? "" : "s", + work); + } + case UC_ALLCHAOS: case UC_ALLSUPER: case UC_ALLEMERALDS: diff --git a/src/m_cond.h b/src/m_cond.h index 96cdf8c0d..b330b942e 100644 --- a/src/m_cond.h +++ b/src/m_cond.h @@ -41,6 +41,8 @@ typedef enum UC_MAPSPBATTACK, // MAPSPBATTACK [map] UC_MAPTIME, // MAPTIME [map] [time to beat, tics] + UC_CHARACTERWINS, // CHARACTERWINS [character] [x rounds] + UC_ALLCHAOS, // ALLCHAOS [minimum difficulty] UC_ALLSUPER, // ALLSUPER [minimum difficulty] UC_ALLEMERALDS, // ALLEMERALDS [minimum difficulty] From 9076b3c99be085d93d1ee838cd69175e9c87c1d8 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 24 Aug 2023 01:16:14 +0100 Subject: [PATCH 19/21] Self-review: Correctly initialised gamedata spraycan map id in clear_Levels --- src/deh_soc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/deh_soc.c b/src/deh_soc.c index bdff40b1c..76488462e 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -220,7 +220,7 @@ void clear_levels(void) { UINT16 i; for (i = 0; i < gamedata->numspraycans; i++) - gamedata->spraycans[i].map = 0; + gamedata->spraycans[i].map = NEXTMAP_INVALID; } // Exit the current gamemap as a safeguard From 6d5770ff5a47eca0b48d6c38c73b5969b72a23d6 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 24 Aug 2023 21:32:41 +0100 Subject: [PATCH 20/21] M_AssignSpraycans: Fix off-by-one in shuffled prepended colours causing crashes The prepended colour list passed to M_Shuffle_UINT16 was off by one, leading to possible pollution of the region with an uninitialised value. For some reason, some people's machines guarantee clean stack memory on game startup, while other people's do not. This is why some people were crashing on Spray Can list generation and some weren't. The stack memory was DEFINITELY not clean by the time you could navigate to the gamedata clear menu, which is why that was crashing without fail. --- src/m_cond.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/m_cond.c b/src/m_cond.c index e0bf2d9cb..5d3e07a59 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -746,7 +746,7 @@ static void M_AssignSpraycans(void) if (prependlen) { // Swap the early colours for random order - M_Shuffle_UINT16(tempcanlist + prependoffset - prependlen, prependlen); + M_Shuffle_UINT16(tempcanlist + prependoffset - (prependlen - 1), prependlen); // Put at the front of the main list // (technically reverses the prepend order, but it From 29c39433669d99c6db9735602894deb9a2450c08 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 24 Aug 2023 21:38:17 +0100 Subject: [PATCH 21/21] M_AssignSpraycans: Forgot to remove an irrelevant check, now should update if new Spray Can conditions are added --- src/m_cond.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/m_cond.c b/src/m_cond.c index 5d3e07a59..eecc73ae6 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -681,9 +681,6 @@ static void M_AssignSpraycans(void) // the release date of "Bomb Rush Cyberfunk". // ~toast 180823 (committed a day later) - if (gamedata->numspraycans != 0) - return; - // Init ordered list of skincolors UINT16 tempcanlist[MAXSKINCOLORS]; UINT16 listlen = 0, prependlen = 0;