Merge branch 'more-sprite2' into 'next'

Add 'sprite2' field to states

See merge request STJr/SRB2!2211
This commit is contained in:
sphere 2024-03-07 12:06:48 +00:00
commit ee96ed12a4
24 changed files with 3048 additions and 2817 deletions

View file

@ -5096,6 +5096,10 @@ struct int_const_s const INT_CONST[] = {
{"RF_SHADOWEFFECTS",RF_SHADOWEFFECTS},
{"RF_DROPSHADOW",RF_DROPSHADOW},
// Animation flags
{"SPR2F_MASK",SPR2F_MASK},
{"SPR2F_SUPER",SPR2F_SUPER},
// Level flags
{"LF_SCRIPTISFILE",LF_SCRIPTISFILE},
{"LF_SPEEDMUSIC",LF_SPEEDMUSIC},

View file

@ -3530,7 +3530,7 @@ void F_TitleDemoTicker(void)
// ==========
static skin_t *contskins[2];
static UINT8 cont_spr2[2][6];
static UINT16 cont_spr2[2][6];
static UINT8 *contcolormaps[2];
void F_StartContinue(void)

View file

@ -413,7 +413,7 @@ void G_WriteGhostTic(mobj_t *ghost)
{
oldghost.sprite2 = ghost->sprite2;
ziptic |= GZT_SPR2;
WRITEUINT8(demo_p,oldghost.sprite2);
WRITEUINT16(demo_p,oldghost.sprite2);
}
// Check for sprite set changes
@ -513,7 +513,7 @@ void G_WriteGhostTic(mobj_t *ghost)
temp = ghost->player->followmobj->z-ghost->z;
WRITEFIXED(demo_p,temp);
if (followtic & FZT_SKIN)
WRITEUINT8(demo_p,ghost->player->followmobj->sprite2);
WRITEUINT16(demo_p,ghost->player->followmobj->sprite2);
WRITEUINT16(demo_p,ghost->player->followmobj->sprite);
WRITEUINT8(demo_p,(ghost->player->followmobj->frame & FF_FRAMEMASK));
WRITEUINT16(demo_p,ghost->player->followmobj->color);
@ -575,7 +575,7 @@ void G_ConsGhostTic(void)
if (ziptic & GZT_FRAME)
demo_p++;
if (ziptic & GZT_SPR2)
demo_p++;
demo_p += (demoversion < 0x0011) ? sizeof(UINT8) : sizeof(UINT16);
if (ziptic & GZT_EXTRA)
{ // But wait, there's more!
@ -644,7 +644,7 @@ void G_ConsGhostTic(void)
// momx, momy and momz
demo_p += (demoversion < 0x000e) ? sizeof(INT16) * 3 : sizeof(fixed_t) * 3;
if (followtic & FZT_SKIN)
demo_p++;
demo_p += (demoversion < 0x0011) ? sizeof(UINT8) : sizeof(UINT16);
demo_p += sizeof(UINT16);
demo_p++;
demo_p += (demoversion==0x000c) ? 1 : sizeof(UINT16);
@ -726,7 +726,7 @@ void G_GhostTicker(void)
if (ziptic & GZT_FRAME)
g->oldmo.frame = READUINT8(g->p);
if (ziptic & GZT_SPR2)
g->oldmo.sprite2 = READUINT8(g->p);
g->oldmo.sprite2 = (g->version < 0x0011) ? READUINT8(g->p) : READUINT16(g->p);
// Update ghost
P_UnsetThingPosition(g->mo);
@ -941,7 +941,7 @@ void G_GhostTicker(void)
follow->z = g->mo->z + temp;
P_SetThingPosition(follow);
if (followtic & FZT_SKIN)
follow->sprite2 = READUINT8(g->p);
follow->sprite2 = (g->version < 0x0011) ? READUINT8(g->p) : READUINT16(g->p);
else
follow->sprite2 = 0;
follow->sprite = READUINT16(g->p);
@ -1056,7 +1056,7 @@ void G_ReadMetalTic(mobj_t *metal)
oldmetal.frame = G_ConvertOldFrameFlags(oldmetal.frame);
}
if (ziptic & GZT_SPR2)
oldmetal.sprite2 = READUINT8(metal_p);
oldmetal.sprite2 = (metalversion < 0x0011) ? READUINT8(metal_p) : READUINT16(metal_p);
// Set movement, position, and angle
// oldmetal contains where you're supposed to be.
@ -1199,7 +1199,7 @@ void G_ReadMetalTic(mobj_t *metal)
follow->z = metal->z + temp;
P_SetThingPosition(follow);
if (followtic & FZT_SKIN)
follow->sprite2 = READUINT8(metal_p);
follow->sprite2 = (metalversion < 0x0011) ? READUINT8(metal_p) : READUINT16(metal_p);
else
follow->sprite2 = 0;
follow->sprite = READUINT16(metal_p);
@ -1207,7 +1207,7 @@ void G_ReadMetalTic(mobj_t *metal)
if (metalversion < 0x000f)
follow->frame = G_ConvertOldFrameFlags(follow->frame);
follow->angle = metal->angle;
follow->color = (metalversion==0x000c) ? READUINT8(metal_p) : READUINT16(metal_p);
follow->color = (metalversion == 0x000c) ? READUINT8(metal_p) : READUINT16(metal_p);
if (!(followtic & FZT_SPAWNED))
{
@ -1308,7 +1308,7 @@ void G_WriteMetalTic(mobj_t *metal)
{
oldmetal.sprite2 = metal->sprite2;
ziptic |= GZT_SPR2;
WRITEUINT8(demo_p,oldmetal.sprite2);
WRITEUINT16(demo_p,oldmetal.sprite2);
}
// Check for sprite set changes
@ -1383,7 +1383,7 @@ void G_WriteMetalTic(mobj_t *metal)
temp = metal->player->followmobj->z-metal->z;
WRITEFIXED(demo_p,temp);
if (followtic & FZT_SKIN)
WRITEUINT8(demo_p,metal->player->followmobj->sprite2);
WRITEUINT16(demo_p,metal->player->followmobj->sprite2);
WRITEUINT16(demo_p,metal->player->followmobj->sprite);
WRITEUINT32(demo_p,metal->player->followmobj->frame); // NOT & FF_FRAMEMASK here, so 32 bits
WRITEUINT16(demo_p,metal->player->followmobj->color);
@ -2607,10 +2607,10 @@ void G_AddGhost(char *defdemoname)
}
gh->oldmo.color = gh->mo->color;
gh->mo->state = states+S_PLAY_STND;
gh->mo->state = &states[S_PLAY_STND];
gh->mo->sprite = gh->mo->state->sprite;
gh->mo->sprite2 = (gh->mo->state->frame & FF_FRAMEMASK);
//gh->mo->frame = tr_trans30<<FF_TRANSSHIFT;
gh->mo->sprite2 = P_GetStateSprite2(gh->mo->state);
gh->mo->frame = (gh->mo->state->frame & ~FF_FRAMEMASK) | P_GetSprite2StateFrame(gh->mo->state);
gh->mo->flags2 |= MF2_DONTDRAW;
gh->fadein = (9-3)*6; // fade from invisible to trans30 over as close to 35 tics as possible
gh->mo->tics = -1;

View file

@ -4364,9 +4364,9 @@ static void HWR_ProjectSprite(mobj_t *thing)
//Fab : 02-08-98: 'skin' override spritedef currently used for skin
if (thing->skin && thing->sprite == SPR_PLAY)
{
sprdef = &((skin_t *)thing->skin)->sprites[thing->sprite2];
sprdef = P_GetSkinSpritedef(thing->skin, thing->sprite2);
#ifdef ROTSPRITE
sprinfo = &((skin_t *)thing->skin)->sprinfo[thing->sprite2];
sprinfo = P_GetSkinSpriteInfo(thing->skin, thing->sprite2);
#endif
}
else

View file

@ -1078,30 +1078,47 @@ static boolean HWR_CanInterpolateSprite2(modelspr2frames_t *spr2frame)
return spr2frame->interpolate;
}
//
// HWR_GetModelSprite2 (see P_GetSkinSprite2)
// For non-super players, tries each sprite2's immediate predecessor until it finds one with a number of frames or ends up at standing.
// For super players, does the same as above - but tries the super equivalent for each sprite2 before the non-super version.
//
static UINT8 HWR_GetModelSprite2(md2_t *md2, skin_t *skin, UINT8 spr2, player_t *player)
static modelspr2frames_t *HWR_GetModelSprite2Frames(md2_t *md2, UINT16 spr2)
{
UINT8 super = 0, i = 0;
if (!md2 || !md2->model)
return NULL;
if (!md2 || !md2->model || !md2->model->spr2frames || !skin)
return 0;
boolean is_super = spr2 & SPR2F_SUPER;
if ((playersprite_t)(spr2 & ~FF_SPR2SUPER) >= free_spr2)
return 0;
spr2 &= SPR2F_MASK;
while (!md2->model->spr2frames[spr2].numframes
&& spr2 != SPR2_STND
&& ++i != 32) // recursion limiter
if (spr2 >= free_spr2)
return NULL;
if (is_super)
{
if (spr2 & FF_SPR2SUPER)
modelspr2frames_t *frames = md2->model->superspr2frames;
if (frames && md2->model->superspr2frames[spr2].numframes)
return &md2->model->superspr2frames[spr2];
}
if (md2->model->spr2frames)
return &md2->model->spr2frames[spr2];
return NULL;
}
static modelspr2frames_t *HWR_GetModelSprite2(md2_t *md2, skin_t *skin, UINT16 spr2, player_t *player)
{
UINT16 super = 0;
UINT8 i = 0;
if (!md2 || !md2->model || !skin)
return HWR_GetModelSprite2Frames(md2, 0);
while (!HWR_GetModelSprite2Frames(md2, spr2)
&& spr2 != SPR2_STND
&& ++i < 32) // recursion limiter
{
if (spr2 & SPR2F_SUPER)
{
super = FF_SPR2SUPER;
spr2 &= ~FF_SPR2SUPER;
super = SPR2F_SUPER;
spr2 &= ~SPR2F_SUPER;
continue;
}
@ -1130,9 +1147,9 @@ static UINT8 HWR_GetModelSprite2(md2_t *md2, skin_t *skin, UINT8 spr2, player_t
}
if (i >= 32) // probably an infinite loop...
return 0;
spr2 = 0;
return spr2;
return HWR_GetModelSprite2Frames(md2, spr2);
}
// Adjust texture coords of model to fit into a patch's max_s and max_t
@ -1188,7 +1205,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
char filename[64];
INT32 frame = 0;
INT32 nextFrame = -1;
UINT8 spr2 = 0;
modelspr2frames_t *spr2frames = NULL;
FTransform p;
FSurfaceInfo Surf;
@ -1418,18 +1435,24 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
tics = (float)spr->mobj->anim_duration;
}
if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY)
sprdef = P_GetSkinSpritedef(spr->mobj->skin, spr->mobj->sprite2);
else
sprdef = &sprites[spr->mobj->sprite];
frame = (spr->mobj->frame & FF_FRAMEMASK);
if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY && md2->model->spr2frames)
if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY)
spr2frames = HWR_GetModelSprite2(md2, spr->mobj->skin, spr->mobj->sprite2, spr->mobj->player);
if (spr2frames)
{
spr2 = HWR_GetModelSprite2(md2, spr->mobj->skin, spr->mobj->sprite2, spr->mobj->player);
mod = md2->model->spr2frames[spr2].numframes;
mod = spr2frames->numframes;
#ifndef DONTHIDEDIFFANIMLENGTH // by default, different anim length is masked by the mod
if (mod > (INT32)((skin_t *)spr->mobj->skin)->sprites[spr2].numframes)
mod = ((skin_t *)spr->mobj->skin)->sprites[spr2].numframes;
if (mod > (INT32)sprdef->numframes)
mod = sprdef->numframes;
#endif
if (!mod)
mod = 1;
frame = md2->model->spr2frames[spr2].frames[frame%mod];
frame = spr2frames->frames[frame % mod];
}
else
{
@ -1449,13 +1472,18 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
if (durs > INTERPOLERATION_LIMIT)
durs = INTERPOLERATION_LIMIT;
if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY && md2->model->spr2frames)
if (spr2frames)
{
if (HWR_CanInterpolateSprite2(&md2->model->spr2frames[spr2])
UINT16 next_spr2 = P_GetStateSprite2(&states[spr->mobj->state->nextstate]);
// Add or remove SPR2F_SUPER based on certain conditions
next_spr2 = P_ApplySuperFlagToSprite2(next_spr2, spr->mobj);
if (HWR_CanInterpolateSprite2(spr2frames)
&& (spr->mobj->frame & FF_ANIMATE
|| (spr->mobj->state->nextstate != S_NULL
&& states[spr->mobj->state->nextstate].sprite == SPR_PLAY
&& ((P_GetSkinSprite2(spr->mobj->skin, (((spr->mobj->player && spr->mobj->player->powers[pw_super]) ? FF_SPR2SUPER : 0)|states[spr->mobj->state->nextstate].frame) & FF_FRAMEMASK, spr->mobj->player) == spr->mobj->sprite2)))))
&& ((P_GetSkinSprite2(spr->mobj->skin, next_spr2, spr->mobj->player) == spr->mobj->sprite2)))))
{
nextFrame = (spr->mobj->frame & FF_FRAMEMASK) + 1;
if (nextFrame >= mod)
@ -1466,7 +1494,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
nextFrame = 0;
}
if (frame || !(spr->mobj->state->frame & FF_SPR2ENDSTATE))
nextFrame = md2->model->spr2frames[spr2].frames[nextFrame];
nextFrame = spr2frames->frames[nextFrame];
else
nextFrame = -1;
}
@ -1502,11 +1530,6 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
else
p.z = FIXED_TO_FLOAT(interp.z);
if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY)
sprdef = &((skin_t *)spr->mobj->skin)->sprites[spr->mobj->sprite2];
else
sprdef = &sprites[spr->mobj->sprite];
sprframe = &sprdef->spriteframes[spr->mobj->frame & FF_FRAMEMASK];
if (sprframe->rotate || papersprite)

