Merge branch 'master' of http://git.magicalgirl.moe/STJr/SRB2Internal.git into skin_patch

# Conflicts:
#	src/dehacked.c
#	src/p_setup.c
#	src/r_things.c
This commit is contained in:
toasterbabe 2017-04-07 15:37:22 +01:00
commit 8f9ee2da30
55 changed files with 3152 additions and 1869 deletions

View file

@ -1073,7 +1073,7 @@ static void R_ProjectSprite(mobj_t *thing)
{
sprdef = &((skin_t *)thing->skin)->sprites[thing->sprite2];
if (rot >= sprdef->numframes) {
CONS_Alert(CONS_ERROR, M_GetText("R_ProjectSprite: invalid skins[\"%s\"].sprites[SPR2_%s] frame %s\n"), ((skin_t *)thing->skin)->name, spr2names[thing->sprite2], sizeu5(rot));
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(rot));
thing->sprite = states[S_UNKNOWN].sprite;
thing->frame = states[S_UNKNOWN].frame;
sprdef = &sprites[thing->sprite];
@ -2383,7 +2383,11 @@ static void Sk_SetDefaultValue(skin_t *skin)
skin->flags = 0;
strcpy(skin->realname, "Someone");
#ifdef SKINNAMEPADDING
strcpy(skin->hudname, " ???");
#else
strcpy(skin->hudname, "???");
#endif
strncpy(skin->charsel, "CHRSONIC", 8);
strncpy(skin->face, "MISSING", 8);
strncpy(skin->superface, "MISSING", 8);
@ -2445,16 +2449,29 @@ void R_InitSkins(void)
numskins = 0;
}
UINT32 R_GetSkinAvailabilities(void)
{
INT32 s;
UINT32 response = 0;
for (s = 0; s < MAXSKINS; s++)
{
if (skins[s].availability && unlockables[skins[s].availability - 1].unlocked)
response |= (1 << s);
}
return response;
}
// returns true if available in circumstances, otherwise nope
// warning don't use with an invalid skinnum other than -1 which always returns true
boolean R_SkinUnlock(INT32 skinnum)
boolean R_SkinUsable(INT32 playernum, INT32 skinnum)
{
return ((skinnum == -1) // Simplifies things elsewhere, since there's already plenty of checks for less-than-0...
|| (!skins[skinnum].availability)
|| (unlockables[skins[skinnum].availability - 1].unlocked)
|| ((playernum != -1) ? (players[playernum].availabilities & (1 << skinnum)) : (unlockables[skins[skinnum].availability - 1].unlocked))
|| (modeattacking) // If you have someone else's run you might as well take a look
|| (Playing() && (R_SkinAvailable(mapheaderinfo[gamemap-1]->forcecharacter) == skinnum)) // Force 1.
|| (netgame && !(server || adminplayer == consoleplayer) && (cv_forceskin.value == skinnum)) // Force 2.
|| (netgame && (cv_forceskin.value == skinnum)) // Force 2.
);
}
@ -2479,7 +2496,7 @@ void SetPlayerSkin(INT32 playernum, const char *skinname)
INT32 i = R_SkinAvailable(skinname);
player_t *player = &players[playernum];
if ((i != -1) && (!P_IsLocalPlayer(player) || R_SkinUnlock(i)))
if ((i != -1) && R_SkinUsable(playernum, i))
{
SetPlayerSkinByNum(playernum, i);
return;
@ -2501,8 +2518,7 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum)
skin_t *skin = &skins[skinnum];
UINT8 newcolor = 0;
if ((skinnum >= 0 && skinnum < numskins) // Make sure it exists!
&& (!P_IsLocalPlayer(player) || R_SkinUnlock(skinnum))) // ...but is it allowed? We must always allow external players to change skin. The server should vet that...
if (skinnum >= 0 && skinnum < numskins && R_SkinUsable(playernum, skinnum)) // Make sure it exists!
{
player->skin = skinnum;
@ -2544,7 +2560,7 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum)
if (player->mo)
{
if ((player->pflags & PF_NIGHTSMODE) && (skin->sprites[SPR2_NGT0].numframes == 0)) // If you don't have a sprite for flying horizontally, use the default NiGHTS skin.
if ((player->powers[pw_carry] == CR_NIGHTSMODE) && (skin->sprites[SPR2_NGT0].numframes == 0)) // If you don't have a sprite for flying horizontally, use the default NiGHTS skin.
{
skin = &skins[DEFAULTNIGHTSSKIN];
newcolor = ((skin->flags & SF_SUPER) ? skin->supercolor : skin->prefcolor);
@ -2554,16 +2570,16 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum)
player->mo->color = newcolor;
P_SetScale(player->mo, player->mo->scale);
player->mo->radius = FixedMul(skin->radius, player->mo->scale);
P_SetPlayerMobjState(player->mo, player->mo->state-states); // Prevent visual errors when switching between skins with differing number of frames
}
return;
}
else if (skinnum >= 0 && skinnum < numskins)
skinnum = 255; // Cheeky emulation.
if (P_IsLocalPlayer(player))
CONS_Alert(CONS_WARNING, M_GetText("Skin %d not found\n"), skinnum);
CONS_Alert(CONS_WARNING, M_GetText("Requested skin not found\n"));
else if(server || adminplayer == consoleplayer)
CONS_Alert(CONS_WARNING, "Player %d (%s) skin %d not found\n", playernum, player_names[playernum], skinnum);
CONS_Alert(CONS_WARNING, "Player %d (%s) skin not found\n", playernum, player_names[playernum]);
SetPlayerSkinByNum(playernum, 0); // not found put the sonic skin
}
@ -2592,6 +2608,12 @@ static UINT16 W_CheckForSkinMarkerInPwad(UINT16 wadid, UINT16 startlump)
return INT16_MAX; // not found
}
#ifdef SKINNAMEPADDING
#define HUDNAMEWRITE(value) snprintf(skin->hudname, sizeof(skin->hudname), "%5s", value)
#else
#define HUDNAMEWRITE(value) STRBUFCPY(skin->hudname, value)
#endif
//
// Patch skins from a pwad, each skin preceded by 'P_SKIN' marker
//
@ -2617,24 +2639,155 @@ static UINT16 W_CheckForPatchSkinMarkerInPwad(UINT16 wadid, UINT16 startlump)
return INT16_MAX; // not found
}
//
void R_LoadSkinSprites(UINT16 wadnum, UINT16 lump, skin_t *skin)
static void R_LoadSkinSprites(UINT16 wadnum, UINT16 *lump, UINT16 *lastlump, skin_t *skin)
{
UINT16 lastlump, z;
UINT16 newlastlump;
UINT8 sprite2;
lastlump = W_CheckNumForNamePwad("S_END",wadnum,lump); // stop at S_END
// old wadding practices die hard -- stop at S_SKIN (/P_SKIN) or S_START if they come before S_END.
z = W_CheckNumForNamePwad("S_SKIN",wadnum,lump);
if (z < lastlump) lastlump = z;
z = W_CheckNumForNamePwad("P_SKIN",wadnum,lump);
if (z < lastlump) lastlump = z;
z = W_CheckNumForNamePwad("S_START",wadnum,lump);
if (z < lastlump) lastlump = z;
*lump += 1; // start after S_SKIN
*lastlump = W_CheckNumForNamePwad("S_END",wadnum,*lump); // stop at S_END
// load all sprite sets we are aware of.
// old wadding practices die hard -- stop at S_SKIN (or P_SKIN) or S_START if they come before S_END.
newlastlump = W_CheckForSkinMarkerInPwad(wadnum,*lump);
if (newlastlump < *lastlump) *lastlump = newlastlump;
newlastlump = W_CheckForPatchSkinMarkerInPwad(wadnum,*lump);
if (newlastlump < *lastlump) *lastlump = newlastlump;
newlastlump = W_CheckNumForNamePwad("S_START",wadnum,*lump);
if (newlastlump < *lastlump) *lastlump = newlastlump;
// ...and let's handle super, too
newlastlump = W_CheckNumForNamePwad("S_SUPER",wadnum,*lump);
if (newlastlump < *lastlump)
{
newlastlump++;
// load all sprite sets we are aware of... for super!
for (sprite2 = 0; sprite2 < free_spr2; sprite2++)
R_AddSingleSpriteDef((spritename = spr2names[sprite2]), &skin->sprites[FF_SPR2SUPER|sprite2], wadnum, newlastlump, *lastlump);
newlastlump--;
*lastlump = newlastlump; // okay, make the normal sprite set loading end there
}
// load all sprite sets we are aware of... for normal stuff.
for (sprite2 = 0; sprite2 < free_spr2; sprite2++)
R_AddSingleSpriteDef(spr2names[sprite2], &skin->sprites[sprite2], wadnum, lump, lastlump);
R_AddSingleSpriteDef((spritename = spr2names[sprite2]), &skin->sprites[sprite2], wadnum, *lump, *lastlump);
}
// returns whether found appropriate property
static boolean R_ProcessPatchableFields(skin_t *skin, char *stoken, char *value)
{
// custom translation table
if (!stricmp(stoken, "startcolor"))
skin->starttranscolor = atoi(value);
#define FULLPROCESS(field) else if (!stricmp(stoken, #field)) skin->field = get_number(value);
// character type identification
FULLPROCESS(flags)
FULLPROCESS(ability)
FULLPROCESS(ability2)
FULLPROCESS(thokitem)
FULLPROCESS(spinitem)
FULLPROCESS(revitem)
#undef FULLPROCESS
#define GETFRACBITS(field) else if (!stricmp(stoken, #field)) skin->field = atoi(value)<<FRACBITS;
GETFRACBITS(normalspeed)
GETFRACBITS(runspeed)
GETFRACBITS(mindash)
GETFRACBITS(maxdash)
GETFRACBITS(actionspd)
GETFRACBITS(radius)
GETFRACBITS(height)
GETFRACBITS(spinheight)
#undef GETFRACBITS
#define GETINT(field) else if (!stricmp(stoken, #field)) skin->field = atoi(value);
GETINT(thrustfactor)
GETINT(accelstart)
GETINT(acceleration)
#undef GETINT
#define GETSKINCOLOR(field) else if (!stricmp(stoken, #field)) skin->field = R_GetColorByName(value);
GETSKINCOLOR(prefcolor)
GETSKINCOLOR(prefoppositecolor)
#undef GETSKINCOLOR
else if (!stricmp(stoken, "supercolor"))
skin->supercolor = R_GetSuperColorByName(value);
#define GETFLOAT(field) else if (!stricmp(stoken, #field)) skin->field = FLOAT_TO_FIXED(atof(value));
GETFLOAT(jumpfactor)
GETFLOAT(highresscale)
GETFLOAT(shieldscale)
GETFLOAT(camerascale)
#undef GETFLOAT
#define GETFLAG(field) else if (!stricmp(stoken, #field)) { \
strupr(value); \
if (atoi(value) || value[0] == 'T' || value[0] == 'Y') \
skin->flags |= (SF_##field); \
else \
skin->flags &= ~(SF_##field); \
}
// parameters for individual character flags
// these are uppercase so they can be concatenated with SF_
// 1, true, yes are all valid values
GETFLAG(SUPER)
GETFLAG(NOSUPERSPIN)
GETFLAG(NOSPINDASHDUST)
GETFLAG(HIRES)
GETFLAG(NOSKID)
GETFLAG(NOSPEEDADJUST)
GETFLAG(RUNONWATER)
GETFLAG(NOJUMPSPIN)
GETFLAG(NOJUMPDAMAGE)
GETFLAG(STOMPDAMAGE)
GETFLAG(MARIODAMAGE)
GETFLAG(MACHINE)
GETFLAG(DASHMODE)
GETFLAG(FASTEDGE)
GETFLAG(MULTIABILITY)
#undef GETFLAG
else // let's check if it's a sound, otherwise error out
{
boolean found = false;
sfxenum_t i;
size_t stokenadjust;
// Remove the prefix. (We need to affect an adjusting variable so that we can print error messages if it's not actually a sound.)
if ((stoken[0] == 'D' || stoken[0] == 'd') && (stoken[1] == 'S' || stoken[1] == 's')) // DS*
stokenadjust = 2;
else // sfx_*
stokenadjust = 4;
// Remove the prefix. (We can affect this directly since we're not going to use it again.)
if ((value[0] == 'D' || value[0] == 'd') && (value[1] == 'S' || value[1] == 's')) // DS*
value += 2;
else // sfx_*
value += 4;
// copy name of sounds that are remapped
// for this skin
for (i = 0; i < sfx_skinsoundslot0; i++)
{
if (!S_sfx[i].name)
continue;
if (S_sfx[i].skinsound != -1
&& !stricmp(S_sfx[i].name,
stoken + stokenadjust))
{
skin->soundsid[S_sfx[i].skinsound] =
S_AddSoundFx(value, S_sfx[i].singularity, S_sfx[i].pitch, true);
found = true;
}
}
return found;
}
return true;
}
//
@ -2729,7 +2882,7 @@ void R_AddSkins(UINT16 wadnum)
}
if (!hudname)
{
STRBUFCPY(skin->hudname, skin->name);
HUDNAMEWRITE(skin->name);
strupr(skin->hudname);
for (value = skin->hudname; *value; value++)
if (*value == '_') *value = ' '; // turn _ into spaces.
@ -2742,18 +2895,17 @@ void R_AddSkins(UINT16 wadnum)
for (value = skin->realname; *value; value++)
if (*value == '_') *value = ' '; // turn _ into spaces.
if (!hudname)
STRBUFCPY(skin->hudname, skin->realname);
HUDNAMEWRITE(skin->realname);
}
else if (!stricmp(stoken, "hudname"))
{ // Life icon name (eg. "K.T.E")
hudname = true;
STRBUFCPY(skin->hudname, value);
HUDNAMEWRITE(value);
for (value = skin->hudname; *value; value++)
if (*value == '_') *value = ' '; // turn _ into spaces.
if (!realname)
STRBUFCPY(skin->realname, skin->hudname);
}
else if (!stricmp(stoken, "charsel"))
{
strupr(value);
@ -2772,37 +2924,6 @@ void R_AddSkins(UINT16 wadnum)
strupr(value);
strncpy(skin->superface, value, sizeof skin->superface);
}
#define FULLPROCESS(field) else if (!stricmp(stoken, #field)) skin->field = get_number(value);
// character type identification
FULLPROCESS(flags)
FULLPROCESS(ability)
FULLPROCESS(ability2)
FULLPROCESS(thokitem)
FULLPROCESS(spinitem)
FULLPROCESS(revitem)
#undef FULLPROCESS
#define GETFRACBITS(field) else if (!stricmp(stoken, #field)) skin->field = atoi(value)<<FRACBITS;
GETFRACBITS(normalspeed)
GETFRACBITS(runspeed)
GETFRACBITS(mindash)
GETFRACBITS(maxdash)
GETFRACBITS(actionspd)
GETFRACBITS(radius)
GETFRACBITS(height)
GETFRACBITS(spinheight)
#undef GETFRACBITS
#define GETINT(field) else if (!stricmp(stoken, #field)) skin->field = atoi(value);
GETINT(thrustfactor)
GETINT(accelstart)
GETINT(acceleration)
#undef GETINT
else if (!stricmp(stoken, "availability"))
{
skin->availability = atoi(value);
@ -2811,93 +2932,16 @@ void R_AddSkins(UINT16 wadnum)
if (skin->availability)
STRBUFCPY(unlockables[skin->availability - 1].name, skin->realname);
}
else if (!R_ProcessPatchableFields(skin, stoken, value))
CONS_Debug(DBG_SETUP, "R_AddSkins: Unknown keyword '%s' in S_SKIN lump #%d (WAD %s)\n", stoken, lump, wadfiles[wadnum]->filename);
// custom translation table
else if (!stricmp(stoken, "startcolor"))
skin->starttranscolor = atoi(value);
#define GETSKINCOLOR(field) else if (!stricmp(stoken, #field)) skin->field = R_GetColorByName(value);
GETSKINCOLOR(prefcolor)
GETSKINCOLOR(prefoppositecolor)
#undef GETSKINCOLOR
else if (!stricmp(stoken, "supercolor"))
skin->supercolor = R_GetSuperColorByName(value);
#define GETFLOAT(field) else if (!stricmp(stoken, #field)) skin->field = FLOAT_TO_FIXED(atof(value));
GETFLOAT(jumpfactor)
GETFLOAT(highresscale)
GETFLOAT(shieldscale)
GETFLOAT(camerascale)
#undef GETFLOAT
#define GETFLAG(field) else if (!stricmp(stoken, #field)) { \
strupr(value); \
if (atoi(value) || value[0] == 'T' || value[0] == 'Y') \
skin->flags |= (SF_##field); \
else \
skin->flags &= ~(SF_##field); \
}
// parameters for individual character flags
// these are uppercase so they can be concatenated with SF_
// 1, true, yes are all valid values
GETFLAG(SUPER)
GETFLAG(SUPERANIMS)
GETFLAG(SUPERSPIN)
GETFLAG(HIRES)
GETFLAG(NOSKID)
GETFLAG(NOSPEEDADJUST)
GETFLAG(RUNONWATER)
GETFLAG(NOJUMPSPIN)
GETFLAG(NOJUMPDAMAGE)
GETFLAG(STOMPDAMAGE)
GETFLAG(MARIODAMAGE)
GETFLAG(MACHINE)
GETFLAG(NOSPINDASHDUST)
#undef GETFLAG
else // let's check if it's a sound, otherwise error out
{
boolean found = false;
sfxenum_t i;
size_t stokenadjust;
// Remove the prefix. (We need to affect an adjusting variable so that we can print error messages if it's not actually a sound.)
if ((stoken[0] == 'D' || stoken[0] == 'd') && (stoken[1] == 'S' || stoken[1] == 's')) // DS*
stokenadjust = 2;
else // sfx_*
stokenadjust = 4;
// Remove the prefix. (We can affect this directly since we're not going to use it again.)
if ((value[0] == 'D' || value[0] == 'd') && (value[1] == 'S' || value[1] == 's')) // DS*
value += 2;
else // sfx_*
value += 4;
// copy name of sounds that are remapped
// for this skin
for (i = 0; i < sfx_skinsoundslot0; i++)
{
if (!S_sfx[i].name)
continue;
if (S_sfx[i].skinsound != -1
&& !stricmp(S_sfx[i].name,
stoken + stokenadjust))
{
skin->soundsid[S_sfx[i].skinsound] =
S_AddSoundFx(value, S_sfx[i].singularity, S_sfx[i].pitch, true);
found = true;
}
}
if (!found)
CONS_Debug(DBG_SETUP, "R_AddSkins: Unknown keyword '%s' in S_SKIN lump #%d (WAD %s)\n", stoken, lump, wadfiles[wadnum]->filename);
}
next_token:
stoken = strtok(NULL, "\r\n= ");
}
free(buf2);
// Add sprites
R_LoadSkinSprites(wadnum, ++lump, skin);
R_LoadSkinSprites(wadnum, &lump, &lastlump, skin);
R_FlushTranslationColormapCache();
@ -2933,10 +2977,7 @@ void R_PatchSkins(UINT16 wadnum)
char *value;
size_t size;
skin_t *skin;
boolean noskincomplain;
UINT8 parsemode; // the types are not enums because they should be irrelevant outside this function
#define PATCHPARSE_GET_NAME 0
#define PATCHPARSE_MODIFY_PROPERTY 1
boolean noskincomplain, realname, hudname;
//
// search for all skin patch markers in pwad
@ -2960,13 +3001,12 @@ void R_PatchSkins(UINT16 wadnum)
buf2[size] = '\0';
skin = NULL;
noskincomplain = false;
noskincomplain = realname = hudname = 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)
*/
parsemode = 0;
stoken = strtok(buf2, "\r\n= ");
while (stoken)
{
@ -2982,28 +3022,43 @@ void R_PatchSkins(UINT16 wadnum)
if (!value)
I_Error("R_PatchSkins: syntax error in P_SKIN lump# %d(%s) in WAD %s\n", lump, W_CheckNameForNumPwad(wadnum,lump), wadfiles[wadnum]->filename);
switch (parsemode) // This is where additional tokens with values may be considered.
if (!skin) // Get the name!
{
case PATCHPARSE_GET_NAME:
if (!stricmp(stoken, "name"))
if (!stricmp(stoken, "name"))
{
strlwr(value);
skinnum = R_SkinAvailable(value);
if (skinnum != -1)
skin = &skins[skinnum];
else
{
strlwr(value);
skinnum = R_SkinAvailable(value);
if (skinnum != -1)
{
skin = &skins[skinnum];
parsemode = PATCHPARSE_MODIFY_PROPERTY; // We have a skin now, so we can modify its properties.
}
else
{
CONS_Debug(DBG_SETUP, "R_PatchSkins: unknown skin name in P_SKIN lump# %d(%s) in WAD %s\n", lump, W_CheckNameForNumPwad(wadnum,lump), wadfiles[wadnum]->filename);
noskincomplain = true;
}
CONS_Debug(DBG_SETUP, "R_PatchSkins: unknown skin name in P_SKIN lump# %d(%s) in WAD %s\n", lump, W_CheckNameForNumPwad(wadnum,lump), wadfiles[wadnum]->filename);
noskincomplain = true;
}
case PATCHPARSE_MODIFY_PROPERTY: // No value-requiring properties available for modification yet.
break;
default: // ???
break;
}
}
else // Get the properties!
{
if (!stricmp(stoken, "realname"))
{ // Display name (eg. "Knuckles")
realname = true;
STRBUFCPY(skin->realname, value);
for (value = skin->realname; *value; value++)
if (*value == '_') *value = ' '; // turn _ into spaces.
if (!hudname)
HUDNAMEWRITE(skin->realname);
}
else if (!stricmp(stoken, "hudname"))
{ // Life icon name (eg. "K.T.E")
hudname = true;
HUDNAMEWRITE(value);
for (value = skin->hudname; *value; value++)
if (*value == '_') *value = ' '; // turn _ into spaces.
if (!realname)
STRBUFCPY(skin->realname, skin->hudname);
}
else if (!R_ProcessPatchableFields(skin, stoken, value))
CONS_Debug(DBG_SETUP, "R_PatchSkins: Unknown keyword '%s' in P_SKIN lump #%d (WAD %s)\n", stoken, lump, wadfiles[wadnum]->filename);
}
if (!skin)
@ -3022,10 +3077,11 @@ next_token:
}
// Patch sprites
R_LoadSkinSprites(wadnum, ++lump, skin);
R_LoadSkinSprites(wadnum, &lump, &lastlump, skin);
if (!skin->availability) // Safe to print...
CONS_Printf(M_GetText("Patched skin '%s'\n"), skin->name);
}
return;
}
}
#undef HUDNAMEWRITE