From f7b166da07d821c655cc804111d419ab3c14c694 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 27 Feb 2022 07:56:45 -0500 Subject: [PATCH] Refresh sprite2s Allows for custom characters to be loaded first, then a wad that adds a custom sprite2, and the custom character's sprite2s won't be discarded. --- src/deh_lua.c | 3 + src/deh_soc.c | 2 + src/r_skins.c | 156 ++++++++++++++++++++++++++++++++++++++++++++++++-- src/r_skins.h | 2 + 4 files changed, 158 insertions(+), 5 deletions(-) diff --git a/src/deh_lua.c b/src/deh_lua.c index a2ffca95b..7984a38c8 100644 --- a/src/deh_lua.c +++ b/src/deh_lua.c @@ -188,6 +188,9 @@ static inline int lib_freeslot(lua_State *L) lua_remove(L, 1); continue; } + + R_RefreshSprite2(); + return r; } diff --git a/src/deh_soc.c b/src/deh_soc.c index 3a611f3ba..dd33594ea 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -513,6 +513,8 @@ void readfreeslots(MYFILE *f) } while (!myfeof(f)); // finish when the line is empty Z_Free(s); + + R_RefreshSprite2(); } void readthing(MYFILE *f, INT32 num) diff --git a/src/r_skins.c b/src/r_skins.c index 86c0bbc54..010280403 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -499,7 +499,7 @@ static UINT16 W_CheckForPatchSkinMarkerInPwad(UINT16 wadid, UINT16 startlump) return INT16_MAX; // not found } -static void R_LoadSkinSprites(UINT16 wadnum, UINT16 *lump, UINT16 *lastlump, skin_t *skin) +static void R_LoadSkinSprites(UINT16 wadnum, UINT16 *lump, UINT16 *lastlump, skin_t *skin, UINT8 start_spr2) { UINT16 newlastlump; UINT8 sprite2; @@ -521,7 +521,7 @@ static void R_LoadSkinSprites(UINT16 wadnum, UINT16 *lump, UINT16 *lastlump, ski { newlastlump++; // load all sprite sets we are aware of... for super! - for (sprite2 = 0; sprite2 < free_spr2; sprite2++) + for (sprite2 = start_spr2; sprite2 < free_spr2; sprite2++) R_AddSingleSpriteDef(spr2names[sprite2], &skin->sprites[FF_SPR2SUPER|sprite2], wadnum, newlastlump, *lastlump); newlastlump--; @@ -529,7 +529,7 @@ static void R_LoadSkinSprites(UINT16 wadnum, UINT16 *lump, UINT16 *lastlump, ski } // load all sprite sets we are aware of... for normal stuff. - for (sprite2 = 0; sprite2 < free_spr2; sprite2++) + for (sprite2 = start_spr2; sprite2 < free_spr2; sprite2++) R_AddSingleSpriteDef(spr2names[sprite2], &skin->sprites[sprite2], wadnum, *lump, *lastlump); if (skin->sprites[0].numframes == 0) @@ -795,7 +795,7 @@ next_token: free(buf2); // Add sprites - R_LoadSkinSprites(wadnum, &lump, &lastlump, skin); + R_LoadSkinSprites(wadnum, &lump, &lastlump, skin, 0); //ST_LoadFaceGraphics(numskins); -- nah let's do this elsewhere R_FlushTranslationColormapCache(); @@ -928,7 +928,7 @@ next_token: } // Patch sprites - R_LoadSkinSprites(wadnum, &lump, &lastlump, skin); + R_LoadSkinSprites(wadnum, &lump, &lastlump, skin, 0); //ST_LoadFaceGraphics(skinnum); -- nah let's do this elsewhere R_FlushTranslationColormapCache(); @@ -941,3 +941,149 @@ next_token: #undef HUDNAMEWRITE #undef SYMBOLCONVERT + +static UINT16 W_CheckForEitherSkinMarkerInPwad(UINT16 wadid, UINT16 startlump) +{ + UINT16 i; + const char *S_SKIN = "S_SKIN"; + const char *P_SKIN = "P_SKIN"; + lumpinfo_t *lump_p; + + // scan forward, start at + if (startlump < wadfiles[wadid]->numlumps) + { + lump_p = wadfiles[wadid]->lumpinfo + startlump; + for (i = startlump; i < wadfiles[wadid]->numlumps; i++, lump_p++) + if (memcmp(lump_p->name,S_SKIN,6)==0 || memcmp(lump_p->name,P_SKIN,6)==0) + return i; + } + return INT16_MAX; // not found +} + +static void R_RefreshSprite2ForWad(UINT16 wadnum, UINT8 start_spr2) +{ + UINT16 lump, lastlump = 0; + char *buf; + char *buf2; + char *stoken; + char *value; + size_t size; + skin_t *skin; + boolean noskincomplain; + + // + // search for all skin patch markers in pwad + // + + while ((lump = W_CheckForEitherSkinMarkerInPwad(wadnum, lastlump)) != INT16_MAX) + { + INT32 skinnum = 0; + + // advance by default + lastlump = lump + 1; + + buf = W_CacheLumpNumPwad(wadnum, lump, PU_CACHE); + size = W_LumpLengthPwad(wadnum, lump); + + // for strtok + buf2 = malloc(size+1); + if (!buf2) + I_Error("R_RefreshSprite2ForWad: No more free memory\n"); + M_Memcpy(buf2,buf,size); + buf2[size] = '\0'; + + skin = NULL; + noskincomplain = false; + + /* + Parse. Has more phases than the parser in R_AddSkins because it needs to have the patching name first (no default skin name is acceptible for patching, unlike skin creation) + */ + + stoken = strtok(buf2, "\r\n= "); + while (stoken) + { + if ((stoken[0] == '/' && stoken[1] == '/') + || (stoken[0] == '#'))// skip comments + { + stoken = strtok(NULL, "\r\n"); // skip end of line + goto next_token; // find the real next token + } + + value = strtok(NULL, "\r\n= "); + + if (!value) + I_Error("R_RefreshSprite2ForWad: syntax error in P_SKIN lump# %d(%s) in WAD %s\n", lump, W_CheckNameForNumPwad(wadnum,lump), wadfiles[wadnum]->filename); + + if (!stricmp(stoken, "name")) + { + strlwr(value); + skinnum = R_SkinAvailable(value); + if (skinnum != -1) + skin = &skins[skinnum]; + else + { + CONS_Debug(DBG_SETUP, "R_RefreshSprite2ForWad: unknown skin name in P_SKIN lump# %d(%s) in WAD %s\n", lump, W_CheckNameForNumPwad(wadnum,lump), wadfiles[wadnum]->filename); + noskincomplain = true; + } + } + + if (!skin) + break; + +next_token: + stoken = strtok(NULL, "\r\n= "); + } + free(buf2); + + if (!skin) // Didn't include a name parameter? What a waste. + { + if (!noskincomplain) + CONS_Debug(DBG_SETUP, "R_RefreshSprite2ForWad: no skin name given in P_SKIN lump #%d (WAD %s)\n", lump, wadfiles[wadnum]->filename); + continue; + } + + // Update sprites, in the range of (start_spr2 - free_spr2-1) + R_LoadSkinSprites(wadnum, &lump, &lastlump, skin, start_spr2); + //R_FlushTranslationColormapCache(); // I don't think this is needed for what we're doing? + } +} + +static playersprite_t old_spr2 = SPR2_FIRSTFREESLOT; +void R_RefreshSprite2(void) +{ + // Sprite2s being defined by custom wads can create situations where + // a custom character might want to add support, but due to load order, + // might not be defined in time. + + // The trick where you load characters then level packs to keep savedata + // in particular will practically garantuee a level pack can NEVER add custom animations, + // because custom character's Sprite2s will not be added. + + // So, go through every file, and reload the sprite2s that were added. + + INT32 i; + + if (old_spr2 > free_spr2) + { +#ifdef PARANOIA + I_Error("R_RefreshSprite2: old_spr2 is too high?! (old_spr2: %d, free_spr2: %d)\n", old_spr2, free_spr2); +#else + // Just silently fix + old_spr2 = free_spr2; +#endif + } + + if (old_spr2 == free_spr2) + { + // No sprite2s were added since the last time we did freeslots. + return; + } + + for (i = 0; i < numwadfiles; i++) + { + R_RefreshSprite2ForWad(i, old_spr2); + } + + // Update previous value. + old_spr2 = free_spr2; +} diff --git a/src/r_skins.h b/src/r_skins.h index a38997f4d..2ef1bdd65 100644 --- a/src/r_skins.h +++ b/src/r_skins.h @@ -100,4 +100,6 @@ void R_PatchSkins(UINT16 wadnum, boolean mainfile); UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player); +void R_RefreshSprite2(void); + #endif //__R_SKINS__