View file

@ -292,6 +292,7 @@ void LoadModelSprite2(model_t *model)
{
INT32 i;
modelspr2frames_t *spr2frames = NULL;
modelspr2frames_t *superspr2frames = NULL;
INT32 numframes = model->meshes[0].numFrames;
char *framename = model->frameNames;
@ -335,25 +336,33 @@ void LoadModelSprite2(model_t *model)
spr2idx = 0;
while (spr2idx < free_spr2)
{
modelspr2frames_t *frames = NULL;
if (!memcmp(spr2names[spr2idx], name, 4))
{
if (!spr2frames)
spr2frames = (modelspr2frames_t*)Z_Calloc(sizeof(modelspr2frames_t)*NUMPLAYERSPRITES*2, PU_STATIC, NULL);
spr2frames = (modelspr2frames_t*)Z_Calloc(sizeof(modelspr2frames_t)*NUMPLAYERSPRITES, PU_STATIC, NULL);
frames = spr2frames;
if (super)
spr2idx |= FF_SPR2SUPER;
{
if (!superspr2frames)
superspr2frames = (modelspr2frames_t*)Z_Calloc(sizeof(modelspr2frames_t)*NUMPLAYERSPRITES, PU_STATIC, NULL);
frames = superspr2frames;
}
if (framechars[0])
{
frame = atoi(framechars);
if (spr2frames[spr2idx].numframes < frame+1)
spr2frames[spr2idx].numframes = frame+1;
if (frames[spr2idx].numframes < frame+1)
frames[spr2idx].numframes = frame+1;
}
else
{
frame = spr2frames[spr2idx].numframes;
spr2frames[spr2idx].numframes++;
frame = frames[spr2idx].numframes;
frames[spr2idx].numframes++;
}
spr2frames[spr2idx].frames[frame] = i;
spr2frames[spr2idx].interpolate = interpolate;
frames[spr2idx].frames[frame] = i;
frames[spr2idx].interpolate = interpolate;
break;
}
spr2idx++;
@ -366,7 +375,10 @@ void LoadModelSprite2(model_t *model)
if (model->spr2frames)
Z_Free(model->spr2frames);
if (model->superspr2frames)
Z_Free(model->superspr2frames);
model->spr2frames = spr2frames;
model->superspr2frames = superspr2frames;
}
//

View file

@ -101,6 +101,7 @@ typedef struct model_s
char *frameNames;
boolean interpolate[256];
modelspr2frames_t *spr2frames;
modelspr2frames_t *superspr2frames;
// the max_s and max_t values that the uvs are currently adjusted to
// (if a sprite is used as a texture)

5290
src/info.c

File diff suppressed because it is too large Load diff

View file

@ -1078,9 +1078,6 @@ typedef enum sprite
NUMSPRITES
} spritenum_t;
// Make sure to be conscious of FF_FRAMEMASK and the fact sprite2 is stored as a UINT8 whenever you change this table.
// Currently, FF_FRAMEMASK is 0xff, or 255 - but the second half is used by FF_SPR2SUPER, so the limitation is 0x7f.
// Since this is zero-based, there can be at most 128 different SPR2_'s without changing that.
typedef enum playersprite
{
SPR2_STND = 0,
@ -1160,15 +1157,17 @@ typedef enum playersprite
SPR2_XTRA, // stuff that isn't in-map - "would this ever need an md2 or variable length animation?"
SPR2_FIRSTFREESLOT,
SPR2_LASTFREESLOT = 0x7f,
SPR2_LASTFREESLOT = 1024, // Do not make higher than SPR2F_MASK (currently 0x3FF) plus one
NUMPLAYERSPRITES
} playersprite_t;
// SPR2_XTRA
#define XTRA_LIFEPIC 0 // Life icon patch
#define XTRA_CHARSEL 1 // Character select picture
#define XTRA_CONTINUE 2 // Continue icon
#define XTRA_ENDING 3 // Ending finale patches
enum
{
XTRA_LIFEPIC,
XTRA_CHARSEL,
XTRA_CONTINUE,
XTRA_ENDING
};
typedef enum state
{
@ -4380,6 +4379,7 @@ typedef struct
INT32 var1;
INT32 var2;
statenum_t nextstate;
UINT16 sprite2;
} state_t;
extern state_t states[NUMSTATES];

