Merge branch SRB2:next into mobj-alpha

This commit is contained in:
MIDIMan 2024-05-03 14:36:17 +00:00
commit d626856ae2
20 changed files with 436 additions and 198 deletions

View file

@ -59,24 +59,19 @@ static inline int lib_freeslot(lua_State *L)
} }
else if (fastcmp(type, "SPR")) else if (fastcmp(type, "SPR"))
{ {
char wad;
spritenum_t j; spritenum_t j;
lua_getfield(L, LUA_REGISTRYINDEX, "WAD");
wad = (char)lua_tointeger(L, -1); if (strlen(word) > MAXSPRITENAME)
lua_pop(L, 1); return luaL_error(L, "Sprite name is longer than %d characters\n", MAXSPRITENAME);
for (j = SPR_FIRSTFREESLOT; j <= SPR_LASTFREESLOT; j++) for (j = SPR_FIRSTFREESLOT; j <= SPR_LASTFREESLOT; j++)
{ {
if (used_spr[(j-SPR_FIRSTFREESLOT)/8] & (1<<(j%8))) if (in_bit_array(used_spr, j - SPR_FIRSTFREESLOT))
{
if (!sprnames[j][4] && memcmp(sprnames[j],word,4)==0)
sprnames[j][4] = wad;
continue; // Already allocated, next. continue; // Already allocated, next.
}
// Found a free slot! // Found a free slot!
CONS_Printf("Sprite SPR_%s allocated.\n",word); CONS_Printf("Sprite SPR_%s allocated.\n",word);
strncpy(sprnames[j],word,4); strcpy(sprnames[j], word);
//sprnames[j][4] = 0; set_bit_array(used_spr, j - SPR_FIRSTFREESLOT); // Okay, this sprite slot has been named now.
used_spr[(j-SPR_FIRSTFREESLOT)/8] |= 1<<(j%8); // Okay, this sprite slot has been named now.
// Lua needs to update the value in _G if it exists // Lua needs to update the value in _G if it exists
LUA_UpdateSprName(word, j); LUA_UpdateSprName(word, j);
lua_pushinteger(L, j); lua_pushinteger(L, j);
@ -455,17 +450,19 @@ static int ScanConstants(lua_State *L, boolean mathlib, const char *word)
} }
else if (fastncmp("SPR_",word,4)) { else if (fastncmp("SPR_",word,4)) {
p = word+4; p = word+4;
for (i = 0; i < NUMSPRITES; i++) i = R_GetSpriteNumByName(p);
if (!sprnames[i][4] && fastncmp(p,sprnames[i],4)) { if (i != NUMSPRITES)
// updating overridden sprnames is not implemented for soc parser, {
// so don't use cache // updating overridden sprnames is not implemented for soc parser,
if (mathlib) // so don't use cache
lua_pushinteger(L, i); if (mathlib)
else lua_pushinteger(L, i);
CacheAndPushConstant(L, word, i); else
return 1; CacheAndPushConstant(L, word, i);
} return 1;
if (mathlib) return luaL_error(L, "sprite '%s' could not be found.\n", word); }
else if (mathlib)
return luaL_error(L, "sprite '%s' could not be found.\n", word);
return 0; return 0;
} }
else if (fastncmp("SPR2_",word,5)) { else if (fastncmp("SPR2_",word,5)) {
@ -738,18 +735,18 @@ static inline int lib_getenum(lua_State *L)
// If a sprname has been "cached" to _G, update it to a new value. // If a sprname has been "cached" to _G, update it to a new value.
void LUA_UpdateSprName(const char *name, lua_Integer value) void LUA_UpdateSprName(const char *name, lua_Integer value)
{ {
char fullname[9] = "SPR_XXXX"; char fullname[4 + MAXSPRITENAME + 1] = "SPR_";
if (!gL) if (!gL)
return; return;
strncpy(&fullname[4], name, 4); strcpy(&fullname[4], name);
lua_pushstring(gL, fullname); lua_pushstring(gL, fullname);
lua_rawget(gL, LUA_GLOBALSINDEX); lua_rawget(gL, LUA_GLOBALSINDEX);
if (!lua_isnil(gL, -1)) if (!lua_isnil(gL, -1))
{ {
lua_pushstring(gL, name); lua_pushstring(gL, fullname);
lua_pushinteger(gL, value); lua_pushinteger(gL, value);
lua_rawset(gL, LUA_GLOBALSINDEX); lua_rawset(gL, LUA_GLOBALSINDEX);
} }

View file

@ -405,7 +405,6 @@ void readfreeslots(MYFILE *f)
{ {
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
char *word,*type; char *word,*type;
char *tmp;
int i; int i;
do do
@ -415,10 +414,13 @@ void readfreeslots(MYFILE *f)
if (s[0] == '\n') if (s[0] == '\n')
break; break;
tmp = strchr(s, '#'); char *hashtag = strchr(s, '#');
if (tmp) char *space = strchr(s, ' ');
*tmp = '\0'; if (hashtag)
if (s == tmp) *hashtag = '\0';
if (space)
*space = '\0';
if (s == hashtag || s == space)
continue; // Skip comment lines, but don't break. continue; // Skip comment lines, but don't break.
type = strtok(s, "_"); type = strtok(s, "_");
@ -440,18 +442,16 @@ void readfreeslots(MYFILE *f)
S_AddSoundFx(word, false, 0, false); S_AddSoundFx(word, false, 0, false);
else if (fastcmp(type, "SPR")) else if (fastcmp(type, "SPR"))
{ {
if (strlen(word) > MAXSPRITENAME)
I_Error("Sprite name is longer than %d characters\n", MAXSPRITENAME);
for (i = SPR_FIRSTFREESLOT; i <= SPR_LASTFREESLOT; i++) for (i = SPR_FIRSTFREESLOT; i <= SPR_LASTFREESLOT; i++)
{ {
if (used_spr[(i-SPR_FIRSTFREESLOT)/8] & (1<<(i%8))) if (in_bit_array(used_spr, i - SPR_FIRSTFREESLOT))
{
if (!sprnames[i][4] && memcmp(sprnames[i],word,4)==0)
sprnames[i][4] = (char)f->wad;
continue; // Already allocated, next. continue; // Already allocated, next.
}
// Found a free slot! // Found a free slot!
strncpy(sprnames[i],word,4); strcpy(sprnames[i], word);
//sprnames[i][4] = 0; set_bit_array(used_spr, i - SPR_FIRSTFREESLOT); // Okay, this sprite slot has been named now.
used_spr[(i-SPR_FIRSTFREESLOT)/8] |= 1<<(i%8); // Okay, this sprite slot has been named now.
// Lua needs to update the value in _G if it exists // Lua needs to update the value in _G if it exists
LUA_UpdateSprName(word, i); LUA_UpdateSprName(word, i);
break; break;
@ -4182,9 +4182,9 @@ spritenum_t get_sprite(const char *word)
return atoi(word); return atoi(word);
if (fastncmp("SPR_",word,4)) if (fastncmp("SPR_",word,4))
word += 4; // take off the SPR_ word += 4; // take off the SPR_
for (i = 0; i < NUMSPRITES; i++) i = R_GetSpriteNumByName(word);
if (!sprnames[i][4] && memcmp(word,sprnames[i],4)==0) if (i != NUMSPRITES)
return i; return i;
deh_warning("Couldn't find sprite named 'SPR_%s'",word); deh_warning("Couldn't find sprite named 'SPR_%s'",word);
return SPR_NULL; return SPR_NULL;
} }

View file

@ -31,7 +31,7 @@
char *FREE_STATES[NUMSTATEFREESLOTS]; char *FREE_STATES[NUMSTATEFREESLOTS];
char *FREE_MOBJS[NUMMOBJFREESLOTS]; char *FREE_MOBJS[NUMMOBJFREESLOTS];
char *FREE_SKINCOLORS[NUMCOLORFREESLOTS]; char *FREE_SKINCOLORS[NUMCOLORFREESLOTS];
UINT8 used_spr[(NUMSPRITEFREESLOTS / 8) + 1]; // Bitwise flag for sprite freeslot in use! I would use ceil() here if I could, but it only saves 1 byte of memory anyway. bitarray_t used_spr[BIT_ARRAY_SIZE(NUMSPRITEFREESLOTS)]; // Sprite freeslots in use
const char NIGHTSGRADE_LIST[] = { const char NIGHTSGRADE_LIST[] = {
'F', // GRADE_F 'F', // GRADE_F

View file

@ -23,13 +23,13 @@
extern char *FREE_STATES[NUMSTATEFREESLOTS]; extern char *FREE_STATES[NUMSTATEFREESLOTS];
extern char *FREE_MOBJS[NUMMOBJFREESLOTS]; extern char *FREE_MOBJS[NUMMOBJFREESLOTS];
extern char *FREE_SKINCOLORS[NUMCOLORFREESLOTS]; extern char *FREE_SKINCOLORS[NUMCOLORFREESLOTS];
extern UINT8 used_spr[(NUMSPRITEFREESLOTS / 8) + 1]; // Bitwise flag for sprite freeslot in use! I would use ceil() here if I could, but it only saves 1 byte of memory anyway. extern bitarray_t used_spr[BIT_ARRAY_SIZE(NUMSPRITEFREESLOTS)]; // Sprite freeslots in use
#define initfreeslots() {\ #define initfreeslots() {\
memset(FREE_STATES,0,sizeof(char *) * NUMSTATEFREESLOTS);\ memset(FREE_STATES, 0, sizeof(FREE_STATES));\
memset(FREE_MOBJS,0,sizeof(char *) * NUMMOBJFREESLOTS);\ memset(FREE_MOBJS, 0, sizeof(FREE_MOBJS));\
memset(FREE_SKINCOLORS,0,sizeof(char *) * NUMCOLORFREESLOTS);\ memset(FREE_SKINCOLORS, 0, sizeof(FREE_SKINCOLORS));\
memset(used_spr,0,sizeof(UINT8) * ((NUMSPRITEFREESLOTS / 8) + 1));\ memset(used_spr, 0, sizeof(used_spr));\
memset(actionsoverridden, LUA_REFNIL, sizeof(actionsoverridden));\ memset(actionsoverridden, LUA_REFNIL, sizeof(actionsoverridden));\
} }

View file

@ -571,19 +571,15 @@ void HWR_LoadModels(void)
} }
// Add sprite models. // Add sprite models.
// Must be 4 characters long exactly. Otherwise, it's not a sprite name. for (i = 0; i < numsprites; i++)
if (len == 4)
{ {
for (i = 0; i < numsprites; i++) if (stricmp(name, sprnames[i]) == 0)
{ {
if (stricmp(name, sprnames[i]) == 0) md2_models[i].scale = scale;
{ md2_models[i].offset = offset;
md2_models[i].scale = scale; md2_models[i].found = true;
md2_models[i].offset = offset; strcpy(md2_models[i].filename, filename);
md2_models[i].found = true; goto modelfound;
strcpy(md2_models[i].filename, filename);
goto modelfound;
}
} }
} }

View file

@ -26,9 +26,10 @@
#include "hardware/hw_light.h" #include "hardware/hw_light.h"
#endif #endif
// Hey, moron! If you change this table, don't forget about the sprite enum in info.h and the sprite lights in hw_light.c! // Hey, moron! If you change this table, don't forget about the sprite enum in info.h and the sprite lights in hw_light.c!
// For the sake of constant merge conflicts, let's spread this out // For the sake of constant merge conflicts, let's spread this out
char sprnames[NUMSPRITES + 1][5] = char sprnames[NUMSPRITES + 1][MAXSPRITENAME + 1] =
{ {
"NULL", // invisible object "NULL", // invisible object
"UNKN", "UNKN",
@ -525,7 +526,7 @@ char sprnames[NUMSPRITES + 1][5] =
"GWLR", "GWLR",
}; };
char spr2names[NUMPLAYERSPRITES][5] = char spr2names[NUMPLAYERSPRITES][MAXSPRITENAME + 1] =
{ {
"STND", "STND",
"WAIT", "WAIT",

View file

@ -575,6 +575,7 @@ extern int actionsoverridden[NUMACTIONS][MAX_ACTION_RECURSION];
#define NUMMOBJFREESLOTS 1024 #define NUMMOBJFREESLOTS 1024
#define NUMSPRITEFREESLOTS NUMMOBJFREESLOTS #define NUMSPRITEFREESLOTS NUMMOBJFREESLOTS
#define NUMSTATEFREESLOTS (NUMMOBJFREESLOTS*8) #define NUMSTATEFREESLOTS (NUMMOBJFREESLOTS*8)
#define MAXSPRITENAME 64
// Hey, moron! If you change this table, don't forget about sprnames in info.c and the sprite lights in hw_light.c! // Hey, moron! If you change this table, don't forget about sprnames in info.c and the sprite lights in hw_light.c!
typedef enum sprite typedef enum sprite
@ -4383,8 +4384,8 @@ typedef struct
} state_t; } state_t;
extern state_t states[NUMSTATES]; extern state_t states[NUMSTATES];
extern char sprnames[NUMSPRITES + 1][5]; extern char sprnames[NUMSPRITES + 1][MAXSPRITENAME + 1];
extern char spr2names[NUMPLAYERSPRITES][5]; extern char spr2names[NUMPLAYERSPRITES][MAXSPRITENAME + 1];
extern playersprite_t spr2defaults[NUMPLAYERSPRITES]; extern playersprite_t spr2defaults[NUMPLAYERSPRITES];
extern state_t *astate; extern state_t *astate;
extern playersprite_t free_spr2; extern playersprite_t free_spr2;

View file

@ -3030,6 +3030,9 @@ static int lib_rFrame2Char(lua_State *L)
//HUDSAFE //HUDSAFE
c[0] = R_Frame2Char(ch); c[0] = R_Frame2Char(ch);
if (c[0] == '\xFF')
return luaL_error(L, "frame %u cannot be represented by a character", ch);
c[1] = 0; c[1] = 0;
lua_pushstring(L, c); lua_pushstring(L, c);

View file

@ -492,9 +492,7 @@ static int libd_getSpritePatch(lua_State *L)
else if (lua_isstring(L, 1)) // sprite prefix name given, e.g. "THOK" else if (lua_isstring(L, 1)) // sprite prefix name given, e.g. "THOK"
{ {
const char *name = lua_tostring(L, 1); const char *name = lua_tostring(L, 1);
for (i = 0; i < NUMSPRITES; i++) i = R_GetSpriteNumByName(name);
if (fastcmp(name, sprnames[i]))
break;
if (i >= NUMSPRITES) if (i >= NUMSPRITES)
return 0; return 0;
} }

View file

@ -88,12 +88,12 @@ static int lib_getSprname(lua_State *L)
else if (lua_isstring(L, 1)) else if (lua_isstring(L, 1))
{ {
const char *name = lua_tostring(L, 1); const char *name = lua_tostring(L, 1);
for (i = 0; i < NUMSPRITES; i++) i = R_GetSpriteNumByName(name);
if (fastcmp(name, sprnames[i])) if (i != NUMSPRITES)
{ {
lua_pushinteger(L, i); lua_pushinteger(L, i);
return 1; return 1;
} }
} }
return 0; return 0;
} }
@ -245,22 +245,15 @@ static int lib_getSpriteInfo(lua_State *L)
if (lua_isstring(L, 1)) if (lua_isstring(L, 1))
{ {
const char *name = lua_tostring(L, 1); const char *name = lua_tostring(L, 1);
INT32 spr; INT32 spr = R_GetSpriteNumByName(name);
for (spr = 0; spr < NUMSPRITES; spr++) if (spr == NUMSPRITES)
{
if (fastcmp(name, sprnames[spr]))
{
i = spr;
break;
}
}
if (i == NUMSPRITES)
{ {
char *check; char *check;
i = strtol(name, &check, 10); i = strtol(name, &check, 10);
if (check == name || *check != '\0') if (check == name || *check != '\0')
return luaL_error(L, "unknown sprite name %s", name); return luaL_error(L, "unknown sprite name %s", name);
} }
i = spr;
} }
else else
i = luaL_checkinteger(L, 1); i = luaL_checkinteger(L, 1);
@ -359,8 +352,8 @@ static int PopPivotTable(spriteinfo_t *info, lua_State *L, int stk)
default: default:
TYPEERROR("pivot frame", LUA_TNUMBER, lua_type(L, stk+1)); TYPEERROR("pivot frame", LUA_TNUMBER, lua_type(L, stk+1));
} }
if ((idx < 0) || (idx >= 64)) if ((idx < 0) || (idx >= MAXFRAMENUM))
return luaL_error(L, "pivot frame %d out of range (0 - %d)", idx, 63); return luaL_error(L, "pivot frame %d out of range (0 - %d)", idx, MAXFRAMENUM - 1);
// the values in pivot[] are also tables // the values in pivot[] are also tables
if (PopPivotSubTable(info->pivot, L, stk+2, idx)) if (PopPivotSubTable(info->pivot, L, stk+2, idx))
info->available = true; info->available = true;
@ -555,7 +548,7 @@ static int pivotlist_set(lua_State *L)
static int pivotlist_num(lua_State *L) static int pivotlist_num(lua_State *L)
{ {
lua_pushinteger(L, 64); lua_pushinteger(L, MAXFRAMENUM);
return 1; return 1;
} }

View file

@ -622,9 +622,6 @@ static inline boolean LUA_LoadFile(MYFILE *f, char *name)
if (!gL) // Lua needs to be initialized if (!gL) // Lua needs to be initialized
LUA_ClearState(); LUA_ClearState();
lua_pushinteger(gL, f->wad);
lua_setfield(gL, LUA_REGISTRYINDEX, "WAD");
lua_pushcfunction(gL, LUA_GetErrorMessage); lua_pushcfunction(gL, LUA_GetErrorMessage);
errorhandlerindex = lua_gettop(gL); errorhandlerindex = lua_gettop(gL);

View file

@ -35,7 +35,7 @@
#pragma interface #pragma interface
#endif #endif
/// \brief Frame flags: only the frame number - 0 to 256 (Frames from 0 to 63, Sprite2 number uses 0 to 127 plus FF_SPR2SUPER) /// \brief Frame flags: only the frame number - 0 to 256 (Frames from 0 to 255, Sprite2 number uses 0 to 127 plus FF_SPR2SUPER)
#define FF_FRAMEMASK 0xff #define FF_FRAMEMASK 0xff
/// \brief Frame flags - SPR2: Super sprite2 /// \brief Frame flags - SPR2: Super sprite2

View file

@ -976,6 +976,8 @@ typedef struct
#endif #endif
} spriteframe_t; } spriteframe_t;
#define MAXFRAMENUM 256
// //
// A sprite definition: a number of animation frames. // A sprite definition: a number of animation frames.
// //

View file

@ -1570,7 +1570,7 @@ static void R_ParseSpriteInfo(boolean spr2)
spriteinfo_t *info; spriteinfo_t *info;
char *sprinfoToken; char *sprinfoToken;
size_t sprinfoTokenLength; size_t sprinfoTokenLength;
char newSpriteName[5]; // no longer dynamically allocated char newSpriteName[MAXSPRITENAME + 1]; // no longer dynamically allocated
spritenum_t sprnum = NUMSPRITES; spritenum_t sprnum = NUMSPRITES;
playersprite_t spr2num = NUMPLAYERSPRITES; playersprite_t spr2num = NUMPLAYERSPRITES;
INT32 i; INT32 i;
@ -1584,31 +1584,17 @@ static void R_ParseSpriteInfo(boolean spr2)
I_Error("Error parsing SPRTINFO lump: Unexpected end of file where sprite name should be"); I_Error("Error parsing SPRTINFO lump: Unexpected end of file where sprite name should be");
} }
sprinfoTokenLength = strlen(sprinfoToken); sprinfoTokenLength = strlen(sprinfoToken);
if (sprinfoTokenLength != 4) if (sprinfoTokenLength > MAXSPRITENAME)
{ I_Error("Error parsing SPRTINFO lump: Sprite name \"%s\" is longer than %d characters", sprinfoToken, MAXSPRITENAME);
I_Error("Error parsing SPRTINFO lump: Sprite name \"%s\" isn't 4 characters long",sprinfoToken); strcpy(newSpriteName, sprinfoToken);
} strupr(newSpriteName); // Just do this now so we don't have to worry about it
else
{
memset(&newSpriteName, 0, 5);
M_Memcpy(newSpriteName, sprinfoToken, sprinfoTokenLength);
// ^^ we've confirmed that the token is == 4 characters so it will never overflow a 5 byte char buffer
strupr(newSpriteName); // Just do this now so we don't have to worry about it
}
Z_Free(sprinfoToken); Z_Free(sprinfoToken);
if (!spr2) if (!spr2)
{ {
for (i = 0; i <= NUMSPRITES; i++) sprnum = R_GetSpriteNumByName(newSpriteName);
{ if (sprnum == NUMSPRITES)
if (i == NUMSPRITES) I_Error("Error parsing SPRTINFO lump: Unknown sprite name \"%s\"", newSpriteName);
I_Error("Error parsing SPRTINFO lump: Unknown sprite name \"%s\"", newSpriteName);
if (!memcmp(newSpriteName,sprnames[i],4))
{
sprnum = i;
break;
}
}
} }
else else
{ {

View file

@ -100,7 +100,7 @@ typedef struct
typedef struct typedef struct
{ {
spriteframepivot_t pivot[64]; spriteframepivot_t pivot[MAXFRAMENUM];
boolean available; boolean available;
} spriteinfo_t; } spriteinfo_t;

View file

@ -625,7 +625,7 @@ static void R_LoadSkinSprites(UINT16 wadnum, UINT16 *lump, UINT16 *lastlump, ski
newlastlump++; newlastlump++;
// load all sprite sets we are aware of... for super! // load all sprite sets we are aware of... for super!
for (sprite2 = start_spr2; sprite2 < free_spr2; sprite2++) for (sprite2 = start_spr2; sprite2 < free_spr2; sprite2++)
R_AddSingleSpriteDef(spr2names[sprite2], &skin->super.sprites[sprite2], wadnum, newlastlump, *lastlump); R_AddSingleSpriteDef(spr2names[sprite2], &skin->super.sprites[sprite2], wadnum, newlastlump, *lastlump, false);
newlastlump--; newlastlump--;
*lastlump = newlastlump; // okay, make the normal sprite set loading end there *lastlump = newlastlump; // okay, make the normal sprite set loading end there
@ -633,7 +633,7 @@ static void R_LoadSkinSprites(UINT16 wadnum, UINT16 *lump, UINT16 *lastlump, ski
// load all sprite sets we are aware of... for normal stuff. // load all sprite sets we are aware of... for normal stuff.
for (sprite2 = start_spr2; sprite2 < free_spr2; sprite2++) for (sprite2 = start_spr2; sprite2 < free_spr2; sprite2++)
R_AddSingleSpriteDef(spr2names[sprite2], &skin->sprites[sprite2], wadnum, *lump, *lastlump); R_AddSingleSpriteDef(spr2names[sprite2], &skin->sprites[sprite2], wadnum, *lump, *lastlump, false);
if (skin->sprites[0].numframes == 0) if (skin->sprites[0].numframes == 0)
CONS_Alert(CONS_ERROR, M_GetText("No frames found for sprite SPR2_%s\n"), spr2names[0]); CONS_Alert(CONS_ERROR, M_GetText("No frames found for sprite SPR2_%s\n"), spr2names[0]);

View file

@ -77,7 +77,7 @@ spriteinfo_t spriteinfo[NUMSPRITES];
spritedef_t *sprites; spritedef_t *sprites;
size_t numsprites; size_t numsprites;
static spriteframe_t sprtemp[64]; static spriteframe_t sprtemp[MAXFRAMENUM];
static size_t maxframe; static size_t maxframe;
static const char *spritename; static const char *spritename;
@ -116,6 +116,14 @@ static INT32 drawsegs_xrange_count = 0;
// //
// ========================================================================== // ==========================================================================
spritenum_t R_GetSpriteNumByName(const char *name)
{
for (spritenum_t i = 0; i < NUMSPRITES; i++)
if (!strcmp(name, sprnames[i]))
return i;
return NUMSPRITES;
}
// //
// //
// //
@ -128,10 +136,14 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch
{ {
char cn = R_Frame2Char(frame), cr = R_Rotation2Char(rotation); // for debugging char cn = R_Frame2Char(frame), cr = R_Rotation2Char(rotation); // for debugging
char framedescription[256];
if (cn != '\xFF')
sprintf(framedescription, "%s frame %d (%c)", spritename, frame, cn);
else
sprintf(framedescription, "%s frame %d", spritename, frame);
INT32 r; INT32 r;
lumpnum_t lumppat = wad; lumpnum_t lumppat = (wad << 16) + lump;
lumppat <<= 16;
lumppat += lump;
if (maxframe ==(size_t)-1 || frame > maxframe) if (maxframe ==(size_t)-1 || frame > maxframe)
maxframe = frame; maxframe = frame;
@ -147,9 +159,9 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch
{ {
// the lump should be used for all rotations // the lump should be used for all rotations
if (sprtemp[frame].rotate == SRF_SINGLE) if (sprtemp[frame].rotate == SRF_SINGLE)
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has multiple rot = 0 lump\n", spritename, cn); CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s has multiple rot = 0 lump\n", framedescription);
else if (sprtemp[frame].rotate != SRF_NONE) // Let's bundle 1-8/16 and L/R rotations into one debug message. else if (sprtemp[frame].rotate != SRF_NONE) // Let's bundle 1-8/16 and L/R rotations into one debug message.
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has rotations and a rot = 0 lump\n", spritename, cn); CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s has rotations and a rot = 0 lump\n", framedescription);
sprtemp[frame].rotate = SRF_SINGLE; sprtemp[frame].rotate = SRF_SINGLE;
for (r = 0; r < 16; r++) for (r = 0; r < 16; r++)
@ -169,15 +181,15 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch
if (sprtemp[frame].rotate == SRF_NONE) if (sprtemp[frame].rotate == SRF_NONE)
sprtemp[frame].rotate = SRF_SINGLE; sprtemp[frame].rotate = SRF_SINGLE;
else if (sprtemp[frame].rotate == SRF_SINGLE) else if (sprtemp[frame].rotate == SRF_SINGLE)
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has L/R rotations and a rot = 0 lump\n", spritename, cn); CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s has L/R rotations and a rot = 0 lump\n", framedescription);
else if (sprtemp[frame].rotate == SRF_3D) else if (sprtemp[frame].rotate == SRF_3D)
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has both L/R and 1-8 rotations\n", spritename, cn); CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s has both L/R and 1-8 rotations\n", framedescription);
else if (sprtemp[frame].rotate == SRF_3DGE) else if (sprtemp[frame].rotate == SRF_3DGE)
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has both L/R and 1-G rotations\n", spritename, cn); CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s has both L/R and 1-G rotations\n", framedescription);
else if ((sprtemp[frame].rotate & SRF_LEFT) && (rotation == ROT_L)) else if ((sprtemp[frame].rotate & SRF_LEFT) && (rotation == ROT_L))
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has multiple L rotations\n", spritename, cn); CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s has multiple L rotations\n", framedescription);
else if ((sprtemp[frame].rotate & SRF_RIGHT) && (rotation == ROT_R)) else if ((sprtemp[frame].rotate & SRF_RIGHT) && (rotation == ROT_R))
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has multiple R rotations\n", spritename, cn); CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s has multiple R rotations\n", framedescription);
sprtemp[frame].rotate |= ((rotation == ROT_R) ? SRF_RIGHT : SRF_LEFT); sprtemp[frame].rotate |= ((rotation == ROT_R) ? SRF_RIGHT : SRF_LEFT);
if ((sprtemp[frame].rotate & SRF_2D) == SRF_2D) if ((sprtemp[frame].rotate & SRF_2D) == SRF_2D)
@ -204,9 +216,9 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch
if (sprtemp[frame].rotate == SRF_NONE) if (sprtemp[frame].rotate == SRF_NONE)
sprtemp[frame].rotate = SRF_SINGLE; sprtemp[frame].rotate = SRF_SINGLE;
else if (sprtemp[frame].rotate == SRF_SINGLE) else if (sprtemp[frame].rotate == SRF_SINGLE)
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has 1-8/G rotations and a rot = 0 lump\n", spritename, cn); CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s has 1-8/G rotations and a rot = 0 lump\n", framedescription);
else if (sprtemp[frame].rotate & SRF_2D) else if (sprtemp[frame].rotate & SRF_2D)
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has both L/R and 1-8/G rotations\n", spritename, cn); CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s has both L/R and 1-8/G rotations\n", framedescription);
// make 0 based // make 0 based
rotation--; rotation--;
@ -226,7 +238,12 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch
} }
if (sprtemp[frame].lumppat[rotation] != LUMPERROR) if (sprtemp[frame].lumppat[rotation] != LUMPERROR)
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s: %c%c has two lumps mapped to it\n", spritename, cn, cr); {
if (cn != '\xFF')
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s: %d_%c (%c%c) has two lumps mapped to it\n", spritename, frame, cr, cn, cr);
else
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s: %d_%c has two lumps mapped to it\n", spritename, frame, cr);
}
// lumppat & lumpid are the same for original Doom, but different // lumppat & lumpid are the same for original Doom, but different
// when using sprites in pwad : the lumppat points the new graphics // when using sprites in pwad : the lumppat points the new graphics
@ -238,24 +255,201 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch
sprtemp[frame].flip &= ~(1<<rotation); sprtemp[frame].flip &= ~(1<<rotation);
} }
static boolean GetFramesAndRotationsFromShortLumpName(
const char *name,
INT32 *ret_frame,
UINT8 *ret_rotation,
INT32 *ret_frame2,
UINT8 *ret_rotation2
)
{
size_t namelen = strlen(name);
if (namelen != 6 && namelen != 8)
return false;
*ret_frame = R_Char2Frame(name[4]);
*ret_rotation = R_Char2Rotation(name[5]);
if (*ret_frame >= 64 || *ret_rotation == 255)
return false;
if (namelen == 8)
{
*ret_frame2 = R_Char2Frame(name[6]);
*ret_rotation2 = R_Char2Rotation(name[7]);
if (*ret_frame2 >= 64 || *ret_rotation2 == 255)
return false;
}
else
{
*ret_frame2 = -1;
*ret_rotation2 = 255;
}
return true;
}
static boolean GetSingleFrameAndRotation(
const char *name,
size_t len,
INT32 *ret_frame,
UINT8 *ret_rotation
)
{
const char *underscore = strchr(name, '_');
// Found but past the part of the name we are parsing
if ((size_t)(underscore - name) >= len)
underscore = NULL;
size_t framelen = underscore ? (size_t)(underscore - name) : len;
if (framelen < 1 || framelen > 4)
return false;
char framepart[4 + 1]; // Max 9999
strlcpy(framepart, name, framelen + 1);
for (size_t i = 0; i < framelen; i++)
if (!isdigit(framepart[i]))
return false;
*ret_frame = atoi(framepart);
*ret_rotation = underscore ? R_Char2Rotation(*(underscore + 1)) : 0;
if (*ret_frame >= MAXFRAMENUM || *ret_rotation == 255)
return false;
return true;
}
static boolean GetFramesAndRotationsFromLongLumpName(
const char *name,
INT32 *ret_frame,
UINT8 *ret_rotation,
INT32 *ret_frame2,
UINT8 *ret_rotation2
)
{
const char *plus = strchr(name, '+');
if (plus)
{
size_t len1 = plus - name;
if (!GetSingleFrameAndRotation(name, len1, ret_frame, ret_rotation))
return false;
if (!GetSingleFrameAndRotation(plus + 1, strlen(name) - len1 - 1, ret_frame2, ret_rotation2))
return false;
}
else
{
if (!GetSingleFrameAndRotation(name, strlen(name), ret_frame, ret_rotation))
return false;
*ret_frame2 = -1;
*ret_rotation2 = 255;
}
return true;
}
static UINT8 GetOppositeRotation(UINT8 rotation, UINT8 flags)
{
if (flags & ~SRF_3DMASK)
I_Error("GetOppositeRotation: rotation type not supported");
UINT8 numrotations = (flags == SRF_3D) ? 8 : 16;
return (rotation == 1) ? 1 : numrotations + 2 - rotation;
}
static void MirrorMissingRotations(void)
{
for (UINT32 framenum = 0; framenum < maxframe; framenum++)
{
spriteframe_t *frame = &sprtemp[framenum];
if (frame->rotate == SRF_NONE || !(frame->rotate & SRF_3DMASK))
continue;
UINT8 numrotations = frame->rotate == SRF_3D ? 8 : 16;
for (UINT8 rotation = 1; rotation <= numrotations; rotation++)
{
if (frame->lumppat[rotation - 1] != LUMPERROR)
continue;
UINT8 baserotation = GetOppositeRotation(rotation, frame->rotate);
UINT32 lumpnum = frame->lumppat[baserotation - 1];
R_InstallSpriteLump(WADFILENUM(lumpnum), LUMPNUM(lumpnum), frame->lumpid[baserotation], framenum, rotation, 1);
}
}
}
// Some checks to help development
static void CheckFrame(const char *sprname)
{
for (UINT32 frame = 0; frame < maxframe; frame++)
{
spriteframe_t *spriteframe = &sprtemp[frame];
char framedescription[256];
if (frame < 64)
sprintf(framedescription, "%s frame %d (%c)", sprname, frame, R_Frame2Char(frame));
else
sprintf(framedescription, "%s frame %d", sprname, frame);
switch (spriteframe->rotate)
{
case SRF_NONE:
// no rotations were found for that frame at all
I_Error("R_AddSingleSpriteDef: No patches found for %s", framedescription);
break;
case SRF_SINGLE:
// only the first rotation is needed
break;
case SRF_2D: // both Left and Right rotations
// we test to see whether the left and right slots are present
if ((spriteframe->lumppat[2] == LUMPERROR) || (spriteframe->lumppat[6] == LUMPERROR))
I_Error("R_AddSingleSpriteDef: Sprite %s is missing rotations (L-R mode)",
framedescription);
break;
default:
{
// must have all 8/16 frames
UINT8 rotation = ((spriteframe->rotate & SRF_3DGE) ? 16 : 8);
while (rotation--)
{
// we test the patch lump, or the id lump whatever
// if it was not loaded the two are LUMPERROR
if (spriteframe->lumppat[rotation] == LUMPERROR)
I_Error("R_AddSingleSpriteDef: Sprite %s is missing rotations (1-%c mode)",
framedescription, ((spriteframe->rotate & SRF_3DGE) ? 'G' : '8'));
}
}
break;
}
}
}
// Install a single sprite, given its identifying name (4 chars) // Install a single sprite, given its identifying name (4 chars)
// //
// (originally part of R_AddSpriteDefs) // (originally part of R_AddSpriteDefs)
// //
// Pass: name of sprite : 4 chars // Pass: name of sprite
// spritedef_t // spritedef_t
// wadnum : wad number, indexes wadfiles[], where patches // wadnum : wad number, indexes wadfiles[], where patches
// for frames are found // for frames are found
// startlump : first lump to search for sprite frames // startlump : first lump to search for sprite frames
// endlump : AFTER the last lump to search // endlump : AFTER the last lump to search
// longname : whether to use long sprite names or 4-char names
// //
// Returns true if the sprite was succesfully added // Returns true if the sprite was succesfully added
// //
boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 wadnum, UINT16 startlump, UINT16 endlump) boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 wadnum, UINT16 startlump, UINT16 endlump, boolean longname)
{ {
UINT16 l; UINT16 l;
UINT8 frame;
UINT8 rotation;
lumpinfo_t *lumpinfo; lumpinfo_t *lumpinfo;
UINT16 numadded = 0; UINT16 numadded = 0;
@ -282,15 +476,23 @@ boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16
for (l = startlump; l < endlump; l++) for (l = startlump; l < endlump; l++)
{ {
if (memcmp(lumpinfo[l].name,sprname,4)==0) if (longname && W_IsLumpFolder(wadnum, l))
I_Error("R_AddSingleSpriteDef: all frame lumps for a sprite should be contained inside a single folder\n");
// For long sprites, the startlump-endlump range only includes
// relevant lumps, so no check needed in that case
if (longname || (strlen(sprname) == 4 && !memcmp(lumpinfo[l].name, sprname, 4)))
{ {
INT16 width, height; INT16 width, height;
INT16 topoffset, leftoffset; INT16 topoffset, leftoffset;
INT32 frame, frame2;
UINT8 rotation, rotation2;
frame = R_Char2Frame(lumpinfo[l].name[4]); boolean good = longname ?
rotation = R_Char2Rotation(lumpinfo[l].name[5]); GetFramesAndRotationsFromLongLumpName(lumpinfo[l].longname, &frame, &rotation, &frame2, &rotation2) :
GetFramesAndRotationsFromShortLumpName(lumpinfo[l].name, &frame, &rotation, &frame2, &rotation2);
if (frame >= 64 || rotation == 255) // Give an actual NAME error -_-... if (!good) // Give an actual NAME error -_-...
{ {
CONS_Alert(CONS_WARNING, M_GetText("Bad sprite name: %s\n"), W_CheckNameForNumPwad(wadnum,l)); CONS_Alert(CONS_WARNING, M_GetText("Bad sprite name: %s\n"), W_CheckNameForNumPwad(wadnum,l));
continue; continue;
@ -322,19 +524,8 @@ boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16
//---------------------------------------------------- //----------------------------------------------------
R_InstallSpriteLump(wadnum, l, numspritelumps, frame, rotation, 0); R_InstallSpriteLump(wadnum, l, numspritelumps, frame, rotation, 0);
if (frame2 != -1)
if (lumpinfo[l].name[6]) R_InstallSpriteLump(wadnum, l, numspritelumps, frame2, rotation2, 1);
{
frame = R_Char2Frame(lumpinfo[l].name[6]);
rotation = R_Char2Rotation(lumpinfo[l].name[7]);
if (frame >= 64 || rotation == 255) // Give an actual NAME error -_-...
{
CONS_Alert(CONS_WARNING, M_GetText("Bad sprite name: %s\n"), W_CheckNameForNumPwad(wadnum,l));
continue;
}
R_InstallSpriteLump(wadnum, l, numspritelumps, frame, rotation, 1);
}
if (++numspritelumps >= max_spritelumps) if (++numspritelumps >= max_spritelumps)
{ {
@ -374,41 +565,10 @@ boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16
maxframe++; maxframe++;
// if (longname)
// some checks to help development MirrorMissingRotations();
//
for (frame = 0; frame < maxframe; frame++)
{
switch (sprtemp[frame].rotate)
{
case SRF_NONE:
// no rotations were found for that frame at all
I_Error("R_AddSingleSpriteDef: No patches found for %.4s frame %c", sprname, R_Frame2Char(frame));
break;
case SRF_SINGLE: CheckFrame(sprname);
// only the first rotation is needed
break;
case SRF_2D: // both Left and Right rotations
// we test to see whether the left and right slots are present
if ((sprtemp[frame].lumppat[2] == LUMPERROR) || (sprtemp[frame].lumppat[6] == LUMPERROR))
I_Error("R_AddSingleSpriteDef: Sprite %.4s frame %c is missing rotations (L-R mode)",
sprname, R_Frame2Char(frame));
break;
default:
// must have all 8/16 frames
rotation = ((sprtemp[frame].rotate & SRF_3DGE) ? 16 : 8);
while (rotation--)
// we test the patch lump, or the id lump whatever
// if it was not loaded the two are LUMPERROR
if (sprtemp[frame].lumppat[rotation] == LUMPERROR)
I_Error("R_AddSingleSpriteDef: Sprite %.4s frame %c is missing rotations (1-%c mode)",
sprname, R_Frame2Char(frame), ((sprtemp[frame].rotate & SRF_3DGE) ? 'G' : '8'));
break;
}
}
// allocate space for the frames present and copy sprtemp to it // allocate space for the frames present and copy sprtemp to it
if (spritedef->numframes && // has been allocated if (spritedef->numframes && // has been allocated
@ -429,14 +589,10 @@ boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16
return true; return true;
} }
// static void AddShortSpriteDefs(UINT16 wadnum, size_t *ptr_spritesadded, size_t *ptr_framesadded)
// Search for sprites replacements in a wad whose names are in namelist
//
void R_AddSpriteDefs(UINT16 wadnum)
{ {
size_t i, addsprites = 0; size_t i;
UINT16 start, end; UINT16 start, end;
char wadname[MAX_WADPATH];
// Find the sprites section in this resource file. // Find the sprites section in this resource file.
switch (wadfiles[wadnum]->type) switch (wadfiles[wadnum]->type)
@ -474,27 +630,90 @@ void R_AddSpriteDefs(UINT16 wadnum)
return; return;
} }
// //
// scan through lumps, for each sprite, find all the sprite frames // scan through lumps, for each sprite, find all the sprite frames
// //
for (i = 0; i < numsprites; i++) for (i = 0; i < numsprites; i++)
{ {
if (sprnames[i][4] && wadnum >= (UINT16)sprnames[i][4]) if (R_AddSingleSpriteDef(sprnames[i], &sprites[i], wadnum, start, end, false))
continue;
if (R_AddSingleSpriteDef(sprnames[i], &sprites[i], wadnum, start, end))
{ {
// if a new sprite was added (not just replaced) // if a new sprite was added (not just replaced)
addsprites++; (*ptr_spritesadded)++;
#ifndef ZDEBUG #ifndef ZDEBUG
CONS_Debug(DBG_SETUP, "sprite %s set in pwad %d\n", sprnames[i], wadnum); CONS_Debug(DBG_SETUP, "sprite %s set in pwad %d\n", sprnames[i], wadnum);
#endif #endif
} }
} }
nameonly(strcpy(wadname, wadfiles[wadnum]->filename)); *ptr_framesadded += end - start;
CONS_Printf(M_GetText("%s added %d frames in %s sprites\n"), wadname, end-start, sizeu1(addsprites)); }
static void AddLongSpriteDefs(UINT16 wadnum, size_t *ptr_spritesadded, size_t *ptr_framesadded)
{
if (!W_FileHasFolders(wadfiles[wadnum]))
return;
UINT16 start = W_CheckNumForFolderStartPK3("LongSprites/", wadnum, 0);
UINT16 end = W_CheckNumForFolderEndPK3("LongSprites/", wadnum, start);
if (start == INT16_MAX || end == INT16_MAX || start >= end)
return;
size_t lumpnum = start;
while (lumpnum < end)
{
if (W_IsLumpFolder(wadnum, lumpnum))
{
lumpnum++;
continue;
}
UINT16 folderstart, folderend;
char *folderpath = W_GetLumpFolderPathPK3(wadnum, lumpnum);
folderstart = lumpnum;
folderend = W_CheckNumForFolderEndPK3(folderpath, wadnum, lumpnum);
Z_Free(folderpath);
spritenum_t sprnum;
char *sprname = W_GetLumpFolderNamePK3(wadnum, lumpnum);
strupr(sprname);
sprnum = R_GetSpriteNumByName(sprname);
if (sprnum != NUMSPRITES && R_AddSingleSpriteDef(sprname, &sprites[sprnum], wadnum, folderstart, folderend, true))
{
// A new sprite was added (not just replaced)
(*ptr_spritesadded)++;
#ifndef ZDEBUG
CONS_Debug(DBG_SETUP, "long sprite %s set in pwad %d\n", sprname, wadnum);
#endif
}
Z_Free(sprname);
lumpnum = folderend;
}
*ptr_framesadded += end - start;
}
//
// Search for sprites replacements in a wad whose names are in namelist
//
void R_AddSpriteDefs(UINT16 wadnum)
{
char wadname[MAX_WADPATH];
size_t spritesadded = 0;
size_t framesadded = 0;
AddShortSpriteDefs(wadnum, &spritesadded, &framesadded);
AddLongSpriteDefs(wadnum, &spritesadded, &framesadded);
if (spritesadded || framesadded)
{
nameonly(strcpy(wadname, wadfiles[wadnum]->filename));
CONS_Printf(M_GetText("%s added %s frames in %s sprites\n"), wadname, sizeu1(framesadded), sizeu2(spritesadded));
}
} }
// //

View file

@ -27,7 +27,9 @@
#define FEETADJUST (4<<FRACBITS) // R_AddSingleSpriteDef #define FEETADJUST (4<<FRACBITS) // R_AddSingleSpriteDef
boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 wadnum, UINT16 startlump, UINT16 endlump); spritenum_t R_GetSpriteNumByName(const char *name);
boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 wadnum, UINT16 startlump, UINT16 endlump, boolean longname);
//faB: find sprites in wadfile, replace existing, add new ones //faB: find sprites in wadfile, replace existing, add new ones
// (only sprites from namelist are added or replaced) // (only sprites from namelist are added or replaced)

View file

@ -1349,6 +1349,47 @@ UINT16 W_CheckNumForFolderEndPK3(const char *name, UINT16 wad, UINT16 startlump)
return i; return i;
} }
char *W_GetLumpFolderPathPK3(UINT16 wad, UINT16 lump)
{
const char *fullname = wadfiles[wad]->lumpinfo[lump].fullname;
const char *slash = strrchr(fullname, '/');
INT32 pathlen = slash ? slash - fullname : 0;
char *path = Z_Calloc(pathlen + 1, PU_STATIC, NULL);
strncpy(path, fullname, pathlen);
return path;
}
char *W_GetLumpFolderNamePK3(UINT16 wad, UINT16 lump)
{
const char *fullname = wadfiles[wad]->lumpinfo[lump].fullname;
size_t start, end;
INT32 i = strlen(fullname);
i--;
while (i >= 0 && fullname[i] != '/')
i--;
if (i < 0)
return NULL;
end = i;
i--;
while (i >= 0 && fullname[i] != '/')
i--;
if (i < 0)
return NULL;
start = i + 1;
size_t namelen = end - start;
char *foldername = Z_Calloc(namelen + 1, PU_STATIC, NULL);
strncpy(foldername, fullname + start, namelen);
return foldername;
}
void W_GetFolderLumpsPwad(const char *name, UINT16 wad, UINT32 **list, UINT16 *list_capacity, UINT16 *numlumps) void W_GetFolderLumpsPwad(const char *name, UINT16 wad, UINT32 **list, UINT16 *list_capacity, UINT16 *numlumps)
{ {
size_t name_length = strlen(name); size_t name_length = strlen(name);

View file

@ -180,6 +180,8 @@ UINT16 W_CheckNumForMarkerStartPwad(const char *name, UINT16 wad, UINT16 startlu
UINT16 W_CheckNumForFullNamePK3(const char *name, UINT16 wad, UINT16 startlump); UINT16 W_CheckNumForFullNamePK3(const char *name, UINT16 wad, UINT16 startlump);
UINT16 W_CheckNumForFolderStartPK3(const char *name, UINT16 wad, UINT16 startlump); UINT16 W_CheckNumForFolderStartPK3(const char *name, UINT16 wad, UINT16 startlump);
UINT16 W_CheckNumForFolderEndPK3(const char *name, UINT16 wad, UINT16 startlump); UINT16 W_CheckNumForFolderEndPK3(const char *name, UINT16 wad, UINT16 startlump);
char *W_GetLumpFolderPathPK3(UINT16 wad, UINT16 lump);
char *W_GetLumpFolderNamePK3(UINT16 wad, UINT16 lump);
void W_GetFolderLumpsPwad(const char *name, UINT16 wad, UINT32 **list, UINT16 *list_capacity, UINT16 *numlumps); void W_GetFolderLumpsPwad(const char *name, UINT16 wad, UINT32 **list, UINT16 *list_capacity, UINT16 *numlumps);
void W_GetFolderLumps(const char *name, UINT32 **list, UINT16 *list_capacity, UINT16 *numlumps); void W_GetFolderLumps(const char *name, UINT32 **list, UINT16 *list_capacity, UINT16 *numlumps);