View file

@ -674,17 +674,15 @@ static int lib_pRemoveMobj(lua_State *L)
return 0;
}
// P_IsValidSprite2 technically doesn't exist, and probably never should... but too much would need to be exposed to allow this to be checked by other methods.
static int lib_pIsValidSprite2(lua_State *L)
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
UINT8 spr2 = (UINT8)luaL_checkinteger(L, 2);
UINT16 spr2 = (UINT16)luaL_checkinteger(L, 2);
//HUDSAFE
INLEVEL
if (!mobj)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, (mobj->skin && (((skin_t *)mobj->skin)->sprites[spr2].numframes)));
lua_pushboolean(L, mobj->skin && P_IsValidSprite2(mobj->skin, spr2));
return 1;
}
@ -3039,6 +3037,9 @@ static int lib_rFrame2Char(lua_State *L)
return 2;
}
// R_SKINS
////////////
// R_SetPlayerSkin technically doesn't exist either, although it's basically just SetPlayerSkin and SetPlayerSkinByNum handled in one place for convenience
static int lib_rSetPlayerSkin(lua_State *L)
{
@ -3101,6 +3102,47 @@ static int lib_rSkinUsable(lua_State *L)
return 1;
}
static int lib_pGetStateSprite2(lua_State *L)
{
int statenum = luaL_checkinteger(L, 1);
if (statenum < 0 || statenum >= NUMSTATES)
return luaL_error(L, "state %d out of range (0 - %d)", statenum, NUMSTATES-1);
lua_pushinteger(L, P_GetStateSprite2(&states[statenum]));
return 1;
}
static int lib_pGetSprite2StateFrame(lua_State *L)
{
int statenum = luaL_checkinteger(L, 1);
if (statenum < 0 || statenum >= NUMSTATES)
return luaL_error(L, "state %d out of range (0 - %d)", statenum, NUMSTATES-1);
lua_pushinteger(L, P_GetSprite2StateFrame(&states[statenum]));
return 1;
}
static int lib_pIsStateSprite2Super(lua_State *L)
{
int statenum = luaL_checkinteger(L, 1);
if (statenum < 0 || statenum >= NUMSTATES)
return luaL_error(L, "state %d out of range (0 - %d)", statenum, NUMSTATES-1);
lua_pushboolean(L, P_IsStateSprite2Super(&states[statenum]));
return 1;
}
// Not a real function. Who cares? I know I don't.
static int lib_pGetSuperSprite2(lua_State *L)
{
int animID = luaL_checkinteger(L, 1) & SPR2F_MASK;
if (animID < 0 || animID >= NUMPLAYERSPRITES)
return luaL_error(L, "sprite2 %d out of range (0 - %d)", animID, NUMPLAYERSPRITES-1);
lua_pushinteger(L, animID | SPR2F_SUPER);
return 1;
}
// R_DATA
////////////
@ -4506,7 +4548,13 @@ static luaL_Reg lib[] = {
{"R_Char2Frame",lib_rChar2Frame},
{"R_Frame2Char",lib_rFrame2Char},
{"R_SetPlayerSkin",lib_rSetPlayerSkin},
// r_skins
{"R_SkinUsable",lib_rSkinUsable},
{"P_GetStateSprite2",lib_pGetStateSprite2},
{"P_GetSprite2StateFrame",lib_pGetSprite2StateFrame},
{"P_IsStateSprite2Super",lib_pIsStateSprite2Super},
{"P_GetSuperSprite2",lib_pGetSuperSprite2},
// r_data
{"R_CheckTextureNumForName",lib_rCheckTextureNumForName},

View file

@ -556,7 +556,7 @@ static int libd_getSprite2Patch(lua_State *L)
UINT8 angle = 0;
spritedef_t *sprdef;
spriteframe_t *sprframe;
boolean super = false; // add FF_SPR2SUPER to sprite2 if true
boolean super = false; // add SPR2F_SUPER to sprite2 if true
HUDONLY
// get skin first!
@ -583,11 +583,12 @@ static int libd_getSprite2Patch(lua_State *L)
if (lua_isnumber(L, 1)) // sprite number given, e.g. SPR2_STND
{
j = lua_tonumber(L, 1);
if (j & FF_SPR2SUPER) // e.g. SPR2_STND|FF_SPR2SUPER
if (j & SPR2F_SUPER) // e.g. SPR2_STND|SPR2F_SUPER
{
super = true;
j &= ~FF_SPR2SUPER; // remove flag so the next check doesn't fail
j &= ~SPR2F_SUPER; // remove flag so the next check doesn't fail
}
if (j >= free_spr2)
return 0;
}
@ -606,17 +607,15 @@ static int libd_getSprite2Patch(lua_State *L)
if (lua_isboolean(L, 2)) // optional boolean for superness
{
super = lua_toboolean(L, 2); // note: this can override FF_SPR2SUPER from sprite number
super = lua_toboolean(L, 2); // note: this can override SPR2F_SUPER from sprite number
lua_remove(L, 2); // remove
}
// if it's not boolean then just assume it's the frame number
if (super)
j |= FF_SPR2SUPER;
j |= SPR2F_SUPER;
j = P_GetSkinSprite2(skins[i], j, NULL); // feed skin and current sprite2 through to change sprite2 used if necessary
sprdef = &skins[i]->sprites[j];
sprdef = P_GetSkinSpritedef(skins[i], j);
// set frame number
frame = luaL_optinteger(L, 2, 0);
@ -644,7 +643,7 @@ static int libd_getSprite2Patch(lua_State *L)
INT32 rot = R_GetRollAngle(rollangle);
if (rot) {
patch_t *rotsprite = Patch_GetRotatedSprite(sprframe, frame, angle, sprframe->flip & (1<<angle), &skins[i]->sprinfo[j], rot);
patch_t *rotsprite = Patch_GetRotatedSprite(sprframe, frame, angle, sprframe->flip & (1<<angle), P_GetSkinSpriteInfo(skins[i], j), rot);
LUA_PushUserdata(L, rotsprite, META_PATCH);
lua_pushboolean(L, false);
lua_pushboolean(L, true);

View file

@ -165,7 +165,7 @@ static int lib_getSpr2default(lua_State *L)
static int lib_setSpr2default(lua_State *L)
{
playersprite_t i;
UINT8 j = 0;
UINT16 j = 0;
if (hud_running)
return luaL_error(L, "Do not alter spr2defaults[] in HUD rendering code!");

View file

@ -564,7 +564,7 @@ static int mobj_set(lua_State *L)
mo->frame = (UINT32)luaL_checkinteger(L, 3);
break;
case mobj_sprite2:
mo->sprite2 = P_GetSkinSprite2(((skin_t *)mo->skin), (UINT8)luaL_checkinteger(L, 3), mo->player);
mo->sprite2 = P_GetSkinSprite2(((skin_t *)mo->skin), (UINT16)luaL_checkinteger(L, 3), mo->player);
break;
case mobj_anim_duration:
mo->anim_duration = (UINT16)luaL_checkinteger(L, 3);

View file

@ -55,6 +55,7 @@ enum skin {
skin_contangle,
skin_soundsid,
skin_sprites,
skin_supersprites,
skin_natkcolor
};
@ -95,6 +96,7 @@ static const char *const skin_opt[] = {
"contangle",
"soundsid",
"sprites",
"supersprites",
"natkcolor",
NULL};
@ -220,6 +222,9 @@ static int skin_get(lua_State *L)
case skin_sprites:
LUA_PushUserdata(L, skin->sprites, META_SKINSPRITES);
break;
case skin_supersprites:
LUA_PushUserdata(L, skin->super.sprites, META_SKINSPRITES);
break;
case skin_natkcolor:
lua_pushinteger(L, skin->natkcolor);
break;
@ -347,17 +352,17 @@ static int lib_getSkinSprite(lua_State *L)
spritedef_t *sksprites = *(spritedef_t **)luaL_checkudata(L, 1, META_SKINSPRITES);
playersprite_t i = luaL_checkinteger(L, 2);
if (i < 0 || i >= NUMPLAYERSPRITES*2)
return luaL_error(L, LUA_QL("skin_t") " field 'sprites' index %d out of range (0 - %d)", i, (NUMPLAYERSPRITES*2)-1);
if (i < 0 || i >= NUMPLAYERSPRITES)
return luaL_error(L, "skin sprites index %d out of range (0 - %d)", i, NUMPLAYERSPRITES-1);
LUA_PushUserdata(L, &sksprites[i], META_SKINSPRITESLIST);
return 1;
}
// #skin.sprites -> NUMPLAYERSPRITES*2
// #skin.sprites -> NUMPLAYERSPRITES
static int lib_numSkinsSprites(lua_State *L)
{
lua_pushinteger(L, NUMPLAYERSPRITES*2);
lua_pushinteger(L, NUMPLAYERSPRITES);
return 1;
}

View file

@ -12056,7 +12056,7 @@ static void M_HandleConnectIP(INT32 choice)
static fixed_t multi_tics;
static UINT8 multi_frame;
static UINT8 multi_spr2;
static UINT16 multi_spr2;
static boolean multi_paused;
static boolean multi_invcolor;

View file

@ -85,9 +85,15 @@ void P_AddCachedAction(mobj_t *mobj, INT32 statenum)
//
static void P_SetupStateAnimation(mobj_t *mobj, state_t *st)
{
INT32 animlength = (mobj->sprite == SPR_PLAY && mobj->skin)
? (INT32)(((skin_t *)mobj->skin)->sprites[mobj->sprite2].numframes) - 1
: st->var1;
INT32 animlength;
if (mobj->sprite == SPR_PLAY && mobj->skin)
{
spritedef_t *spritedef = P_GetSkinSpritedef(mobj->skin, mobj->sprite2);
animlength = (INT32)(spritedef->numframes);
}
else
animlength = st->var1;
if (!(st->frame & FF_ANIMATE))
return;
@ -138,8 +144,13 @@ FUNCINLINE static ATTRINLINE void P_CycleStateAnimation(mobj_t *mobj)
}
// sprite2 version of above
if (mobj->skin && (((++mobj->frame) & FF_FRAMEMASK) >= (UINT32)(((skin_t *)mobj->skin)->sprites[mobj->sprite2].numframes)))
mobj->frame &= ~FF_FRAMEMASK;
if (mobj->skin)
{
spritedef_t *spritedef = P_GetSkinSpritedef(mobj->skin, mobj->sprite2);
UINT32 anim_length = (UINT32)(spritedef->numframes);
if (((++mobj->frame) & FF_FRAMEMASK) >= anim_length)
mobj->frame &= ~FF_FRAMEMASK;
}
}
//
@ -395,31 +406,23 @@ static boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state)
{
skin_t *skin = ((skin_t *)mobj->skin);
UINT16 frame = (mobj->frame & FF_FRAMEMASK)+1;
UINT8 numframes, spr2;
UINT8 numframes;
UINT16 spr2;
if (skin)
{
UINT16 stateframe = st->frame;
spr2 = P_GetStateSprite2(st);
// Add/Remove FF_SPR2SUPER based on certain conditions
if (player->charflags & SF_NOSUPERSPRITES || (player->powers[pw_carry] == CR_NIGHTSMODE && (player->charflags & SF_NONIGHTSSUPER)))
stateframe = stateframe & ~FF_SPR2SUPER;
else if (player->powers[pw_super] || (player->powers[pw_carry] == CR_NIGHTSMODE && (player->charflags & SF_SUPER)))
stateframe = stateframe | FF_SPR2SUPER;
// Add or remove SPR2F_SUPER based on certain conditions
spr2 = P_ApplySuperFlagToSprite2(spr2, mobj);
if (stateframe & FF_SPR2SUPER)
{
if (mobj->eflags & MFE_FORCENOSUPER)
stateframe = stateframe & ~FF_SPR2SUPER;
}
else if (mobj->eflags & MFE_FORCESUPER)
stateframe = stateframe | FF_SPR2SUPER;
// Get the needed sprite2 and frame number
spr2 = P_GetSkinSprite2(skin, spr2, mobj->player);
// Get the sprite2 and frame number
spr2 = P_GetSkinSprite2(skin, (stateframe & FF_FRAMEMASK), mobj->player);
numframes = skin->sprites[spr2].numframes;
spritedef_t *sprdef = P_GetSkinSpritedef(skin, spr2);
numframes = sprdef->numframes;
if (state == S_PLAY_STND && (spr2 & FF_SPR2SUPER) && skin->sprites[SPR2_WAIT|FF_SPR2SUPER].numframes == 0)
if (state == S_PLAY_STND && (spr2 & SPR2F_SUPER) && sprdef[SPR2_WAIT].numframes == 0)
mobj->tics = -1; // If no super wait, don't wait at all
}
else
@ -432,12 +435,19 @@ static boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state)
if (mobj->sprite != SPR_PLAY)
{
mobj->sprite = SPR_PLAY;
frame = 0;
frame = P_GetSprite2StateFrame(st);
}
else if (mobj->sprite2 != spr2)
{
if ((st->frame & FF_SPR2MIDSTART) && numframes && P_RandomChance(FRACUNIT/2))
frame = numframes/2;
if (st->frame & FF_SPR2MIDSTART)
{
if (numframes && P_RandomChance(FRACUNIT/2))
frame = numframes/2;
else
frame = 0;
}
else if (numframes)
frame = P_GetSprite2StateFrame(st) % numframes;
else
frame = 0;
}
@ -452,6 +462,7 @@ static boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state)
{
if (mobj->frame & FF_FRAMEMASK)
mobj->frame--;
return P_SetPlayerMobjState(mobj, st->var1);
}
}
@ -539,26 +550,23 @@ boolean P_SetMobjState(mobj_t *mobj, statenum_t state)
{
skin_t *skin = ((skin_t *)mobj->skin);
UINT16 frame = (mobj->frame & FF_FRAMEMASK)+1;
UINT8 numframes, spr2;
UINT8 numframes;
UINT16 spr2;
if (skin)
{
UINT16 stateframe = st->frame;
spr2 = P_GetStateSprite2(st);
// Add/Remove FF_SPR2SUPER based on certain conditions
if (stateframe & FF_SPR2SUPER)
{
if (mobj->eflags & MFE_FORCENOSUPER)
stateframe = stateframe & ~FF_SPR2SUPER;
}
else if (mobj->eflags & MFE_FORCESUPER)
stateframe = stateframe | FF_SPR2SUPER;
// Add or remove SPR2F_SUPER based on certain conditions
spr2 = P_ApplySuperFlagToSprite2(spr2, mobj);
// Get the sprite2 and frame number
spr2 = P_GetSkinSprite2(skin, (stateframe & FF_FRAMEMASK), NULL);
numframes = skin->sprites[spr2].numframes;
// Get the needed sprite2 and frame number
spr2 = P_GetSkinSprite2(skin, spr2, NULL);
if (state == S_PLAY_STND && (spr2 & FF_SPR2SUPER) && skin->sprites[SPR2_WAIT|FF_SPR2SUPER].numframes == 0)
spritedef_t *sprdef = P_GetSkinSpritedef(skin, spr2);
numframes = sprdef->numframes;
if (state == S_PLAY_STND && (spr2 & SPR2F_SUPER) && sprdef[SPR2_WAIT].numframes == 0)
mobj->tics = -1; // If no super wait, don't wait at all
}
else
@ -571,12 +579,19 @@ boolean P_SetMobjState(mobj_t *mobj, statenum_t state)
if (mobj->sprite != SPR_PLAY)
{
mobj->sprite = SPR_PLAY;
frame = 0;
frame = P_GetSprite2StateFrame(st);
}
else if (mobj->sprite2 != spr2)
{
if ((st->frame & FF_SPR2MIDSTART) && numframes && P_RandomChance(FRACUNIT/2))
frame = numframes/2;
if (st->frame & FF_SPR2MIDSTART)
{
if (numframes && P_RandomChance(FRACUNIT/2))
frame = numframes/2;
else
frame = 0;
}
else if (numframes)
frame = P_GetSprite2StateFrame(st) % numframes;
else
frame = 0;
}
@ -591,6 +606,7 @@ boolean P_SetMobjState(mobj_t *mobj, statenum_t state)
{
if (mobj->frame & FF_FRAMEMASK)
mobj->frame--;
return P_SetMobjState(mobj, st->var1);
}
}
@ -11193,7 +11209,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type, ...)
if (mobj->skin) // correct inadequecies above.
{
mobj->sprite2 = P_GetSkinSprite2(mobj->skin, (mobj->frame & FF_FRAMEMASK), NULL);
mobj->sprite2 = P_GetSkinSprite2(mobj->skin, P_GetStateSprite2(mobj->state), NULL);
mobj->frame &= ~FF_FRAMEMASK;
}

View file

@ -308,7 +308,7 @@ typedef struct mobj_s
angle_t spriteroll, old_spriteroll, old_spriteroll2;
spritenum_t sprite; // used to find patch_t and flip value
UINT32 frame; // frame number, plus bits see p_pspr.h
UINT8 sprite2; // player sprites
UINT16 sprite2; // player sprites
UINT16 anim_duration; // for FF_ANIMATE states
UINT32 renderflags; // render flags
@ -451,7 +451,7 @@ typedef struct precipmobj_s
angle_t spriteroll, old_spriteroll, old_spriteroll2;
spritenum_t sprite; // used to find patch_t and flip value
UINT32 frame; // frame number, plus bits see p_pspr.h
UINT8 sprite2; // player sprites
UINT16 sprite2; // player sprites
UINT16 anim_duration; // for FF_ANIMATE states
UINT32 renderflags; // render flags

View file

@ -97,6 +97,11 @@
/// \brief Frame flags - Animate: Start at a random place in the animation (mutually exclusive with above)
#define FF_RANDOMANIM 0x40000000
/// \brief Animation flags: Bits used for the animation ID
#define SPR2F_MASK 0x3FF
/// \brief Animation flags: "Super" flag
#define SPR2F_SUPER 0x400
/** \brief translucency tables
\todo add another asm routine which use the fg and bg indexes in the

View file

@ -1882,7 +1882,7 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
diff |= MD_TICS;
if (mobj->sprite != mobj->state->sprite)
diff |= MD_SPRITE;
if (mobj->sprite == SPR_PLAY && mobj->sprite2 != (mobj->state->frame&FF_FRAMEMASK))
if (mobj->sprite == SPR_PLAY && mobj->sprite2 != P_GetStateSprite2(mobj->state))
diff |= MD_SPRITE;
if (mobj->frame != mobj->state->frame)
diff |= MD_FRAME;
@ -2066,7 +2066,7 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
if (diff & MD_SPRITE) {
WRITEUINT16(save_p, mobj->sprite);
if (mobj->sprite == SPR_PLAY)
WRITEUINT8(save_p, mobj->sprite2);
WRITEUINT16(save_p, mobj->sprite2);
}
if (diff & MD_FRAME)
{
@ -3096,12 +3096,12 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker)
if (diff & MD_SPRITE) {
mobj->sprite = READUINT16(save_p);
if (mobj->sprite == SPR_PLAY)
mobj->sprite2 = READUINT8(save_p);
mobj->sprite2 = READUINT16(save_p);
}
else {
mobj->sprite = mobj->state->sprite;
if (mobj->sprite == SPR_PLAY)
mobj->sprite2 = mobj->state->frame&FF_FRAMEMASK;
mobj->sprite2 = P_GetStateSprite2(mobj->state);
}
if (diff & MD_FRAME)
{

View file

@ -1400,7 +1400,7 @@ void P_DoSuperDetransformation(player_t *player)
if (!G_CoopGametype())
player->powers[pw_flashing] = flashingtics-1;
if (player->mo->sprite2 & FF_SPR2SUPER)
if (player->mo->sprite2 & SPR2F_SUPER)
P_SetMobjState(player->mo, player->mo->state-states);
// Inform the netgame that the champion has fallen in the heat of battle.
@ -11417,10 +11417,10 @@ void P_DoTailsOverlay(player_t *player, mobj_t *tails)
}
else
{
if (tails->state != states+chosenstate)
if (tails->state != &states[chosenstate])
{
if (states[chosenstate].sprite == SPR_PLAY)
tails->sprite2 = P_GetSkinSprite2(((skin_t *)tails->skin), (states[chosenstate].frame & FF_FRAMEMASK), player);
tails->sprite2 = P_GetSkinSprite2(((skin_t *)tails->skin), P_GetStateSprite2(&states[chosenstate]), player);
P_SetMobjState(tails, chosenstate);
}
}

View file

@ -35,30 +35,87 @@
INT32 numskins = 0;
skin_t **skins = NULL;
//
// P_GetSkinSprite2
// For non-super players, tries each sprite2's immediate predecessor until it finds one with a number of frames or ends up at standing.
// For super players, does the same as above - but tries the super equivalent for each sprite2 before the non-super version.
//
UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player)
// Gets the animation ID of a state
UINT16 P_GetStateSprite2(state_t *state)
{
UINT8 super = 0, i = 0;
if (state->sprite2)
return state->sprite2;
else
{
// Transform the state frame into an animation ID
UINT32 stateframe = state->frame & FF_FRAMEMASK;
UINT16 spr2 = stateframe & ~FF_SPR2SUPER;
if (stateframe & FF_SPR2SUPER)
spr2 |= SPR2F_SUPER;
return spr2;
}
}
// Gets the starting frame of an animation
UINT16 P_GetSprite2StateFrame(state_t *state)
{
if (state->sprite2)
return state->frame & FF_FRAMEMASK;
else
return 0;
}
// Checks if a state should use the "super" variant of the animation
boolean P_IsStateSprite2Super(state_t *state)
{
if (state->sprite2)
{
if (state->sprite2 & SPR2F_SUPER)
return true;
}
else if (state->frame & FF_SPR2SUPER)
return true;
return false;
}
// Applies SPR2F_SUPER to an animation based on the actor's state
UINT16 P_ApplySuperFlagToSprite2(UINT16 spr2, mobj_t *mobj)
{
if (mobj->player)
{
if (mobj->player->charflags & SF_NOSUPERSPRITES || (mobj->player->powers[pw_carry] == CR_NIGHTSMODE && (mobj->player->charflags & SF_NONIGHTSSUPER)))
spr2 &= ~SPR2F_SUPER;
else if (mobj->player->powers[pw_super] || (mobj->player->powers[pw_carry] == CR_NIGHTSMODE && (mobj->player->charflags & SF_SUPER)))
spr2 |= SPR2F_SUPER;
}
if (spr2 & SPR2F_SUPER)
{
if (mobj->eflags & MFE_FORCENOSUPER)
spr2 &= ~SPR2F_SUPER;
}
else if (mobj->eflags & MFE_FORCESUPER)
spr2 |= SPR2F_SUPER;
return spr2;
}
// For non-super players, this tries each sprite2's immediate predecessor until it finds one with a number of frames or ends up at standing.
// For super players, does the same as above - but tries the super equivalent for each sprite2 before the non-super version.
UINT16 P_GetSkinSprite2(skin_t *skin, UINT16 spr2, player_t *player)
{
UINT16 super = 0;
UINT8 i = 0;
if (!skin)
return 0;
if ((playersprite_t)(spr2 & ~FF_SPR2SUPER) >= free_spr2)
return 0;
while (!skin->sprites[spr2].numframes
while (!P_IsValidSprite2(skin, spr2)
&& spr2 != SPR2_STND
&& ++i < 32) // recursion limiter
{
if (spr2 & FF_SPR2SUPER)
if (spr2 & SPR2F_SUPER)
{
super = FF_SPR2SUPER;
spr2 &= ~FF_SPR2SUPER;
super = SPR2F_SUPER;
spr2 &= ~SPR2F_SUPER;
continue;
}
@ -92,6 +149,51 @@ UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player)
return spr2;
}
// Gets the spritedef of a skin animation
spritedef_t *P_GetSkinSpritedef(skin_t *skin, UINT16 spr2)
{
if (!skin)
return NULL;
boolean is_super = spr2 & SPR2F_SUPER;
spr2 &= SPR2F_MASK;
if (spr2 >= free_spr2)
return NULL;
if (is_super)
return &skin->super.sprites[spr2];
else
return &skin->sprites[spr2];
}
// Gets the spriteinfo of a skin animation
spriteinfo_t *P_GetSkinSpriteInfo(skin_t *skin, UINT16 spr2)
{
if (!skin)
return NULL;
boolean is_super = spr2 & SPR2F_SUPER;
spr2 &= SPR2F_MASK;
if (spr2 >= free_spr2)
return NULL;
if (is_super)
return &skin->super.sprinfo[spr2];
else
return &skin->sprinfo[spr2];
}
// Checks if a skin animation is valid
boolean P_IsValidSprite2(skin_t *skin, UINT16 spr2)
{
spritedef_t *sprdef = P_GetSkinSpritedef(skin, spr2);
return sprdef && sprdef->numframes;
}
static void Sk_SetDefaultValue(skin_t *skin)
{
INT32 i;
@ -500,10 +602,10 @@ 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, UINT8 start_spr2)
static void R_LoadSkinSprites(UINT16 wadnum, UINT16 *lump, UINT16 *lastlump, skin_t *skin, UINT16 start_spr2)
{
UINT16 newlastlump;
UINT8 sprite2;
UINT16 sprite2;
*lump += 1; // start after S_SKIN
*lastlump = W_CheckNumForNamePwad("S_END",wadnum,*lump); // stop at S_END
@ -523,7 +625,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 = start_spr2; sprite2 < free_spr2; sprite2++)
R_AddSingleSpriteDef(spr2names[sprite2], &skin->sprites[FF_SPR2SUPER|sprite2], wadnum, newlastlump, *lastlump);
R_AddSingleSpriteDef(spr2names[sprite2], &skin->super.sprites[sprite2], wadnum, newlastlump, *lastlump);
newlastlump--;
*lastlump = newlastlump; // okay, make the normal sprite set loading end there

View file

@ -80,9 +80,14 @@ typedef struct
// specific sounds per skin
sfxenum_t soundsid[NUMSKINSOUNDS]; // sound # in S_sfx table
spritedef_t sprites[NUMPLAYERSPRITES];
spriteinfo_t sprinfo[NUMPLAYERSPRITES];
// contains super versions too
spritedef_t sprites[NUMPLAYERSPRITES*2];
spriteinfo_t sprinfo[NUMPLAYERSPRITES*2];
struct {
spritedef_t sprites[NUMPLAYERSPRITES];
spriteinfo_t sprinfo[NUMPLAYERSPRITES];
} super;
} skin_t;
/// Externs
@ -102,7 +107,14 @@ INT32 R_GetForcedSkin(INT32 playernum);
void R_AddSkins(UINT16 wadnum, boolean mainfile);
void R_PatchSkins(UINT16 wadnum, boolean mainfile);
UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player);
UINT16 P_GetStateSprite2(state_t *state);
UINT16 P_GetSprite2StateFrame(state_t *state);
UINT16 P_GetSkinSprite2(skin_t *skin, UINT16 spr2, player_t *player);
UINT16 P_ApplySuperFlagToSprite2(UINT16 spr2, mobj_t *mobj);
spritedef_t *P_GetSkinSpritedef(skin_t *skin, UINT16 spr2);
spriteinfo_t *P_GetSkinSpriteInfo(skin_t *skin, UINT16 spr2);
boolean P_IsValidSprite2(skin_t *skin, UINT16 spr2);
boolean P_IsStateSprite2Super(state_t *state);
void R_RefreshSprite2(void);

View file

@ -1579,20 +1579,22 @@ static void R_ProjectSprite(mobj_t *thing)
// decide which patch to use for sprite relative to player
#ifdef RANGECHECK
if ((size_t)(thing->sprite) >= numsprites)
I_Error("R_ProjectSprite: invalid sprite number %d ", thing->sprite);
I_Error("R_ProjectSprite: invalid sprite number %d", thing->sprite);
#endif
frame = thing->frame&FF_FRAMEMASK;
frame = thing->frame & FF_FRAMEMASK;
//Fab : 02-08-98: 'skin' override spritedef currently used for skin
if (thing->skin && thing->sprite == SPR_PLAY)
{
sprdef = &((skin_t *)thing->skin)->sprites[thing->sprite2];
sprdef = P_GetSkinSpritedef(thing->skin, thing->sprite2);
#ifdef ROTSPRITE
sprinfo = &((skin_t *)thing->skin)->sprinfo[thing->sprite2];
sprinfo = P_GetSkinSpriteInfo(thing->skin, thing->sprite2);
#endif
if (frame >= sprdef->numframes) {
CONS_Alert(CONS_ERROR, M_GetText("R_ProjectSprite: invalid skins[\"%s\"].sprites[%sSPR2_%s] frame %s\n"), ((skin_t *)thing->skin)->name, ((thing->sprite2 & FF_SPR2SUPER) ? "FF_SPR2SUPER|": ""), spr2names[(thing->sprite2 & ~FF_SPR2SUPER)], sizeu5(frame));
if (frame >= sprdef->numframes)
{
CONS_Alert(CONS_ERROR, M_GetText("R_ProjectSprite: invalid skins[\"%s\"].sprites[SPR2_%s] %sframe %s\n"), ((skin_t *)thing->skin)->name, spr2names[thing->sprite2 & SPR2F_MASK], (thing->sprite2 & SPR2F_SUPER) ? "super ": "", sizeu5(frame));
thing->sprite = states[S_UNKNOWN].sprite;
thing->frame = states[S_UNKNOWN].frame;
sprdef = &sprites[thing->sprite];

View file

@ -371,9 +371,11 @@ void ST_LoadFaceGraphics(INT32 skinnum)
spritedef_t *sprdef = &skins[skinnum]->sprites[SPR2_XTRA];
spriteframe_t *sprframe = &sprdef->spriteframes[XTRA_LIFEPIC];
faceprefix[skinnum] = W_CachePatchNum(sprframe->lumppat[0], PU_HUDGFX);
if (skins[skinnum]->sprites[(SPR2_XTRA|FF_SPR2SUPER)].numframes > XTRA_LIFEPIC)
spritedef_t *super_sprdef = P_GetSkinSpritedef(skins[skinnum], SPR2_XTRA|SPR2F_SUPER);
if (super_sprdef->numframes > XTRA_LIFEPIC)
{
sprdef = &skins[skinnum]->sprites[SPR2_XTRA|FF_SPR2SUPER];
sprdef = super_sprdef;
sprframe = &sprdef->spriteframes[0];
superprefix[skinnum] = W_CachePatchNum(sprframe->lumppat[0], PU_HUDGFX);
}