Merge branch 'raise-skin-limit' into 'next'

Raise the skin limit

See merge request STJr/SRB2!1466
This commit is contained in:
Logan Aerl Arias 2024-01-01 22:07:42 +00:00
commit dd8ae3db09
44 changed files with 565 additions and 625 deletions

View file

@ -2056,7 +2056,7 @@ static void CV_SetValueMaybeStealth(consvar_t *var, INT32 value, boolean stealth
if ((value < 0) || (value >= numskins)) if ((value < 0) || (value >= numskins))
tmpskin = "None"; tmpskin = "None";
else else
tmpskin = skins[value].name; tmpskin = skins[value]->name;
strncpy(val, tmpskin, SKINNAMESIZE); strncpy(val, tmpskin, SKINNAMESIZE);
} }
else else

View file

@ -1429,10 +1429,6 @@ void D_SRB2Main(void)
// Make backups of some SOCcable tables. // Make backups of some SOCcable tables.
P_BackupTables(); P_BackupTables();
// Setup character tables
// Have to be done here before files are loaded
M_InitCharacterTables();
mainwads = 3; // doesn't include music.dta mainwads = 3; // doesn't include music.dta
#ifdef USE_PATCH_DTA #ifdef USE_PATCH_DTA
mainwads++; mainwads++;

View file

@ -451,10 +451,10 @@ typedef struct player_s
UINT16 flashcount; UINT16 flashcount;
UINT16 flashpal; UINT16 flashpal;
// Player skin colorshift, 0-15 for which color to draw player. // Player skin colorshift, which color to draw player.
UINT16 skincolor; UINT16 skincolor;
INT32 skin; UINT8 skin;
UINT32 availabilities; UINT32 availabilities;
UINT32 score; // player score (total) UINT32 score; // player score (total)

View file

@ -188,25 +188,22 @@ void clear_levels(void)
P_AllocMapHeader(gamemap-1); P_AllocMapHeader(gamemap-1);
} }
static boolean findFreeSlot(INT32 *num) static boolean findCharacterSlot(INT32 *num)
{ {
// Send the character select entry to a free slot. if (description)
while (*num < MAXSKINS && (description[*num].used)) {
*num = *num+1; // Send the character select entry to a free slot.
while (*num < numdescriptions && (description[*num].used))
(*num)++;
}
// No more free slots. :( // No more free slots.
if (*num >= MAXSKINS) if (*num >= MAXCHARACTERSLOTS)
return false; return false;
else if (*num >= numdescriptions)
M_InitCharacterTables((*num) + 1);
// Redesign your logo. (See M_DrawSetupChoosePlayerMenu in m_menu.c...) // Found one!
description[*num].picname[0] = '\0';
description[*num].nametag[0] = '\0';
description[*num].displayname[0] = '\0';
description[*num].oppositecolor = SKINCOLOR_NONE;
description[*num].tagtextcolor = SKINCOLOR_NONE;
description[*num].tagoutlinecolor = SKINCOLOR_NONE;
// Found one! ^_^
return (description[*num].used = true); return (description[*num].used = true);
} }
@ -217,30 +214,43 @@ void readPlayer(MYFILE *f, INT32 num)
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
char *word; char *word;
char *word2; char *word2;
char *displayname = ZZ_Alloc(MAXLINELEN+1);
INT32 i;
boolean slotfound = false; boolean slotfound = false;
boolean failure = false;
INT32 i;
if (num < 0 || num >= MAXCHARACTERSLOTS)
{
deh_warning("Character %d out of range (0 - %d)", num, MAXCHARACTERSLOTS-1);
failure = true;
}
#define FINDSLOT \
if (!failure && !slotfound && (slotfound = findCharacterSlot(&num)) == false) { \
failure = true; \
deh_warning("Too many characters, ignoring"); \
}
#define SLOTFOUND \ #define SLOTFOUND \
if (!slotfound && (slotfound = findFreeSlot(&num)) == false) \ FINDSLOT \
goto done; if (failure) \
continue;
displayname[MAXLINELEN] = '\0';
do do
{ {
if (myfgets(s, MAXLINELEN, f)) if (myfgets(s, MAXLINELEN, f))
{ {
char stringvalue[MAXLINELEN];
if (s[0] == '\n') if (s[0] == '\n')
break; break;
for (i = 0; i < MAXLINELEN-3; i++) stringvalue[0] = '\0';
for (i = 0; i < MAXLINELEN-3 && !failure; i++)
{ {
char *tmp;
if (s[i] == '=') if (s[i] == '=')
{ {
tmp = &s[i+2]; strlcpy(stringvalue, &s[i+2], sizeof stringvalue);
strncpy(displayname, tmp, SKINNAMESIZE);
break; break;
} }
} }
@ -255,7 +265,13 @@ void readPlayer(MYFILE *f, INT32 num)
{ {
char *playertext = NULL; char *playertext = NULL;
SLOTFOUND FINDSLOT
if (failure)
{
ignorelinesuntilhash(f);
continue;
}
// A friendly neighborhood alias for brevity's sake // A friendly neighborhood alias for brevity's sake
#define NOTE_SIZE sizeof(description[num].notes) #define NOTE_SIZE sizeof(description[num].notes)
@ -275,7 +291,7 @@ void readPlayer(MYFILE *f, INT32 num)
myhashfgets(playertext, NOTE_SIZE, f), NOTE_SIZE); myhashfgets(playertext, NOTE_SIZE, f), NOTE_SIZE);
} }
else else
strcpy(description[num].notes, ""); description[num].notes[0] = '\0';
// For some reason, cutting the string did not work above. Most likely due to strcpy or strcat... // For some reason, cutting the string did not work above. Most likely due to strcpy or strcat...
// It works down here, though. // It works down here, though.
@ -304,37 +320,32 @@ void readPlayer(MYFILE *f, INT32 num)
if (word2[strlen(word2)-1] == '\n') if (word2[strlen(word2)-1] == '\n')
word2[strlen(word2)-1] = '\0'; word2[strlen(word2)-1] = '\0';
i = atoi(word2);
if (fastcmp(word, "PICNAME")) if (fastcmp(word, "PICNAME"))
{ {
SLOTFOUND SLOTFOUND
strncpy(description[num].picname, word2, 8); strncpy(description[num].picname, word2, 8);
} }
// new character select
else if (fastcmp(word, "DISPLAYNAME")) else if (fastcmp(word, "DISPLAYNAME"))
{ {
char *cur = NULL;
SLOTFOUND SLOTFOUND
// replace '#' with line breaks
// (also remove any '\n') // Remove any line breaks
cur = strchr(stringvalue, '\n');
if (cur)
*cur = '\0';
// Turn '#' into line breaks
cur = strchr(stringvalue, '#');
while (cur)
{ {
char *cur = NULL; *cur = '\n';
cur = strchr(cur, '#');
// remove '\n'
cur = strchr(displayname, '\n');
if (cur)
*cur = '\0';
// turn '#' into '\n'
cur = strchr(displayname, '#');
while (cur)
{
*cur = '\n';
cur = strchr(cur, '#');
}
} }
// copy final string
strncpy(description[num].displayname, displayname, SKINNAMESIZE); strlcpy(description[num].displayname, stringvalue, sizeof description[num].displayname);
} }
else if (fastcmp(word, "OPPOSITECOLOR") || fastcmp(word, "OPPOSITECOLOUR")) else if (fastcmp(word, "OPPOSITECOLOR") || fastcmp(word, "OPPOSITECOLOUR"))
{ {
@ -365,10 +376,12 @@ void readPlayer(MYFILE *f, INT32 num)
Because of this, you are allowed to edit any previous entries you like, but only if you Because of this, you are allowed to edit any previous entries you like, but only if you
signal that you are purposely doing so by disabling and then reenabling the slot. signal that you are purposely doing so by disabling and then reenabling the slot.
*/ */
if (i && !slotfound && (slotfound = findFreeSlot(&num)) == false) i = atoi(word2);
goto done; if (i && !slotfound && (slotfound = findCharacterSlot(&num)) == false)
failure = true;
description[num].used = (!!i); if (!failure)
description[num].used = (!!i);
} }
else if (fastcmp(word, "SKINNAME")) else if (fastcmp(word, "SKINNAME"))
{ {
@ -377,13 +390,12 @@ void readPlayer(MYFILE *f, INT32 num)
strlcpy(description[num].skinname, word2, sizeof description[num].skinname); strlcpy(description[num].skinname, word2, sizeof description[num].skinname);
strlwr(description[num].skinname); strlwr(description[num].skinname);
} }
else else if (!failure)
deh_warning("readPlayer %d: unknown word '%s'", num, word); deh_warning("readPlayer %d: unknown word '%s'", num, word);
} }
} while (!myfeof(f)); // finish when the line is empty } while (!myfeof(f)); // finish when the line is empty
#undef FINDSLOT
#undef SLOTFOUND #undef SLOTFOUND
done:
Z_Free(displayname);
Z_Free(s); Z_Free(s);
} }
@ -933,7 +945,7 @@ void readspriteinfo(MYFILE *f, INT32 num, boolean sprite2)
INT32 value; INT32 value;
#endif #endif
char *lastline; char *lastline;
INT32 skinnumbers[MAXSKINS]; UINT8 *skinnumbers = NULL;
INT32 foundskins = 0; INT32 foundskins = 0;
// allocate a spriteinfo // allocate a spriteinfo
@ -1022,7 +1034,9 @@ void readspriteinfo(MYFILE *f, INT32 num, boolean sprite2)
break; break;
} }
skinnumbers[foundskins] = skinnum; if (skinnumbers == NULL)
skinnumbers = Z_Malloc(sizeof(UINT8) * numskins, PU_STATIC, NULL);
skinnumbers[foundskins] = (UINT8)skinnum;
foundskins++; foundskins++;
} }
else if (fastcmp(word, "DEFAULT")) else if (fastcmp(word, "DEFAULT"))
@ -1065,8 +1079,7 @@ void readspriteinfo(MYFILE *f, INT32 num, boolean sprite2)
} }
for (i = 0; i < foundskins; i++) for (i = 0; i < foundskins; i++)
{ {
size_t skinnum = skinnumbers[i]; skin_t *skin = skins[skinnumbers[i]];
skin_t *skin = &skins[skinnum];
spriteinfo_t *sprinfo = skin->sprinfo; spriteinfo_t *sprinfo = skin->sprinfo;
M_Memcpy(&sprinfo[num], info, sizeof(spriteinfo_t)); M_Memcpy(&sprinfo[num], info, sizeof(spriteinfo_t));
} }
@ -1085,6 +1098,8 @@ void readspriteinfo(MYFILE *f, INT32 num, boolean sprite2)
Z_Free(s); Z_Free(s);
Z_Free(info); Z_Free(info);
if (skinnumbers)
Z_Free(skinnumbers);
} }
void readsprite2(MYFILE *f, INT32 num) void readsprite2(MYFILE *f, INT32 num)
@ -1130,7 +1145,6 @@ void readsprite2(MYFILE *f, INT32 num)
Z_Free(s); Z_Free(s);
} }
// copypasted from readPlayer :]
void readgametype(MYFILE *f, char *gtname) void readgametype(MYFILE *f, char *gtname)
{ {
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);

View file

@ -169,6 +169,20 @@ static void ignorelines(MYFILE *f)
Z_Free(s); Z_Free(s);
} }
void ignorelinesuntilhash(MYFILE *f)
{
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
do
{
if (myfgets(s, MAXLINELEN, f))
{
if (s[0] == '#')
break;
}
} while (!myfeof(f));
Z_Free(s);
}
static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile) static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
{ {
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
@ -226,13 +240,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
i = 0; i = 0;
if (fastcmp(word, "CHARACTER")) if (fastcmp(word, "CHARACTER"))
{ {
if (i >= 0 && i < 32) readPlayer(f, i);
readPlayer(f, i);
else
{
deh_warning("Character %d out of range (0 - 31)", i);
ignorelines(f);
}
continue; continue;
} }
else if (fastcmp(word, "EMBLEM")) else if (fastcmp(word, "EMBLEM"))

View file

@ -61,4 +61,5 @@ typedef struct
#define myfeof(a) (a->data + a->size <= a->curpos) #define myfeof(a) (a->data + a->size <= a->curpos)
char *myfgets(char *buf, size_t bufsize, MYFILE *f); char *myfgets(char *buf, size_t bufsize, MYFILE *f);
char *myhashfgets(char *buf, size_t bufsize, MYFILE *f); char *myhashfgets(char *buf, size_t bufsize, MYFILE *f);
void ignorelinesuntilhash(MYFILE *f);
#endif #endif

View file

@ -233,9 +233,16 @@ extern char logfilename[1024];
// NOTE: it needs more than this to increase the number of players... // NOTE: it needs more than this to increase the number of players...
#define MAXPLAYERS 32 #define MAXPLAYERS 32
#define MAXSKINS 32
#define PLAYERSMASK (MAXPLAYERS-1)
#define MAXPLAYERNAME 21 #define MAXPLAYERNAME 21
#define PLAYERSMASK (MAXPLAYERS-1)
// Don't make MAXSKINS higher than 256, since skin numbers are used with an
// UINT8 in various parts of the codebase. If you do anyway, the data type
// of those variables will have to be changed into at least an UINT16.
// This change must affect code such as demo recording and playback,
// and the structure of some networking packets and commands.
#define MAXSKINS 256
#define MAXCHARACTERSLOTS (MAXSKINS * 3) // Should be higher than MAXSKINS.
#define COLORRAMPSIZE 16 #define COLORRAMPSIZE 16
#define MAXCOLORNAME 32 #define MAXCOLORNAME 32

View file

@ -1603,9 +1603,9 @@ void F_GameEvaluationDrawer(void)
rtatext = (marathonmode & MA_INGAME) ? "In-game timer" : "RTA timer"; rtatext = (marathonmode & MA_INGAME) ? "In-game timer" : "RTA timer";
cuttext = (marathonmode & MA_NOCUTSCENES) ? "" : " w/ cutscenes"; cuttext = (marathonmode & MA_NOCUTSCENES) ? "" : " w/ cutscenes";
if (botskin) if (botskin)
endingtext = va("%s & %s, %s%s", skins[players[consoleplayer].skin].realname, skins[botskin-1].realname, rtatext, cuttext); endingtext = va("%s & %s, %s%s", skins[players[consoleplayer].skin]->realname, skins[botskin-1]->realname, rtatext, cuttext);
else else
endingtext = va("%s, %s%s", skins[players[consoleplayer].skin].realname, rtatext, cuttext); endingtext = va("%s, %s%s", skins[players[consoleplayer].skin]->realname, rtatext, cuttext);
V_DrawCenteredString(BASEVIDWIDTH/2, 182, V_SNAPTOBOTTOM|(ultimatemode ? V_REDMAP : V_YELLOWMAP), endingtext); V_DrawCenteredString(BASEVIDWIDTH/2, 182, V_SNAPTOBOTTOM|(ultimatemode ? V_REDMAP : V_YELLOWMAP), endingtext);
} }
} }
@ -1719,9 +1719,9 @@ static void F_CacheEnding(void)
UINT8 skinnum = players[consoleplayer].skin; UINT8 skinnum = players[consoleplayer].skin;
spritedef_t *sprdef; spritedef_t *sprdef;
spriteframe_t *sprframe; spriteframe_t *sprframe;
if (skins[skinnum].sprites[SPR2_XTRA].numframes > (XTRA_ENDING+2)) if (skins[skinnum]->sprites[SPR2_XTRA].numframes > (XTRA_ENDING+2))
{ {
sprdef = &skins[skinnum].sprites[SPR2_XTRA]; sprdef = &skins[skinnum]->sprites[SPR2_XTRA];
// character head, skin specific // character head, skin specific
sprframe = &sprdef->spriteframes[XTRA_ENDING]; sprframe = &sprdef->spriteframes[XTRA_ENDING];
endfwrk[0] = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH_LOWPRIORITY); endfwrk[0] = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH_LOWPRIORITY);
@ -2167,7 +2167,7 @@ void F_EndingDrawer(void)
boolean donttouch = false; boolean donttouch = false;
const char *str; const char *str;
if (goodending) if (goodending)
str = va("[S] %s: Engage.", skins[players[consoleplayer].skin].realname); str = va("[S] %s: Engage.", skins[players[consoleplayer].skin]->realname);
else else
str = "[S] Eggman: Abscond."; str = "[S] Eggman: Abscond.";
@ -3554,7 +3554,7 @@ void F_StartContinue(void)
S_ChangeMusicInternal("_conti", false); S_ChangeMusicInternal("_conti", false);
S_StopSounds(); S_StopSounds();
contskins[0] = &skins[players[consoleplayer].skin]; contskins[0] = skins[players[consoleplayer].skin];
cont_spr2[0][0] = P_GetSkinSprite2(contskins[0], SPR2_CNT1, NULL); cont_spr2[0][0] = P_GetSkinSprite2(contskins[0], SPR2_CNT1, NULL);
cont_spr2[0][2] = contskins[0]->contangle & 7; cont_spr2[0][2] = contskins[0]->contangle & 7;
contcolormaps[0] = R_GetTranslationColormap(players[consoleplayer].skin, players[consoleplayer].skincolor, GTC_CACHE); contcolormaps[0] = R_GetTranslationColormap(players[consoleplayer].skin, players[consoleplayer].skincolor, GTC_CACHE);
@ -3570,7 +3570,7 @@ void F_StartContinue(void)
else // HACK else // HACK
secondplaya = 1; secondplaya = 1;
contskins[1] = &skins[players[secondplaya].skin]; contskins[1] = skins[players[secondplaya].skin];
cont_spr2[1][0] = P_GetSkinSprite2(contskins[1], SPR2_CNT4, NULL); cont_spr2[1][0] = P_GetSkinSprite2(contskins[1], SPR2_CNT4, NULL);
cont_spr2[1][2] = (contskins[1]->contangle >> 3) & 7; cont_spr2[1][2] = (contskins[1]->contangle >> 3) & 7;
contcolormaps[1] = R_GetTranslationColormap(players[secondplaya].skin, players[secondplaya].skincolor, GTC_CACHE); contcolormaps[1] = R_GetTranslationColormap(players[secondplaya].skin, players[secondplaya].skincolor, GTC_CACHE);

View file

@ -492,7 +492,7 @@ void G_WriteGhostTic(mobj_t *ghost)
if (ghost->player->followmobj->colorized) if (ghost->player->followmobj->colorized)
followtic |= FZT_COLORIZED; followtic |= FZT_COLORIZED;
if (followtic & FZT_SKIN) if (followtic & FZT_SKIN)
WRITEUINT8(demo_p,(UINT8)(((skin_t *)(ghost->player->followmobj->skin))-skins)); WRITEUINT8(demo_p,(UINT8)(((skin_t *)ghost->player->followmobj->skin)->skinnum));
oldghost.flags2 |= MF2_AMBUSH; oldghost.flags2 |= MF2_AMBUSH;
} }
@ -761,7 +761,7 @@ void G_GhostTicker(void)
g->mo->color = SKINCOLOR_WHITE; g->mo->color = SKINCOLOR_WHITE;
break; break;
case GHC_NIGHTSSKIN: // not actually a colour case GHC_NIGHTSSKIN: // not actually a colour
g->mo->skin = &skins[DEFAULTNIGHTSSKIN]; g->mo->skin = skins[DEFAULTNIGHTSSKIN];
break; break;
} }
} }
@ -1387,7 +1387,7 @@ void G_WriteMetalTic(mobj_t *metal)
if (metal->player->followmobj->colorized) if (metal->player->followmobj->colorized)
followtic |= FZT_COLORIZED; followtic |= FZT_COLORIZED;
if (followtic & FZT_SKIN) if (followtic & FZT_SKIN)
WRITEUINT8(demo_p,(UINT8)(((skin_t *)(metal->player->followmobj->skin))-skins)); WRITEUINT8(demo_p,(UINT8)(((skin_t *)metal->player->followmobj->skin)->skinnum));
oldmetal.flags2 |= MF2_AMBUSH; oldmetal.flags2 |= MF2_AMBUSH;
} }
@ -1540,7 +1540,7 @@ void G_BeginRecording(void)
demo_p += 16; demo_p += 16;
// Skin // Skin
const char *skinname = skins[players[0].skin].name; const char *skinname = skins[players[0].skin]->name;
for (i = 0; i < 16 && skinname[i]; i++) for (i = 0; i < 16 && skinname[i]; i++)
name[i] = skinname[i]; name[i] = skinname[i];
for (; i < 16; i++) for (; i < 16; i++)
@ -2289,7 +2289,7 @@ void G_DoPlayDemo(char *defdemoname)
G_InitNew(false, G_BuildMapName(gamemap), true, true, false); G_InitNew(false, G_BuildMapName(gamemap), true, true, false);
// Set color // Set color
players[0].skincolor = skins[players[0].skin].prefcolor; players[0].skincolor = skins[players[0].skin]->prefcolor;
for (i = 0; i < numskincolors; i++) for (i = 0; i < numskincolors; i++)
if (!stricmp(skincolors[i].name,color)) if (!stricmp(skincolors[i].name,color))
{ {
@ -2609,11 +2609,11 @@ void G_AddGhost(char *defdemoname)
gh->oldmo.z = gh->mo->z; gh->oldmo.z = gh->mo->z;
// Set skin // Set skin
gh->mo->skin = &skins[0]; gh->mo->skin = skins[0];
for (i = 0; i < numskins; i++) for (i = 0; i < numskins; i++)
if (!stricmp(skins[i].name,skin)) if (!stricmp(skins[i]->name,skin))
{ {
gh->mo->skin = &skins[i]; gh->mo->skin = skins[i];
break; break;
} }
gh->oldmo.skin = gh->mo->skin; gh->oldmo.skin = gh->mo->skin;

View file

@ -588,14 +588,14 @@ static void G_SetMainRecords(gamedata_t *data, player_t *player)
I_Error("Out of memory for replay filepath\n"); I_Error("Out of memory for replay filepath\n");
sprintf(gpath,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap)); sprintf(gpath,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap));
snprintf(lastdemo, 255, "%s-%s-last.lmp", gpath, skins[cv_chooseskin.value-1].name); snprintf(lastdemo, 255, "%s-%s-last.lmp", gpath, skins[cv_chooseskin.value-1]->name);
if (FIL_FileExists(lastdemo)) if (FIL_FileExists(lastdemo))
{ {
UINT8 *buf; UINT8 *buf;
size_t len = FIL_ReadFile(lastdemo, &buf); size_t len = FIL_ReadFile(lastdemo, &buf);
snprintf(bestdemo, 255, "%s-%s-time-best.lmp", gpath, skins[cv_chooseskin.value-1].name); snprintf(bestdemo, 255, "%s-%s-time-best.lmp", gpath, skins[cv_chooseskin.value-1]->name);
if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & 1) if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & 1)
{ // Better time, save this demo. { // Better time, save this demo.
if (FIL_FileExists(bestdemo)) if (FIL_FileExists(bestdemo))
@ -604,7 +604,7 @@ static void G_SetMainRecords(gamedata_t *data, player_t *player)
CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW RECORD TIME!"), M_GetText("Saved replay as"), bestdemo); CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW RECORD TIME!"), M_GetText("Saved replay as"), bestdemo);
} }
snprintf(bestdemo, 255, "%s-%s-score-best.lmp", gpath, skins[cv_chooseskin.value-1].name); snprintf(bestdemo, 255, "%s-%s-score-best.lmp", gpath, skins[cv_chooseskin.value-1]->name);
if (!FIL_FileExists(bestdemo) || (G_CmpDemoTime(bestdemo, lastdemo) & (1<<1))) if (!FIL_FileExists(bestdemo) || (G_CmpDemoTime(bestdemo, lastdemo) & (1<<1)))
{ // Better score, save this demo. { // Better score, save this demo.
if (FIL_FileExists(bestdemo)) if (FIL_FileExists(bestdemo))
@ -613,7 +613,7 @@ static void G_SetMainRecords(gamedata_t *data, player_t *player)
CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW HIGH SCORE!"), M_GetText("Saved replay as"), bestdemo); CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW HIGH SCORE!"), M_GetText("Saved replay as"), bestdemo);
} }
snprintf(bestdemo, 255, "%s-%s-rings-best.lmp", gpath, skins[cv_chooseskin.value-1].name); snprintf(bestdemo, 255, "%s-%s-rings-best.lmp", gpath, skins[cv_chooseskin.value-1]->name);
if (!FIL_FileExists(bestdemo) || (G_CmpDemoTime(bestdemo, lastdemo) & (1<<2))) if (!FIL_FileExists(bestdemo) || (G_CmpDemoTime(bestdemo, lastdemo) & (1<<2)))
{ // Better rings, save this demo. { // Better rings, save this demo.
if (FIL_FileExists(bestdemo)) if (FIL_FileExists(bestdemo))
@ -726,14 +726,14 @@ static void G_SetNightsRecords(gamedata_t *data, player_t *player)
I_Error("Out of memory for replay filepath\n"); I_Error("Out of memory for replay filepath\n");
sprintf(gpath,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap)); sprintf(gpath,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap));
snprintf(lastdemo, 255, "%s-%s-last.lmp", gpath, skins[cv_chooseskin.value-1].name); snprintf(lastdemo, 255, "%s-%s-last.lmp", gpath, skins[cv_chooseskin.value-1]->name);
if (FIL_FileExists(lastdemo)) if (FIL_FileExists(lastdemo))
{ {
UINT8 *buf; UINT8 *buf;
size_t len = FIL_ReadFile(lastdemo, &buf); size_t len = FIL_ReadFile(lastdemo, &buf);
snprintf(bestdemo, 255, "%s-%s-time-best.lmp", gpath, skins[cv_chooseskin.value-1].name);; snprintf(bestdemo, 255, "%s-%s-time-best.lmp", gpath, skins[cv_chooseskin.value-1]->name);
if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & 1) if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & 1)
{ // Better time, save this demo. { // Better time, save this demo.
if (FIL_FileExists(bestdemo)) if (FIL_FileExists(bestdemo))
@ -742,7 +742,7 @@ static void G_SetNightsRecords(gamedata_t *data, player_t *player)
CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW RECORD TIME!"), M_GetText("Saved replay as"), bestdemo); CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW RECORD TIME!"), M_GetText("Saved replay as"), bestdemo);
} }
snprintf(bestdemo, 255, "%s-%s-score-best.lmp", gpath, skins[cv_chooseskin.value-1].name); snprintf(bestdemo, 255, "%s-%s-score-best.lmp", gpath, skins[cv_chooseskin.value-1]->name);
if (!FIL_FileExists(bestdemo) || (G_CmpDemoTime(bestdemo, lastdemo) & (1<<1))) if (!FIL_FileExists(bestdemo) || (G_CmpDemoTime(bestdemo, lastdemo) & (1<<1)))
{ // Better score, save this demo. { // Better score, save this demo.
if (FIL_FileExists(bestdemo)) if (FIL_FileExists(bestdemo))
@ -2598,7 +2598,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
UINT8 laps; UINT8 laps;
UINT8 mare; UINT8 mare;
UINT16 skincolor; UINT16 skincolor;
INT32 skin; UINT8 skin;
UINT32 availabilities; UINT32 availabilities;
tic_t jointime; tic_t jointime;
tic_t quittime; tic_t quittime;
@ -5008,7 +5008,7 @@ void G_DeferedInitNew(boolean pultmode, const char *mapname, INT32 character, bo
if (savedata.lives > 0) if (savedata.lives > 0)
{ {
if ((botingame = ((botskin = savedata.botskin) != 0))) if ((botingame = ((botskin = savedata.botskin) != 0)))
botcolor = skins[botskin-1].prefcolor; botcolor = skins[botskin-1]->prefcolor;
} }
else if (splitscreen != SSSG) else if (splitscreen != SSSG)
{ {
@ -5138,7 +5138,7 @@ void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer, boolean
players[consoleplayer].lives = savedata.lives; players[consoleplayer].lives = savedata.lives;
players[consoleplayer].score = savedata.score; players[consoleplayer].score = savedata.score;
if ((botingame = ((botskin = savedata.botskin) != 0))) if ((botingame = ((botskin = savedata.botskin) != 0)))
botcolor = skins[botskin-1].prefcolor; botcolor = skins[botskin-1]->prefcolor;
emeralds = savedata.emeralds; emeralds = savedata.emeralds;
savedata.lives = 0; savedata.lives = 0;
} }

View file

@ -4996,7 +4996,7 @@ static void HWR_DrawSprites(void)
if (spr->mobj && spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) if (spr->mobj && spr->mobj->skin && spr->mobj->sprite == SPR_PLAY)
{ {
if (!cv_glmodels.value || md2_playermodels[(skin_t*)spr->mobj->skin-skins].notfound || md2_playermodels[(skin_t*)spr->mobj->skin-skins].scale < 0.0f) if (!cv_glmodels.value || !md2_playermodels[((skin_t*)spr->mobj->skin)->skinnum].found || md2_playermodels[((skin_t*)spr->mobj->skin)->skinnum].scale < 0.0f)
HWR_DrawSprite(spr); HWR_DrawSprite(spr);
else else
{ {
@ -5006,7 +5006,7 @@ static void HWR_DrawSprites(void)
} }
else else
{ {
if (!cv_glmodels.value || md2_models[spr->mobj->sprite].notfound || md2_models[spr->mobj->sprite].scale < 0.0f) if (!cv_glmodels.value || !md2_models[spr->mobj->sprite].found || md2_models[spr->mobj->sprite].scale < 0.0f)
HWR_DrawSprite(spr); HWR_DrawSprite(spr);
else else
{ {
@ -5183,11 +5183,11 @@ static void HWR_ProjectSprite(mobj_t *thing)
if (cv_glmodels.value) //Yellow: Only MD2's dont disappear if (cv_glmodels.value) //Yellow: Only MD2's dont disappear
{ {
if (thing->skin && thing->sprite == SPR_PLAY) if (thing->skin && thing->sprite == SPR_PLAY)
md2 = &md2_playermodels[( (skin_t *)thing->skin - skins )]; md2 = &md2_playermodels[((skin_t *)thing->skin)->skinnum];
else else
md2 = &md2_models[thing->sprite]; md2 = &md2_models[thing->sprite];
if (md2->notfound || md2->scale < 0.0f) if (!md2->found || md2->scale < 0.0f)
return; return;
} }
else else
@ -5576,8 +5576,8 @@ static void HWR_ProjectSprite(mobj_t *thing)
} }
else if (thing->skin && thing->sprite == SPR_PLAY) // This thing is a player! else if (thing->skin && thing->sprite == SPR_PLAY) // This thing is a player!
{ {
size_t skinnum = (skin_t*)thing->skin-skins; UINT8 skinnum = ((skin_t*)thing->skin)->skinnum;
vis->colormap = R_GetTranslationColormap((INT32)skinnum, vis->color, GTC_CACHE); vis->colormap = R_GetTranslationColormap(skinnum, vis->color, GTC_CACHE);
} }
else else
vis->colormap = R_GetTranslationColormap(TC_DEFAULT, vis->color ? vis->color : SKINCOLOR_CYAN, GTC_CACHE); vis->colormap = R_GetTranslationColormap(TC_DEFAULT, vis->color ? vis->color : SKINCOLOR_CYAN, GTC_CACHE);

View file

@ -35,6 +35,7 @@
#include "../m_misc.h" #include "../m_misc.h"
#include "../w_wad.h" #include "../w_wad.h"
#include "../z_zone.h" #include "../z_zone.h"
#include "../r_state.h"
#include "../r_things.h" #include "../r_things.h"
#include "../r_draw.h" #include "../r_draw.h"
#include "../p_tick.h" #include "../p_tick.h"
@ -72,7 +73,8 @@
#endif #endif
md2_t md2_models[NUMSPRITES]; md2_t md2_models[NUMSPRITES];
md2_t md2_playermodels[MAXSKINS]; md2_t *md2_playermodels = NULL;
size_t md2_numplayermodels = 0;
/* /*
@ -484,24 +486,7 @@ static boolean nomd2s = false;
void HWR_InitModels(void) void HWR_InitModels(void)
{ {
size_t i; size_t i;
INT32 s;
FILE *f;
char name[26], filename[32];
float scale, offset;
size_t prefixlen;
CONS_Printf("HWR_InitModels()...\n");
for (s = 0; s < MAXSKINS; s++)
{
md2_playermodels[s].scale = -1.0f;
md2_playermodels[s].model = NULL;
md2_playermodels[s].grpatch = NULL;
md2_playermodels[s].notexturefile = false;
md2_playermodels[s].noblendfile = false;
md2_playermodels[s].skin = -1;
md2_playermodels[s].notfound = true;
md2_playermodels[s].error = false;
}
for (i = 0; i < NUMSPRITES; i++) for (i = 0; i < NUMSPRITES; i++)
{ {
md2_models[i].scale = -1.0f; md2_models[i].scale = -1.0f;
@ -509,11 +494,48 @@ void HWR_InitModels(void)
md2_models[i].grpatch = NULL; md2_models[i].grpatch = NULL;
md2_models[i].notexturefile = false; md2_models[i].notexturefile = false;
md2_models[i].noblendfile = false; md2_models[i].noblendfile = false;
md2_models[i].skin = -1; md2_models[i].found = false;
md2_models[i].notfound = true;
md2_models[i].error = false; md2_models[i].error = false;
} }
if (numsprites && numskins)
HWR_LoadModels();
}
void HWR_LoadModels(void)
{
size_t i;
INT32 s;
FILE *f;
char name[26], filename[32];
// name[24] is used to check for names in the models.dat file that match with sprites or player skins
// sprite names are always 4 characters long, and names is for player skins can be up to 19 characters long
// PLAYERMODELPREFIX is 6 characters long
float scale, offset;
size_t prefixlen;
if (nomd2s)
return;
// realloc player models table
if (numskins != (INT32)md2_numplayermodels)
{
md2_numplayermodels = (size_t)numskins;
md2_playermodels = Z_Realloc(md2_playermodels, sizeof(md2_t) * md2_numplayermodels, PU_STATIC, NULL);
for (s = 0; s < numskins; s++)
{
md2_playermodels[s].scale = -1.0f;
md2_playermodels[s].model = NULL;
md2_playermodels[s].grpatch = NULL;
md2_playermodels[s].notexturefile = false;
md2_playermodels[s].noblendfile = false;
md2_playermodels[s].found = false;
md2_playermodels[s].error = false;
}
}
// read the models.dat file // read the models.dat file
//Filename checking fixed ~Monster Iestyn and Golden //Filename checking fixed ~Monster Iestyn and Golden
f = fopen(va("%s"PATHSEP"%s", srb2home, "models.dat"), "rt"); f = fopen(va("%s"PATHSEP"%s", srb2home, "models.dat"), "rt");
@ -537,23 +559,24 @@ void HWR_InitModels(void)
char *skinname = name; char *skinname = name;
size_t len = strlen(name); size_t len = strlen(name);
// check for the player model prefix. // Check for the player model prefix.
if (!strnicmp(name, PLAYERMODELPREFIX, prefixlen) && (len > prefixlen)) if (!strnicmp(name, PLAYERMODELPREFIX, prefixlen) && (len > prefixlen))
{ {
skinname += prefixlen; skinname += prefixlen;
goto addskinmodel; goto addskinmodel;
} }
// add sprite model // Add sprite models.
if (len == 4) // must be 4 characters long exactly. otherwise it's not a sprite name. // Must be 4 characters long exactly. Otherwise, it's not a sprite name.
if (len == 4)
{ {
for (i = 0; i < NUMSPRITES; i++) 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].scale = scale;
md2_models[i].offset = offset; md2_models[i].offset = offset;
md2_models[i].notfound = false; md2_models[i].found = true;
strcpy(md2_models[i].filename, filename); strcpy(md2_models[i].filename, filename);
goto modelfound; goto modelfound;
} }
@ -561,137 +584,24 @@ void HWR_InitModels(void)
} }
addskinmodel: addskinmodel:
// add player model // Add player models.
for (s = 0; s < MAXSKINS; s++) for (s = 0; s < numskins; s++)
{ {
if (stricmp(skinname, skins[s].name) == 0) if (stricmp(skinname, skins[s]->name) == 0)
{ {
md2_playermodels[s].skin = s;
md2_playermodels[s].scale = scale; md2_playermodels[s].scale = scale;
md2_playermodels[s].offset = offset; md2_playermodels[s].offset = offset;
md2_playermodels[s].notfound = false; md2_playermodels[s].found = true;
strcpy(md2_playermodels[s].filename, filename); strcpy(md2_playermodels[s].filename, filename);
goto modelfound; goto modelfound;
} }
} }
modelfound: modelfound:
// move on to next line... // Move on to the next line...
continue; continue;
} }
fclose(f);
}
void HWR_AddPlayerModel(int skin) // For skins that were added after startup
{
FILE *f;
char name[26], filename[32];
float scale, offset;
size_t prefixlen;
if (nomd2s)
return;
//CONS_Printf("HWR_AddPlayerModel()...\n");
// read the models.dat file
//Filename checking fixed ~Monster Iestyn and Golden
f = fopen(va("%s"PATHSEP"%s", srb2home, "models.dat"), "rt");
if (!f)
{
f = fopen(va("%s"PATHSEP"%s", srb2path, "models.dat"), "rt");
if (!f)
{
CONS_Printf("%s %s\n", M_GetText("Error while loading models.dat:"), strerror(errno));
nomd2s = true;
return;
}
}
// length of the player model prefix
prefixlen = strlen(PLAYERMODELPREFIX);
// Check for any models that match the names of player skins!
while (fscanf(f, "%25s %31s %f %f", name, filename, &scale, &offset) == 4)
{
char *skinname = name;
size_t len = strlen(name);
// ignore the player model prefix.
if (!strnicmp(name, PLAYERMODELPREFIX, prefixlen) && (len > prefixlen))
skinname += prefixlen;
if (stricmp(skinname, skins[skin].name) == 0)
{
md2_playermodels[skin].skin = skin;
md2_playermodels[skin].scale = scale;
md2_playermodels[skin].offset = offset;
md2_playermodels[skin].notfound = false;
strcpy(md2_playermodels[skin].filename, filename);
goto playermodelfound;
}
}
md2_playermodels[skin].notfound = true;
playermodelfound:
fclose(f);
}
void HWR_AddSpriteModel(size_t spritenum) // For sprites that were added after startup
{
FILE *f;
// name[24] is used to check for names in the models.dat file that match with sprites or player skins
// sprite names are always 4 characters long, and names is for player skins can be up to 19 characters long
// PLAYERMODELPREFIX is 6 characters long
char name[26], filename[32];
float scale, offset;
if (nomd2s)
return;
if (spritenum == SPR_PLAY) // Handled already NEWMD2: Per sprite, per-skin check
return;
// Read the models.dat file
//Filename checking fixed ~Monster Iestyn and Golden
f = fopen(va("%s"PATHSEP"%s", srb2home, "models.dat"), "rt");
if (!f)
{
f = fopen(va("%s"PATHSEP"%s", srb2path, "models.dat"), "rt");
if (!f)
{
CONS_Printf("%s %s\n", M_GetText("Error while loading models.dat:"), strerror(errno));
nomd2s = true;
return;
}
}
// Check for any models that match the names of sprite names!
while (fscanf(f, "%25s %31s %f %f", name, filename, &scale, &offset) == 4)
{
// length of the sprite name
size_t len = strlen(name);
if (len != 4) // must be 4 characters long exactly. otherwise it's not a sprite name.
continue;
// check for the player model prefix.
if (!strnicmp(name, PLAYERMODELPREFIX, strlen(PLAYERMODELPREFIX)))
continue; // that's not a sprite...
if (stricmp(name, sprnames[spritenum]) == 0)
{
md2_models[spritenum].scale = scale;
md2_models[spritenum].offset = offset;
md2_models[spritenum].notfound = false;
strcpy(md2_models[spritenum].filename, filename);
goto spritemodelfound;
}
}
md2_models[spritenum].notfound = true;
spritemodelfound:
fclose(f); fclose(f);
} }
@ -1380,8 +1290,8 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
// 2. draw model with correct position, rotation,... // 2. draw model with correct position, rotation,...
if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) // Use the player MD2 list if the mobj has a skin and is using the player sprites if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) // Use the player MD2 list if the mobj has a skin and is using the player sprites
{ {
md2 = &md2_playermodels[(skin_t*)spr->mobj->skin-skins]; UINT8 skinnum = ((skin_t*)spr->mobj->skin)->skinnum;
md2->skin = (skin_t*)spr->mobj->skin-skins; md2 = &md2_playermodels[skinnum];
} }
else else
{ {
@ -1476,7 +1386,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
skinnum = TC_RAINBOW; skinnum = TC_RAINBOW;
} }
else if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) else if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY)
skinnum = (INT32)((skin_t*)spr->mobj->skin-skins); skinnum = ((skin_t*)spr->mobj->skin)->skinnum;
else else
skinnum = TC_DEFAULT; skinnum = TC_DEFAULT;
} }

View file

@ -31,17 +31,17 @@ typedef struct
boolean notexturefile; // true if texture file was not found boolean notexturefile; // true if texture file was not found
void *blendgrpatch; void *blendgrpatch;
boolean noblendfile; // true if blend texture file was not found boolean noblendfile; // true if blend texture file was not found
boolean notfound; boolean found;
INT32 skin;
boolean error; boolean error;
} md2_t; } md2_t;
extern md2_t md2_models[NUMSPRITES]; extern md2_t md2_models[NUMSPRITES];
extern md2_t md2_playermodels[MAXSKINS]; extern md2_t *md2_playermodels;
extern size_t md2_numplayermodels;
void HWR_InitModels(void); void HWR_InitModels(void);
void HWR_AddPlayerModel(INT32 skin); void HWR_LoadModels(void);
void HWR_AddSpriteModel(size_t spritenum);
boolean HWR_DrawModel(gl_vissprite_t *spr); boolean HWR_DrawModel(gl_vissprite_t *spr);
#define PLAYERMODELPREFIX "PLAYER" #define PLAYERMODELPREFIX "PLAYER"

View file

@ -328,8 +328,8 @@ model_t *MD2_LoadModel(const char *fileName, int ztag, boolean useFloat)
texcoords = (md2texcoord_t*)&buffer[header->offsetST]; texcoords = (md2texcoord_t*)&buffer[header->offsetST];
frames = (md2frame_t*)&buffer[header->offsetFrames]; frames = (md2frame_t*)&buffer[header->offsetFrames];
retModel->framenames = (char*)Z_Calloc(header->numFrames*16, ztag, 0); retModel->frameNames = (char*)Z_Calloc(header->numFrames*16, ztag, 0);
fname = retModel->framenames; fname = retModel->frameNames;
for (i = 0; i < header->numFrames; i++) for (i = 0; i < header->numFrames; i++)
{ {
md2frame_t *fr = (md2frame_t*)&buffer[header->offsetFrames + foffset]; md2frame_t *fr = (md2frame_t*)&buffer[header->offsetFrames + foffset];

View file

@ -230,8 +230,8 @@ model_t *MD3_LoadModel(const char *fileName, int ztag, boolean useFloat)
retModel->meshes = (mesh_t*)Z_Calloc(sizeof(mesh_t)*retModel->numMeshes, ztag, 0); retModel->meshes = (mesh_t*)Z_Calloc(sizeof(mesh_t)*retModel->numMeshes, ztag, 0);
frames = (md3Frame*)&buffer[mdh->offsetFrames]; frames = (md3Frame*)&buffer[mdh->offsetFrames];
retModel->framenames = (char*)Z_Calloc(mdh->numFrames*16, ztag, 0); retModel->frameNames = (char*)Z_Calloc(mdh->numFrames*16, ztag, 0);
fname = retModel->framenames; fname = retModel->frameNames;
for (i = 0; i < mdh->numFrames; i++) for (i = 0; i < mdh->numFrames; i++)
{ {
memcpy(fname, frames->name, 16); memcpy(fname, frames->name, 16);

View file

@ -10,6 +10,8 @@
#include "../doomdef.h" #include "../doomdef.h"
#include "../doomtype.h" #include "../doomtype.h"
#include "../info.h" #include "../info.h"
#include "../r_skins.h"
#include "../r_state.h"
#include "../z_zone.h" #include "../z_zone.h"
#include "hw_model.h" #include "hw_model.h"
#include "hw_md2load.h" #include "hw_md2load.h"
@ -141,9 +143,7 @@ tag_t *GetTagByName(model_t *model, char *name, int frame)
// //
// LoadModel // LoadModel
// //
// Load a model and // Load a model and convert it to the internal format.
// convert it to the
// internal format.
// //
model_t *LoadModel(const char *filename, int ztag) model_t *LoadModel(const char *filename, int ztag)
{ {
@ -193,9 +193,6 @@ model_t *LoadModel(const char *filename, int ztag)
return NULL; return NULL;
} }
model->mdlFilename = (char*)Z_Malloc(strlen(filename)+1, ztag, 0);
strcpy(model->mdlFilename, filename);
Optimize(model); Optimize(model);
GeneratePolygonNormals(model, ztag); GeneratePolygonNormals(model, ztag);
LoadModelSprite2(model); LoadModelSprite2(model);
@ -236,15 +233,16 @@ model_t *LoadModel(const char *filename, int ztag)
void HWR_ReloadModels(void) void HWR_ReloadModels(void)
{ {
size_t i; size_t i;
INT32 s;
for (s = 0; s < MAXSKINS; s++) HWR_LoadModels();
for (i = 0; i < md2_numplayermodels; i++)
{ {
if (md2_playermodels[s].model) if (md2_playermodels[i].model)
LoadModelSprite2(md2_playermodels[s].model); LoadModelSprite2(md2_playermodels[i].model);
} }
for (i = 0; i < NUMSPRITES; i++) for (i = 0; i < numsprites; i++)
{ {
if (md2_models[i].model) if (md2_models[i].model)
LoadModelInterpolationSettings(md2_models[i].model); LoadModelInterpolationSettings(md2_models[i].model);
@ -255,7 +253,7 @@ void LoadModelInterpolationSettings(model_t *model)
{ {
INT32 i; INT32 i;
INT32 numframes = model->meshes[0].numFrames; INT32 numframes = model->meshes[0].numFrames;
char *framename = model->framenames; char *framename = model->frameNames;
if (!framename) if (!framename)
return; return;
@ -295,7 +293,7 @@ void LoadModelSprite2(model_t *model)
INT32 i; INT32 i;
modelspr2frames_t *spr2frames = NULL; modelspr2frames_t *spr2frames = NULL;
INT32 numframes = model->meshes[0].numFrames; INT32 numframes = model->meshes[0].numFrames;
char *framename = model->framenames; char *framename = model->frameNames;
if (!framename) if (!framename)
return; return;

View file

@ -91,17 +91,14 @@ typedef struct model_s
{ {
int maxNumFrames; int maxNumFrames;
int numMaterials;
material_t *materials;
int numMeshes; int numMeshes;
mesh_t *meshes; mesh_t *meshes;
int numMaterials;
material_t *materials;
int numTags; int numTags;
tag_t *tags; tag_t *tags;
char *mdlFilename; char *frameNames;
boolean unloaded;
char *framenames;
boolean interpolate[256]; boolean interpolate[256];
modelspr2frames_t *spr2frames; modelspr2frames_t *spr2frames;

View file

@ -2116,7 +2116,7 @@ void HU_Erase(void)
// IN-LEVEL MULTIPLAYER RANKINGS // IN-LEVEL MULTIPLAYER RANKINGS
//====================================================================== //======================================================================
#define supercheckdef (!(players[tab[i].num].charflags & SF_NOSUPERSPRITES) && ((players[tab[i].num].powers[pw_super] && players[tab[i].num].mo && (players[tab[i].num].mo->state < &states[S_PLAY_SUPER_TRANS1] || players[tab[i].num].mo->state >= &states[S_PLAY_SUPER_TRANS6])) || (players[tab[i].num].powers[pw_carry] == CR_NIGHTSMODE && skins[players[tab[i].num].skin].flags & SF_SUPER))) #define supercheckdef (!(players[tab[i].num].charflags & SF_NOSUPERSPRITES) && ((players[tab[i].num].powers[pw_super] && players[tab[i].num].mo && (players[tab[i].num].mo->state < &states[S_PLAY_SUPER_TRANS1] || players[tab[i].num].mo->state >= &states[S_PLAY_SUPER_TRANS6])) || (players[tab[i].num].powers[pw_carry] == CR_NIGHTSMODE && skins[players[tab[i].num].skin]->flags & SF_SUPER)))
#define greycheckdef (players[tab[i].num].spectator || players[tab[i].num].playerstate == PST_DEAD || (G_IsSpecialStage(gamemap) && players[tab[i].num].exiting)) #define greycheckdef (players[tab[i].num].spectator || players[tab[i].num].playerstate == PST_DEAD || (G_IsSpecialStage(gamemap) && players[tab[i].num].exiting))
// //

View file

@ -3764,10 +3764,10 @@ static int lib_gAddPlayer(lua_State *L)
if (!lua_isnoneornil(L, 2)) if (!lua_isnoneornil(L, 2))
newplayer->skincolor = R_GetColorByName(luaL_checkstring(L, 2)); newplayer->skincolor = R_GetColorByName(luaL_checkstring(L, 2));
else else
newplayer->skincolor = skins[skinnum].prefcolor; newplayer->skincolor = skins[skinnum]->prefcolor;
// Set the bot default name as the skin // Set the bot default name as the skin
strcpy(player_names[newplayernum], skins[skinnum].realname); strcpy(player_names[newplayernum], skins[skinnum]->realname);
// Read the bot name, if given // Read the bot name, if given
if (!lua_isnoneornil(L, 3)) if (!lua_isnoneornil(L, 3))

View file

@ -557,7 +557,7 @@ static int libd_getSprite2Patch(lua_State *L)
{ {
const char *name = luaL_checkstring(L, 1); const char *name = luaL_checkstring(L, 1);
for (i = 0; i < numskins; i++) for (i = 0; i < numskins; i++)
if (fastcmp(skins[i].name, name)) if (fastcmp(skins[i]->name, name))
break; break;
if (i >= numskins) if (i >= numskins)
return 0; return 0;
@ -599,9 +599,9 @@ static int libd_getSprite2Patch(lua_State *L)
if (super) if (super)
j |= FF_SPR2SUPER; j |= FF_SPR2SUPER;
j = P_GetSkinSprite2(&skins[i], j, NULL); // feed skin and current sprite2 through to change sprite2 used if necessary 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 = &skins[i]->sprites[j];
// set frame number // set frame number
frame = luaL_optinteger(L, 2, 0); frame = luaL_optinteger(L, 2, 0);
@ -629,7 +629,7 @@ static int libd_getSprite2Patch(lua_State *L)
INT32 rot = R_GetRollAngle(rollangle); INT32 rot = R_GetRollAngle(rollangle);
if (rot) { 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), &skins[i]->sprinfo[j], rot);
LUA_PushUserdata(L, rotsprite, META_PATCH); LUA_PushUserdata(L, rotsprite, META_PATCH);
lua_pushboolean(L, false); lua_pushboolean(L, false);
lua_pushboolean(L, true); lua_pushboolean(L, true);

View file

@ -30,9 +30,6 @@
#include "lua_hud.h" // hud_running errors #include "lua_hud.h" // hud_running errors
#include "lua_hook.h" // hook_cmd_running errors #include "lua_hook.h" // hook_cmd_running errors
extern CV_PossibleValue_t Color_cons_t[];
extern UINT8 skincolor_modified[];
boolean LUA_CallAction(enum actionnum actionnum, mobj_t *actor); boolean LUA_CallAction(enum actionnum actionnum, mobj_t *actor);
state_t *astate; state_t *astate;

View file

@ -679,10 +679,10 @@ static int mobj_set(lua_State *L)
strlcpy(skin, luaL_checkstring(L, 3), sizeof skin); strlcpy(skin, luaL_checkstring(L, 3), sizeof skin);
strlwr(skin); // all skin names are lowercase strlwr(skin); // all skin names are lowercase
for (i = 0; i < numskins; i++) for (i = 0; i < numskins; i++)
if (fastcmp(skins[i].name, skin)) if (fastcmp(skins[i]->name, skin))
{ {
if (!mo->player || R_SkinUsable(mo->player-players, i)) if (!mo->player || R_SkinUsable(mo->player-players, i))
mo->skin = &skins[i]; mo->skin = skins[i];
return 0; return 0;
} }
return luaL_error(L, "mobj.skin '%s' not found!", skin); return luaL_error(L, "mobj.skin '%s' not found!", skin);

View file

@ -1396,7 +1396,7 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
skin_t *skin = *((skin_t **)lua_touserdata(gL, myindex)); skin_t *skin = *((skin_t **)lua_touserdata(gL, myindex));
WRITEUINT8(save_p, ARCH_SKIN); WRITEUINT8(save_p, ARCH_SKIN);
WRITEUINT8(save_p, skin - skins); // UINT8 because MAXSKINS is only 32 WRITEUINT8(save_p, skin->skinnum); // UINT8 because MAXSKINS must be <= 256
break; break;
} }
default: default:

View file

@ -234,7 +234,7 @@ static int skin_num(lua_State *L)
// skins are always valid, only added, never removed // skins are always valid, only added, never removed
I_Assert(skin != NULL); I_Assert(skin != NULL);
lua_pushinteger(L, skin-skins); lua_pushinteger(L, skin->skinnum);
return 1; return 1;
} }
@ -253,14 +253,14 @@ static int lib_iterateSkins(lua_State *L)
lua_remove(L, 1); // state is unused. lua_remove(L, 1); // state is unused.
if (!lua_isnil(L, 1)) if (!lua_isnil(L, 1))
i = (INT32)(*((skin_t **)luaL_checkudata(L, 1, META_SKIN)) - skins) + 1; i = (INT32)((*((skin_t **)luaL_checkudata(L, 1, META_SKIN)))->skinnum) + 1;
else else
i = 0; i = 0;
// skins are always valid, only added, never removed // skins are always valid, only added, never removed
if (i < numskins) if (i < numskins)
{ {
LUA_PushUserdata(L, &skins[i], META_SKIN); LUA_PushUserdata(L, skins[i], META_SKIN);
return 1; return 1;
} }
@ -280,7 +280,7 @@ static int lib_getSkin(lua_State *L)
return luaL_error(L, "skins[] index %d out of range (0 - %d)", i, MAXSKINS-1); return luaL_error(L, "skins[] index %d out of range (0 - %d)", i, MAXSKINS-1);
if (i >= numskins) if (i >= numskins)
return 0; return 0;
LUA_PushUserdata(L, &skins[i], META_SKIN); LUA_PushUserdata(L, skins[i], META_SKIN);
return 1; return 1;
} }
@ -295,9 +295,9 @@ static int lib_getSkin(lua_State *L)
// find skin by name // find skin by name
for (i = 0; i < numskins; i++) for (i = 0; i < numskins; i++)
if (fastcmp(skins[i].name, field)) if (fastcmp(skins[i]->name, field))
{ {
LUA_PushUserdata(L, &skins[i], META_SKIN); LUA_PushUserdata(L, skins[i], META_SKIN);
return 1; return 1;
} }

View file

@ -132,7 +132,9 @@ M_waiting_mode_t m_waiting_mode = M_NOT_WAITING;
const char *quitmsg[NUM_QUITMESSAGES]; const char *quitmsg[NUM_QUITMESSAGES];
// Stuff for customizing the player select screen Tails 09-22-2003 // Stuff for customizing the player select screen Tails 09-22-2003
description_t description[MAXSKINS]; description_t *description = NULL;
INT32 numdescriptions = 0;
INT16 char_on = -1, startchar = 0; INT16 char_on = -1, startchar = 0;
static char *char_notes = NULL; static char *char_notes = NULL;
@ -258,7 +260,7 @@ static void M_ConfirmTeamScramble(INT32 choice);
static void M_ConfirmTeamChange(INT32 choice); static void M_ConfirmTeamChange(INT32 choice);
static void M_SecretsMenu(INT32 choice); static void M_SecretsMenu(INT32 choice);
static void M_SetupChoosePlayer(INT32 choice); static void M_SetupChoosePlayer(INT32 choice);
static UINT8 M_SetupChoosePlayerDirect(INT32 choice); static UINT16 M_SetupChoosePlayerDirect(INT32 choice);
static void M_QuitSRB2(INT32 choice); static void M_QuitSRB2(INT32 choice);
menu_t SP_MainDef, OP_MainDef; menu_t SP_MainDef, OP_MainDef;
menu_t MISC_ScrambleTeamDef, MISC_ChangeTeamDef; menu_t MISC_ScrambleTeamDef, MISC_ChangeTeamDef;
@ -2258,7 +2260,7 @@ void Nextmap_OnChange(void)
SP_NightsAttackMenu[naghost].status = IT_DISABLED; SP_NightsAttackMenu[naghost].status = IT_DISABLED;
// Check if file exists, if not, disable REPLAY option // Check if file exists, if not, disable REPLAY option
sprintf(tabase,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s",srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), skins[cv_chooseskin.value-1].name); sprintf(tabase,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s",srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), skins[cv_chooseskin.value-1]->name);
#ifdef OLDNREPLAYNAME #ifdef OLDNREPLAYNAME
sprintf(tabaseold,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s",srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value)); sprintf(tabaseold,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s",srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value));
@ -2329,7 +2331,7 @@ void Nextmap_OnChange(void)
SP_TimeAttackMenu[taghost].status = IT_DISABLED; SP_TimeAttackMenu[taghost].status = IT_DISABLED;
// Check if file exists, if not, disable REPLAY option // Check if file exists, if not, disable REPLAY option
sprintf(tabase,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s",srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), skins[cv_chooseskin.value-1].name); sprintf(tabase,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s",srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), skins[cv_chooseskin.value-1]->name);
for (i = 0; i < 5; i++) { for (i = 0; i < 5; i++) {
SP_ReplayMenu[i].status = IT_DISABLED; SP_ReplayMenu[i].status = IT_DISABLED;
SP_GuestReplayMenu[i].status = IT_DISABLED; SP_GuestReplayMenu[i].status = IT_DISABLED;
@ -3029,7 +3031,7 @@ static void M_ChangeCvar(INT32 choice)
{ {
SINT8 skinno = R_SkinAvailable(cv_chooseskin.string); SINT8 skinno = R_SkinAvailable(cv_chooseskin.string);
if (skinno != -1) if (skinno != -1)
CV_SetValue(cv,skins[skinno].prefcolor); CV_SetValue(cv,skins[skinno]->prefcolor);
return; return;
} }
CV_Set(cv,cv->defaultvalue); CV_Set(cv,cv->defaultvalue);
@ -3936,24 +3938,32 @@ void M_Init(void)
CV_RegisterVar(&cv_serversort); CV_RegisterVar(&cv_serversort);
} }
void M_InitCharacterTables(void) static void M_InitCharacterDescription(INT32 i)
{ {
UINT8 i;
// Setup description table // Setup description table
for (i = 0; i < MAXSKINS; i++) description_t *desc = &description[i];
{ desc->picname[0] = '\0';
description[i].used = false; desc->nametag[0] = '\0';
strcpy(description[i].notes, "???"); desc->skinname[0] = '\0';
strcpy(description[i].picname, ""); desc->displayname[0] = '\0';
strcpy(description[i].nametag, ""); desc->prev = desc->next = 0;
strcpy(description[i].skinname, ""); desc->charpic = NULL;
strcpy(description[i].displayname, ""); desc->namepic = NULL;
description[i].prev = description[i].next = 0; desc->oppositecolor = SKINCOLOR_NONE;
description[i].charpic = NULL; desc->tagtextcolor = SKINCOLOR_NONE;
description[i].namepic = NULL; desc->tagoutlinecolor = SKINCOLOR_NONE;
description[i].oppositecolor = description[i].tagtextcolor = description[i].tagoutlinecolor = 0; strcpy(desc->notes, "???");
} }
void M_InitCharacterTables(INT32 num)
{
INT32 i = numdescriptions;
description = Z_Realloc(description, sizeof(description_t) * num, PU_STATIC, NULL);
numdescriptions = num;
for (; i < numdescriptions; i++)
M_InitCharacterDescription(i);
} }
// ========================================================================== // ==========================================================================
@ -5014,9 +5024,9 @@ static void M_PatchSkinNameTable(void)
for (j = 0; j < MAXSKINS; j++) for (j = 0; j < MAXSKINS; j++)
{ {
if (skins[j].name[0] != '\0' && R_SkinUsable(-1, j)) if (j < numskins && skins[j]->name[0] != '\0' && R_SkinUsable(-1, j))
{ {
skins_cons_t[j].strvalue = skins[j].realname; skins_cons_t[j].strvalue = skins[j]->realname;
skins_cons_t[j].value = j+1; skins_cons_t[j].value = j+1;
} }
else else
@ -8492,7 +8502,7 @@ static void M_DrawLoadGameData(void)
savetodraw--; savetodraw--;
if (savegameinfo[savetodraw].lives != 0) if (savegameinfo[savetodraw].lives != 0)
charskin = &skins[savegameinfo[savetodraw].skinnum]; charskin = skins[savegameinfo[savetodraw].skinnum];
// signpost background // signpost background
{ {
@ -8626,7 +8636,7 @@ static void M_DrawLoadGameData(void)
// botskin first // botskin first
if (savegameinfo[savetodraw].botskin) if (savegameinfo[savetodraw].botskin)
{ {
skin_t *charbotskin = &skins[savegameinfo[savetodraw].botskin-1]; skin_t *charbotskin = skins[savegameinfo[savetodraw].botskin-1];
sprdef = &charbotskin->sprites[SPR2_SIGN]; sprdef = &charbotskin->sprites[SPR2_SIGN];
if (!sprdef->numframes) if (!sprdef->numframes)
goto skipbot; goto skipbot;
@ -9205,9 +9215,9 @@ static void M_CacheCharacterSelectEntry(INT32 i, INT32 skinnum)
{ {
if (!(description[i].picname[0])) if (!(description[i].picname[0]))
{ {
if (skins[skinnum].sprites[SPR2_XTRA].numframes > XTRA_CHARSEL) if (skins[skinnum]->sprites[SPR2_XTRA].numframes > XTRA_CHARSEL)
{ {
spritedef_t *sprdef = &skins[skinnum].sprites[SPR2_XTRA]; spritedef_t *sprdef = &skins[skinnum]->sprites[SPR2_XTRA];
spriteframe_t *sprframe = &sprdef->spriteframes[XTRA_CHARSEL]; spriteframe_t *sprframe = &sprdef->spriteframes[XTRA_CHARSEL];
description[i].charpic = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH); description[i].charpic = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH);
} }
@ -9221,71 +9231,74 @@ static void M_CacheCharacterSelectEntry(INT32 i, INT32 skinnum)
description[i].namepic = W_CachePatchName(description[i].nametag, PU_PATCH); description[i].namepic = W_CachePatchName(description[i].nametag, PU_PATCH);
} }
static UINT8 M_SetupChoosePlayerDirect(INT32 choice) static UINT16 M_SetupChoosePlayerDirect(INT32 choice)
{ {
INT32 skinnum, botskinnum; INT32 skinnum, botskinnum;
UINT8 i; UINT16 i;
UINT8 firstvalid = 255, lastvalid = 255; INT32 firstvalid = INT32_MAX, lastvalid = INT32_MAX;
boolean allowed = false; boolean allowed = false;
char *and;
(void)choice; (void)choice;
if (!mapheaderinfo[startmap-1] || mapheaderinfo[startmap-1]->forcecharacter[0] == '\0') if (!mapheaderinfo[startmap-1] || mapheaderinfo[startmap-1]->forcecharacter[0] == '\0')
{ {
for (i = 0; i < MAXSKINS; i++) // Handle charsels, availability, and unlocks. for (i = 0; i < numdescriptions; i++) // Handle charsels, availability, and unlocks.
{ {
if (description[i].used) // If the character's disabled through SOC, there's nothing we can do for it. char *and;
// If the character's disabled through SOC, there's nothing we can do for it.
if (!description[i].used)
continue;
and = strchr(description[i].skinname, '&');
if (and)
{ {
and = strchr(description[i].skinname, '&'); char firstskin[SKINNAMESIZE+1];
if (and) if (mapheaderinfo[startmap-1] && mapheaderinfo[startmap-1]->typeoflevel & TOL_NIGHTS) // skip tagteam characters for NiGHTS levels
continue;
strncpy(firstskin, description[i].skinname, (and - description[i].skinname));
firstskin[(and - description[i].skinname)] = '\0';
description[i].skinnum[0] = R_SkinAvailable(firstskin);
description[i].skinnum[1] = R_SkinAvailable(and+1);
}
else
{
description[i].skinnum[0] = R_SkinAvailable(description[i].skinname);
description[i].skinnum[1] = -1;
}
skinnum = description[i].skinnum[0];
if ((skinnum != -1) && (R_SkinUsable(-1, skinnum)))
{
botskinnum = description[i].skinnum[1];
if ((botskinnum != -1) && (!R_SkinUsable(-1, botskinnum)))
{ {
char firstskin[SKINNAMESIZE+1]; // Bot skin isn't unlocked
if (mapheaderinfo[startmap-1] && mapheaderinfo[startmap-1]->typeoflevel & TOL_NIGHTS) // skip tagteam characters for NiGHTS levels continue;
continue;
strncpy(firstskin, description[i].skinname, (and - description[i].skinname));
firstskin[(and - description[i].skinname)] = '\0';
description[i].skinnum[0] = R_SkinAvailable(firstskin);
description[i].skinnum[1] = R_SkinAvailable(and+1);
} }
// Handling order.
if (firstvalid == INT32_MAX)
firstvalid = i;
else else
{ {
description[i].skinnum[0] = R_SkinAvailable(description[i].skinname); description[i].prev = lastvalid;
description[i].skinnum[1] = -1; description[lastvalid].next = i;
} }
skinnum = description[i].skinnum[0]; lastvalid = i;
if ((skinnum != -1) && (R_SkinUsable(-1, skinnum)))
{
botskinnum = description[i].skinnum[1];
if ((botskinnum != -1) && (!R_SkinUsable(-1, botskinnum)))
{
// Bot skin isn't unlocked
continue;
}
// Handling order. if (i == char_on)
if (firstvalid == 255) allowed = true;
firstvalid = i;
else
{
description[i].prev = lastvalid;
description[lastvalid].next = i;
}
lastvalid = i;
if (i == char_on) M_CacheCharacterSelectEntry(i, skinnum);
allowed = true;
M_CacheCharacterSelectEntry(i, skinnum);
}
// else -- Technically, character select icons without corresponding skins get bundled away behind this too. Sucks to be them.
} }
// else -- Technically, character select icons without corresponding skins get bundled away behind this too. Sucks to be them.
} }
} }
if (firstvalid == lastvalid) // We're being forced into a specific character, so might as well just skip it. if (firstvalid == lastvalid) // We're being forced into a specific character, so might as well just skip it.
{
return firstvalid; return firstvalid;
}
// One last bit of order we can't do in the iteration above. // One last bit of order we can't do in the iteration above.
description[firstvalid].prev = lastvalid; description[firstvalid].prev = lastvalid;
@ -9294,7 +9307,7 @@ static UINT8 M_SetupChoosePlayerDirect(INT32 choice)
if (!allowed) if (!allowed)
{ {
char_on = firstvalid; char_on = firstvalid;
if (startchar > 0 && startchar < MAXSKINS) if (startchar > 0 && startchar < numdescriptions)
{ {
INT16 workchar = startchar; INT16 workchar = startchar;
while (workchar--) while (workchar--)
@ -9302,13 +9315,13 @@ static UINT8 M_SetupChoosePlayerDirect(INT32 choice)
} }
} }
return MAXSKINS; return MAXCHARACTERSLOTS;
} }
static void M_SetupChoosePlayer(INT32 choice) static void M_SetupChoosePlayer(INT32 choice)
{ {
UINT8 skinset = M_SetupChoosePlayerDirect(choice); UINT16 skinset = M_SetupChoosePlayerDirect(choice);
if (skinset != MAXSKINS) if (skinset != MAXCHARACTERSLOTS)
{ {
M_ChoosePlayer(skinset); M_ChoosePlayer(skinset);
return; return;
@ -9419,7 +9432,7 @@ static void M_DrawSetupChoosePlayerMenu(void)
{ {
const INT32 my = 16; const INT32 my = 16;
skin_t *charskin = &skins[0]; skin_t *charskin = skins[0];
INT32 skinnum = 0; INT32 skinnum = 0;
UINT16 col; UINT16 col;
UINT8 *colormap = NULL; UINT8 *colormap = NULL;
@ -9451,7 +9464,7 @@ static void M_DrawSetupChoosePlayerMenu(void)
// Find skin number from description[] // Find skin number from description[]
skinnum = description[char_on].skinnum[0]; skinnum = description[char_on].skinnum[0];
charskin = &skins[skinnum]; charskin = skins[skinnum];
// Use the opposite of the character's skincolor // Use the opposite of the character's skincolor
col = description[char_on].oppositecolor; col = description[char_on].oppositecolor;
@ -9554,7 +9567,7 @@ static void M_DrawSetupChoosePlayerMenu(void)
prevoutlinecolor = description[prev].tagoutlinecolor; prevoutlinecolor = description[prev].tagoutlinecolor;
if (prevtext[0] == '\0') if (prevtext[0] == '\0')
prevpatch = description[prev].namepic; prevpatch = description[prev].namepic;
charskin = &skins[description[prev].skinnum[0]]; charskin = skins[description[prev].skinnum[0]];
if (!prevtextcolor) if (!prevtextcolor)
prevtextcolor = charskin->prefcolor; prevtextcolor = charskin->prefcolor;
if (!prevoutlinecolor) if (!prevoutlinecolor)
@ -9584,7 +9597,7 @@ static void M_DrawSetupChoosePlayerMenu(void)
nextoutlinecolor = description[next].tagoutlinecolor; nextoutlinecolor = description[next].tagoutlinecolor;
if (nexttext[0] == '\0') if (nexttext[0] == '\0')
nextpatch = description[next].namepic; nextpatch = description[next].namepic;
charskin = &skins[description[next].skinnum[0]]; charskin = skins[description[next].skinnum[0]];
if (!nexttextcolor) if (!nexttextcolor)
nexttextcolor = charskin->prefcolor; nexttextcolor = charskin->prefcolor;
if (!nextoutlinecolor) if (!nextoutlinecolor)
@ -9629,7 +9642,7 @@ static void M_ChoosePlayer(INT32 choice)
UINT8 skinnum; UINT8 skinnum;
// skip this if forcecharacter or no characters available // skip this if forcecharacter or no characters available
if (choice == 255) if (choice == INT32_MAX)
{ {
skinnum = botskin = 0; skinnum = botskin = 0;
botingame = false; botingame = false;
@ -9642,7 +9655,7 @@ static void M_ChoosePlayer(INT32 choice)
if ((botingame = (description[choice].skinnum[1] != -1))) { if ((botingame = (description[choice].skinnum[1] != -1))) {
// this character has a second skin // this character has a second skin
botskin = (UINT8)(description[choice].skinnum[1]+1); botskin = (UINT8)(description[choice].skinnum[1]+1);
botcolor = skins[description[choice].skinnum[1]].prefcolor; botcolor = skins[description[choice].skinnum[1]]->prefcolor;
} }
else else
botskin = botcolor = 0; botskin = botcolor = 0;
@ -9930,7 +9943,7 @@ void M_DrawTimeAttackMenu(void)
gamedata_t *data = clientGamedata; gamedata_t *data = clientGamedata;
INT32 i, x, y, empatx, empaty, cursory = 0; INT32 i, x, y, empatx, empaty, cursory = 0;
UINT16 dispstatus; UINT16 dispstatus;
patch_t *PictureOfUrFace; // my WHAT patch_t *PictureOfUrFace;
patch_t *empatch; patch_t *empatch;
M_SetMenuCurBackground("RECATKBG"); M_SetMenuCurBackground("RECATKBG");
@ -9999,9 +10012,9 @@ void M_DrawTimeAttackMenu(void)
// Character face! // Character face!
{ {
if (skins[cv_chooseskin.value-1].sprites[SPR2_XTRA].numframes > XTRA_CHARSEL) if (skins[cv_chooseskin.value-1]->sprites[SPR2_XTRA].numframes > XTRA_CHARSEL)
{ {
spritedef_t *sprdef = &skins[cv_chooseskin.value-1].sprites[SPR2_XTRA]; spritedef_t *sprdef = &skins[cv_chooseskin.value-1]->sprites[SPR2_XTRA];
spriteframe_t *sprframe = &sprdef->spriteframes[XTRA_CHARSEL]; spriteframe_t *sprframe = &sprdef->spriteframes[XTRA_CHARSEL];
PictureOfUrFace = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH); PictureOfUrFace = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH);
} }
@ -10447,7 +10460,7 @@ static void M_ChooseNightsAttack(INT32 choice)
I_Error("Out of memory for replay filepath\n"); I_Error("Out of memory for replay filepath\n");
sprintf(gpath,"replay"PATHSEP"%s"PATHSEP"%s", timeattackfolder, G_BuildMapName(cv_nextmap.value)); sprintf(gpath,"replay"PATHSEP"%s"PATHSEP"%s", timeattackfolder, G_BuildMapName(cv_nextmap.value));
snprintf(nameofdemo, sizeof nameofdemo, "%s-%s-last", gpath, skins[cv_chooseskin.value-1].name); snprintf(nameofdemo, sizeof nameofdemo, "%s-%s-last", gpath, skins[cv_chooseskin.value-1]->name);
if (!cv_autorecord.value) if (!cv_autorecord.value)
remove(va("%s"PATHSEP"%s.lmp", srb2home, nameofdemo)); remove(va("%s"PATHSEP"%s.lmp", srb2home, nameofdemo));
@ -10476,7 +10489,7 @@ static void M_ChooseTimeAttack(INT32 choice)
I_Error("Out of memory for replay filepath\n"); I_Error("Out of memory for replay filepath\n");
sprintf(gpath,"replay"PATHSEP"%s"PATHSEP"%s", timeattackfolder, G_BuildMapName(cv_nextmap.value)); sprintf(gpath,"replay"PATHSEP"%s"PATHSEP"%s", timeattackfolder, G_BuildMapName(cv_nextmap.value));
snprintf(nameofdemo, sizeof nameofdemo, "%s-%s-last", gpath, skins[cv_chooseskin.value-1].name); snprintf(nameofdemo, sizeof nameofdemo, "%s-%s-last", gpath, skins[cv_chooseskin.value-1]->name);
if (!cv_autorecord.value) if (!cv_autorecord.value)
remove(va("%s"PATHSEP"%s.lmp", srb2home, nameofdemo)); remove(va("%s"PATHSEP"%s.lmp", srb2home, nameofdemo));
@ -10529,7 +10542,7 @@ static void M_ReplayTimeAttack(INT32 choice)
if (choice != 4) if (choice != 4)
{ {
// srb2/replay/main/map01-sonic-time-best.lmp // srb2/replay/main/map01-sonic-time-best.lmp
snprintf(ra_demoname, 1024, "%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), skins[cv_chooseskin.value-1].name, which); snprintf(ra_demoname, 1024, "%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), skins[cv_chooseskin.value-1]->name, which);
} }
} }
else if (currentMenu == &SP_NightsReplayDef) else if (currentMenu == &SP_NightsReplayDef)
@ -10552,7 +10565,7 @@ static void M_ReplayTimeAttack(INT32 choice)
if (choice != 3) if (choice != 3)
{ {
snprintf(ra_demoname, 1024, "%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), skins[cv_chooseskin.value-1].name, which); snprintf(ra_demoname, 1024, "%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), skins[cv_chooseskin.value-1]->name, which);
#ifdef OLDNREPLAYNAME // Check for old style named NiGHTS replay if a new style replay doesn't exist. #ifdef OLDNREPLAYNAME // Check for old style named NiGHTS replay if a new style replay doesn't exist.
if (!FIL_FileExists(ra_demoname)) if (!FIL_FileExists(ra_demoname))
@ -10639,7 +10652,7 @@ static void M_OverwriteGuest(const char *which)
char *rguest = Z_StrDup(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value))); char *rguest = Z_StrDup(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value)));
UINT8 *buf; UINT8 *buf;
size_t len; size_t len;
len = FIL_ReadFile(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), skins[cv_chooseskin.value-1].name, which), &buf); len = FIL_ReadFile(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), skins[cv_chooseskin.value-1]->name, which), &buf);
if (!len) { if (!len) {
return; return;
@ -10781,7 +10794,7 @@ static void M_MarathonLiveEventBackup(INT32 choice)
// Going to Marathon menu... // Going to Marathon menu...
static void M_Marathon(INT32 choice) static void M_Marathon(INT32 choice)
{ {
UINT8 skinset; UINT16 skinset;
INT32 mapnum = 0; INT32 mapnum = 0;
if (choice != -1 && FIL_FileExists(liveeventbackup)) if (choice != -1 && FIL_FileExists(liveeventbackup))
@ -10805,7 +10818,7 @@ static void M_Marathon(INT32 choice)
skinset = M_SetupChoosePlayerDirect(-1); skinset = M_SetupChoosePlayerDirect(-1);
SP_MarathonMenu[marathonplayer].status = (skinset == MAXSKINS) ? IT_KEYHANDLER|IT_STRING : IT_NOTHING|IT_DISABLED; SP_MarathonMenu[marathonplayer].status = (skinset == MAXCHARACTERSLOTS) ? IT_KEYHANDLER|IT_STRING : IT_NOTHING|IT_DISABLED;
while (mapnum < NUMMAPS) while (mapnum < NUMMAPS)
{ {
@ -12248,11 +12261,11 @@ static void M_DrawSetupMultiPlayerMenu(void)
// draw skin string // draw skin string
V_DrawRightAlignedString(BASEVIDWIDTH - x, y, V_DrawRightAlignedString(BASEVIDWIDTH - x, y,
((MP_PlayerSetupMenu[1].status & IT_TYPE) == IT_SPACE ? V_TRANSLUCENT : 0)|(itemOn == 1 ? V_YELLOWMAP : 0)|V_ALLOWLOWERCASE, ((MP_PlayerSetupMenu[1].status & IT_TYPE) == IT_SPACE ? V_TRANSLUCENT : 0)|(itemOn == 1 ? V_YELLOWMAP : 0)|V_ALLOWLOWERCASE,
skins[setupm_fakeskin].realname); skins[setupm_fakeskin]->realname);
if (itemOn == 1 && (MP_PlayerSetupMenu[1].status & IT_TYPE) != IT_SPACE) if (itemOn == 1 && (MP_PlayerSetupMenu[1].status & IT_TYPE) != IT_SPACE)
{ {
V_DrawCharacter(BASEVIDWIDTH - x - 10 - V_StringWidth(skins[setupm_fakeskin].realname, V_ALLOWLOWERCASE) - (skullAnimCounter/5), y, V_DrawCharacter(BASEVIDWIDTH - x - 10 - V_StringWidth(skins[setupm_fakeskin]->realname, V_ALLOWLOWERCASE) - (skullAnimCounter/5), y,
'\x1C' | V_YELLOWMAP, false); '\x1C' | V_YELLOWMAP, false);
V_DrawCharacter(BASEVIDWIDTH - x + 2 + (skullAnimCounter/5), y, V_DrawCharacter(BASEVIDWIDTH - x + 2 + (skullAnimCounter/5), y,
'\x1D' | V_YELLOWMAP, false); '\x1D' | V_YELLOWMAP, false);
@ -12275,7 +12288,7 @@ static void M_DrawSetupMultiPlayerMenu(void)
V_DrawFill(x-(charw/2), y, charw, 84, V_DrawFill(x-(charw/2), y, charw, 84,
multi_invcolor ?skincolors[skincolors[setupm_fakecolor->color].invcolor].ramp[skincolors[setupm_fakecolor->color].invshade] : 159); multi_invcolor ?skincolors[skincolors[setupm_fakecolor->color].invcolor].ramp[skincolors[setupm_fakecolor->color].invshade] : 159);
sprdef = &skins[setupm_fakeskin].sprites[multi_spr2]; sprdef = &skins[setupm_fakeskin]->sprites[multi_spr2];
if (!setupm_fakecolor->color || !sprdef->numframes) // should never happen but hey, who knows if (!setupm_fakecolor->color || !sprdef->numframes) // should never happen but hey, who knows
goto faildraw; goto faildraw;
@ -12296,7 +12309,7 @@ static void M_DrawSetupMultiPlayerMenu(void)
V_DrawFixedPatch( V_DrawFixedPatch(
x<<FRACBITS, x<<FRACBITS,
chary<<FRACBITS, chary<<FRACBITS,
FixedDiv(skins[setupm_fakeskin].highresscale, skins[setupm_fakeskin].shieldscale), FixedDiv(skins[setupm_fakeskin]->highresscale, skins[setupm_fakeskin]->shieldscale),
flags, patch, colormap); flags, patch, colormap);
goto colordraw; goto colordraw;
@ -12528,7 +12541,7 @@ static void M_HandleSetupMultiPlayer(INT32 choice)
setupm_fakeskin = numskins-1; setupm_fakeskin = numskins-1;
} }
while ((prev_setupm_fakeskin != setupm_fakeskin) && !(R_SkinUsable(-1, setupm_fakeskin))); while ((prev_setupm_fakeskin != setupm_fakeskin) && !(R_SkinUsable(-1, setupm_fakeskin)));
multi_spr2 = P_GetSkinSprite2(&skins[setupm_fakeskin], SPR2_WALK, NULL); multi_spr2 = P_GetSkinSprite2(skins[setupm_fakeskin], SPR2_WALK, NULL);
} }
else if (itemOn == 2) // player color else if (itemOn == 2) // player color
{ {
@ -12544,7 +12557,7 @@ static void M_HandleSetupMultiPlayer(INT32 choice)
{ {
S_StartSound(NULL,sfx_strpst); S_StartSound(NULL,sfx_strpst);
// you know what? always putting these in the buffer won't hurt anything. // you know what? always putting these in the buffer won't hurt anything.
COM_BufAddText (va("%s \"%s\"\n",setupm_cvdefaultskin->name,skins[setupm_fakeskin].name)); COM_BufAddText (va("%s \"%s\"\n",setupm_cvdefaultskin->name,skins[setupm_fakeskin]->name));
COM_BufAddText (va("%s %d\n",setupm_cvdefaultcolor->name,setupm_fakecolor->color)); COM_BufAddText (va("%s %d\n",setupm_cvdefaultcolor->name,setupm_fakecolor->color));
break; break;
} }
@ -12568,7 +12581,7 @@ static void M_HandleSetupMultiPlayer(INT32 choice)
setupm_fakeskin = 0; setupm_fakeskin = 0;
} }
while ((prev_setupm_fakeskin != setupm_fakeskin) && !(R_SkinUsable(-1, setupm_fakeskin))); while ((prev_setupm_fakeskin != setupm_fakeskin) && !(R_SkinUsable(-1, setupm_fakeskin)));
multi_spr2 = P_GetSkinSprite2(&skins[setupm_fakeskin], SPR2_WALK, NULL); multi_spr2 = P_GetSkinSprite2(skins[setupm_fakeskin], SPR2_WALK, NULL);
} }
else if (itemOn == 2) // player color else if (itemOn == 2) // player color
{ {
@ -12624,7 +12637,7 @@ static void M_HandleSetupMultiPlayer(INT32 choice)
} }
else if (itemOn == 2) else if (itemOn == 2)
{ {
UINT16 col = skins[setupm_fakeskin].prefcolor; UINT16 col = skins[setupm_fakeskin]->prefcolor;
if ((setupm_fakecolor->color != col) && skincolors[col].accessible) if ((setupm_fakecolor->color != col) && skincolors[col].accessible)
{ {
S_StartSound(NULL,sfx_menu1); // Tails S_StartSound(NULL,sfx_menu1); // Tails
@ -12718,7 +12731,7 @@ static void M_SetupMultiPlayer(INT32 choice)
MP_PlayerSetupMenu[2].status = (IT_KEYHANDLER|IT_STRING); MP_PlayerSetupMenu[2].status = (IT_KEYHANDLER|IT_STRING);
multi_spr2 = P_GetSkinSprite2(&skins[setupm_fakeskin], SPR2_WALK, NULL); multi_spr2 = P_GetSkinSprite2(skins[setupm_fakeskin], SPR2_WALK, NULL);
MP_PlayerSetupDef.prevMenu = currentMenu; MP_PlayerSetupDef.prevMenu = currentMenu;
M_SetupNextMenu(&MP_PlayerSetupDef); M_SetupNextMenu(&MP_PlayerSetupDef);
@ -12759,7 +12772,7 @@ static void M_SetupMultiPlayer2(INT32 choice)
MP_PlayerSetupMenu[2].status = (IT_KEYHANDLER|IT_STRING); MP_PlayerSetupMenu[2].status = (IT_KEYHANDLER|IT_STRING);
multi_spr2 = P_GetSkinSprite2(&skins[setupm_fakeskin], SPR2_WALK, NULL); multi_spr2 = P_GetSkinSprite2(skins[setupm_fakeskin], SPR2_WALK, NULL);
MP_PlayerSetupDef.prevMenu = currentMenu; MP_PlayerSetupDef.prevMenu = currentMenu;
M_SetupNextMenu(&MP_PlayerSetupDef); M_SetupNextMenu(&MP_PlayerSetupDef);
@ -12777,7 +12790,7 @@ static boolean M_QuitMultiPlayerMenu(void)
setupm_name[l] =0; setupm_name[l] =0;
COM_BufAddText (va("%s \"%s\"\n",setupm_cvname->name,setupm_name)); COM_BufAddText (va("%s \"%s\"\n",setupm_cvname->name,setupm_name));
} }
COM_BufAddText (va("%s \"%s\"\n",setupm_cvskin->name,skins[setupm_fakeskin].name)); COM_BufAddText (va("%s \"%s\"\n",setupm_cvskin->name,skins[setupm_fakeskin]->name));
// send color if changed // send color if changed
if (setupm_fakecolor->color != setupm_cvcolor->value) if (setupm_fakecolor->color != setupm_cvcolor->value)
COM_BufAddText (va("%s %d\n",setupm_cvcolor->name,setupm_fakecolor->color)); COM_BufAddText (va("%s %d\n",setupm_cvcolor->name,setupm_fakecolor->color));

View file

@ -200,8 +200,8 @@ void M_Drawer(void);
// Called by D_SRB2Main, loads the config file. // Called by D_SRB2Main, loads the config file.
void M_Init(void); void M_Init(void);
// Called by D_SRB2Main also, sets up the playermenu and description tables. // Called by deh_soc.c, sets up the playermenu and description tables.
void M_InitCharacterTables(void); void M_InitCharacterTables(INT32 num);
// Called by intro code to force menu up upon a keypress, // Called by intro code to force menu up upon a keypress,
// does nothing if menu is already up. // does nothing if menu is already up.
@ -375,10 +375,8 @@ typedef struct
patch_t *charpic; patch_t *charpic;
UINT8 prev; UINT8 prev;
UINT8 next; UINT8 next;
// new character select
char displayname[SKINNAMESIZE+1]; char displayname[SKINNAMESIZE+1];
SINT8 skinnum[2]; INT16 skinnum[2];
UINT16 oppositecolor; UINT16 oppositecolor;
char nametag[8]; char nametag[8];
patch_t *namepic; patch_t *namepic;
@ -431,7 +429,8 @@ typedef struct
INT32 gamemap; INT32 gamemap;
} saveinfo_t; } saveinfo_t;
extern description_t description[MAXSKINS]; extern description_t *description;
extern INT32 numdescriptions;
extern consvar_t cv_showfocuslost; extern consvar_t cv_showfocuslost;
extern consvar_t cv_newgametype, cv_nextmap, cv_chooseskin, cv_serversort; extern consvar_t cv_newgametype, cv_nextmap, cv_chooseskin, cv_serversort;

View file

@ -1259,8 +1259,8 @@ static void SendNameAndColor(void)
CV_StealthSetValue(&cv_playercolor, players[consoleplayer].skincolor); CV_StealthSetValue(&cv_playercolor, players[consoleplayer].skincolor);
else if (skincolors[atoi(cv_playercolor.defaultvalue)].accessible) else if (skincolors[atoi(cv_playercolor.defaultvalue)].accessible)
CV_StealthSet(&cv_playercolor, cv_playercolor.defaultvalue); CV_StealthSet(&cv_playercolor, cv_playercolor.defaultvalue);
else if (skins[players[consoleplayer].skin].prefcolor && skincolors[skins[players[consoleplayer].skin].prefcolor].accessible) else if (skins[players[consoleplayer].skin]->prefcolor && skincolors[skins[players[consoleplayer].skin]->prefcolor].accessible)
CV_StealthSetValue(&cv_playercolor, skins[players[consoleplayer].skin].prefcolor); CV_StealthSetValue(&cv_playercolor, skins[players[consoleplayer].skin]->prefcolor);
else { else {
UINT16 i = 0; UINT16 i = 0;
while (i<numskincolors && !skincolors[i].accessible) i++; while (i<numskincolors && !skincolors[i].accessible) i++;
@ -1270,7 +1270,7 @@ static void SendNameAndColor(void)
if (!strcmp(cv_playername.string, player_names[consoleplayer]) if (!strcmp(cv_playername.string, player_names[consoleplayer])
&& cv_playercolor.value == players[consoleplayer].skincolor && cv_playercolor.value == players[consoleplayer].skincolor
&& !strcmp(cv_skin.string, skins[players[consoleplayer].skin].name)) && !strcmp(cv_skin.string, skins[players[consoleplayer].skin]->name))
return; return;
players[consoleplayer].availabilities = R_GetSkinAvailabilities(); players[consoleplayer].availabilities = R_GetSkinAvailabilities();
@ -1313,7 +1313,7 @@ static void SendNameAndColor(void)
if ((cv_skin.value < 0) || !R_SkinUsable(consoleplayer, cv_skin.value)) if ((cv_skin.value < 0) || !R_SkinUsable(consoleplayer, cv_skin.value))
{ {
INT32 defaultSkinNum = GetPlayerDefaultSkin(consoleplayer); INT32 defaultSkinNum = GetPlayerDefaultSkin(consoleplayer);
CV_StealthSet(&cv_skin, skins[defaultSkinNum].name); CV_StealthSet(&cv_skin, skins[defaultSkinNum]->name);
cv_skin.value = defaultSkinNum; cv_skin.value = defaultSkinNum;
} }
@ -1344,8 +1344,8 @@ static void SendNameAndColor2(void)
CV_StealthSetValue(&cv_playercolor2, players[secondplaya].skincolor); CV_StealthSetValue(&cv_playercolor2, players[secondplaya].skincolor);
else if (skincolors[atoi(cv_playercolor2.defaultvalue)].accessible) else if (skincolors[atoi(cv_playercolor2.defaultvalue)].accessible)
CV_StealthSet(&cv_playercolor, cv_playercolor2.defaultvalue); CV_StealthSet(&cv_playercolor, cv_playercolor2.defaultvalue);
else if (skins[players[secondplaya].skin].prefcolor && skincolors[skins[players[secondplaya].skin].prefcolor].accessible) else if (skins[players[secondplaya].skin]->prefcolor && skincolors[skins[players[secondplaya].skin]->prefcolor].accessible)
CV_StealthSetValue(&cv_playercolor2, skins[players[secondplaya].skin].prefcolor); CV_StealthSetValue(&cv_playercolor2, skins[players[secondplaya].skin]->prefcolor);
else { else {
UINT16 i = 0; UINT16 i = 0;
while (i<numskincolors && !skincolors[i].accessible) i++; while (i<numskincolors && !skincolors[i].accessible) i++;
@ -2079,7 +2079,7 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum)
if (modeattacking) if (modeattacking)
{ {
SetPlayerSkinByNum(0, cv_chooseskin.value-1); SetPlayerSkinByNum(0, cv_chooseskin.value-1);
players[0].skincolor = skins[players[0].skin].prefcolor; players[0].skincolor = skins[players[0].skin]->prefcolor;
} }
mapnumber = M_MapNumber(mapname[3], mapname[4]); mapnumber = M_MapNumber(mapname[3], mapname[4]);
@ -4743,7 +4743,7 @@ static void ForceSkin_OnChange(void)
} }
else else
{ {
CONS_Printf("The server is restricting all players to skin \"%s\".\n",skins[cv_forceskin.value].name); CONS_Printf("The server is restricting all players to skin \"%s\".\n",skins[cv_forceskin.value]->name);
if (Playing()) if (Playing())
ForceAllSkins(cv_forceskin.value); ForceAllSkins(cv_forceskin.value);
} }
@ -4789,7 +4789,7 @@ static void Skin_OnChange(void)
if (!(cv_debug || devparm) if (!(cv_debug || devparm)
&& (gamestate != GS_WAITINGPLAYERS)) // allows command line -warp x +skin y && (gamestate != GS_WAITINGPLAYERS)) // allows command line -warp x +skin y
{ {
CV_StealthSet(&cv_skin, skins[players[consoleplayer].skin].name); CV_StealthSet(&cv_skin, skins[players[consoleplayer].skin]->name);
return; return;
} }

View file

@ -3677,7 +3677,7 @@ void A_1upThinker(mobj_t *actor)
} }
} }
if (closestplayer == -1 || skins[players[closestplayer].skin].sprites[SPR2_LIFE].numframes == 0) if (closestplayer == -1 || skins[players[closestplayer].skin]->sprites[SPR2_LIFE].numframes == 0)
{ // Closest player not found (no players in game?? may be empty dedicated server!), or does not have correct sprite. { // Closest player not found (no players in game?? may be empty dedicated server!), or does not have correct sprite.
if (actor->tracer) if (actor->tracer)
{ {
@ -3698,7 +3698,7 @@ void A_1upThinker(mobj_t *actor)
return; return;
P_SetTarget(&actor->tracer->target, actor); P_SetTarget(&actor->tracer->target, actor);
actor->tracer->skin = &skins[players[closestplayer].skin]; // required here to prevent spr2 default showing stand for a single frame actor->tracer->skin = skins[players[closestplayer].skin]; // required here to prevent spr2 default showing stand for a single frame
P_SetMobjState(actor->tracer, actor->info->seestate); P_SetMobjState(actor->tracer, actor->info->seestate);
// The overlay is going to be one tic early turning off and on // The overlay is going to be one tic early turning off and on
@ -3708,7 +3708,7 @@ void A_1upThinker(mobj_t *actor)
} }
actor->tracer->color = players[closestplayer].mo->color; actor->tracer->color = players[closestplayer].mo->color;
actor->tracer->skin = &skins[players[closestplayer].skin]; actor->tracer->skin = skins[players[closestplayer].skin];
} }
// Function: A_MonitorPop // Function: A_MonitorPop
@ -3769,6 +3769,7 @@ void A_MonitorPop(mobj_t *actor)
{ {
P_SetTarget(&newmobj->target, actor->target); // Transfer target P_SetTarget(&newmobj->target, actor->target); // Transfer target
if (item == MT_1UP_ICON) if (item == MT_1UP_ICON)
{ {
if (!newmobj->target if (!newmobj->target
@ -3857,7 +3858,6 @@ void A_GoldMonitorPop(mobj_t *actor)
if (!P_MobjWasRemoved(newmobj)) if (!P_MobjWasRemoved(newmobj))
{ {
P_SetTarget(&newmobj->target, actor->target); // Transfer target P_SetTarget(&newmobj->target, actor->target); // Transfer target
if (item == MT_1UP_ICON) if (item == MT_1UP_ICON)
{ {
if (actor->tracer) // Remove the old lives icon. if (actor->tracer) // Remove the old lives icon.
@ -5349,7 +5349,7 @@ void A_SignPlayer(mobj_t *actor)
if (!actor->target->player) if (!actor->target->player)
return; return;
skin = &skins[actor->target->player->skin]; skin = skins[actor->target->player->skin];
facecolor = P_GetPlayerColor(actor->target->player); facecolor = P_GetPlayerColor(actor->target->player);
if (signcolor) if (signcolor)
@ -5380,10 +5380,10 @@ void A_SignPlayer(mobj_t *actor)
if (!SignSkinCheck(player, skincount)) if (!SignSkinCheck(player, skincount))
skinnum++; skinnum++;
} }
skin = &skins[skinnum]; skin = skins[skinnum];
} }
else // specific skin else // specific skin
skin = &skins[locvar1]; skin = skins[locvar1];
facecolor = skin->prefcolor; facecolor = skin->prefcolor;
if (signcolor) if (signcolor)

View file

@ -212,7 +212,7 @@ static boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state)
return P_SetPlayerMobjState(mobj, S_PLAY_FALL); return P_SetPlayerMobjState(mobj, S_PLAY_FALL);
// Catch swimming versus flying // Catch swimming versus flying
if ((state == S_PLAY_FLY || (state == S_PLAY_GLIDE && skins[player->skin].sprites[SPR2_SWIM].numframes)) if ((state == S_PLAY_FLY || (state == S_PLAY_GLIDE && skins[player->skin]->sprites[SPR2_SWIM].numframes))
&& player->mo->eflags & MFE_UNDERWATER && !player->skidtime) && player->mo->eflags & MFE_UNDERWATER && !player->skidtime)
return P_SetPlayerMobjState(player->mo, S_PLAY_SWIM); return P_SetPlayerMobjState(player->mo, S_PLAY_SWIM);
else if (state == S_PLAY_SWIM && !(player->mo->eflags & MFE_UNDERWATER)) else if (state == S_PLAY_SWIM && !(player->mo->eflags & MFE_UNDERWATER))
@ -11086,10 +11086,10 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type, ...)
nummaprings++; nummaprings++;
break; break;
case MT_METALSONIC_RACE: case MT_METALSONIC_RACE:
mobj->skin = &skins[5]; mobj->skin = skins[5];
/* FALLTHRU */ /* FALLTHRU */
case MT_METALSONIC_BATTLE: case MT_METALSONIC_BATTLE:
mobj->color = skins[5].prefcolor; mobj->color = skins[5]->prefcolor;
sc = 5; sc = 5;
break; break;
case MT_FANG: case MT_FANG:
@ -11794,7 +11794,7 @@ void P_SpawnPlayer(INT32 playernum)
// set 'spritedef' override in mobj for player skins.. (see ProjectSprite) // set 'spritedef' override in mobj for player skins.. (see ProjectSprite)
// (usefulness: when body mobj is detached from player (who respawns), // (usefulness: when body mobj is detached from player (who respawns),
// the dead body mobj retains the skin through the 'spritedef' override). // the dead body mobj retains the skin through the 'spritedef' override).
mobj->skin = &skins[p->skin]; mobj->skin = skins[p->skin];
P_SetupStateAnimation(mobj, mobj->state); P_SetupStateAnimation(mobj, mobj->state);
mobj->health = 1; mobj->health = 1;
@ -11802,14 +11802,14 @@ void P_SpawnPlayer(INT32 playernum)
p->bonustime = false; p->bonustime = false;
p->realtime = leveltime; p->realtime = leveltime;
p->followitem = skins[p->skin].followitem; p->followitem = skins[p->skin]->followitem;
// Make sure player's stats are reset if they were in dashmode! // Make sure player's stats are reset if they were in dashmode!
if (p->dashmode) if (p->dashmode)
{ {
p->dashmode = 0; p->dashmode = 0;
p->normalspeed = skins[p->skin].normalspeed; p->normalspeed = skins[p->skin]->normalspeed;
p->jumpfactor = skins[p->skin].jumpfactor; p->jumpfactor = skins[p->skin]->jumpfactor;
} }
// Clear lastlinehit and lastsidehit // Clear lastlinehit and lastsidehit
@ -11825,7 +11825,7 @@ void P_SpawnPlayer(INT32 playernum)
P_FlashPal(p, 0, 0); // Resets P_FlashPal(p, 0, 0); // Resets
// Set bounds accurately. // Set bounds accurately.
mobj->radius = FixedMul(skins[p->skin].radius, mobj->scale); mobj->radius = FixedMul(skins[p->skin]->radius, mobj->scale);
mobj->height = P_GetPlayerHeight(p); mobj->height = P_GetPlayerHeight(p);
if (!leveltime && !p->spectator && ((maptol & TOL_NIGHTS) == TOL_NIGHTS) != (G_IsSpecialStage(gamemap))) // non-special NiGHTS stage or special non-NiGHTS stage if (!leveltime && !p->spectator && ((maptol & TOL_NIGHTS) == TOL_NIGHTS) != (G_IsSpecialStage(gamemap))) // non-special NiGHTS stage or special non-NiGHTS stage

View file

@ -78,11 +78,11 @@ static inline void P_ArchivePlayer(void)
// Write skin names, so that loading skins in different orders // Write skin names, so that loading skins in different orders
// doesn't change who the save file is for! // doesn't change who the save file is for!
WRITESTRINGN(save_p, skins[player->skin].name, SKINNAMESIZE); WRITESTRINGN(save_p, skins[player->skin]->name, SKINNAMESIZE);
if (botskin != 0) if (botskin != 0)
{ {
WRITESTRINGN(save_p, skins[botskin-1].name, SKINNAMESIZE); WRITESTRINGN(save_p, skins[botskin-1]->name, SKINNAMESIZE);
} }
else else
{ {
@ -2058,7 +2058,7 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
if (diff2 & MD2_CVMEM) if (diff2 & MD2_CVMEM)
WRITEINT32(save_p, mobj->cvmem); WRITEINT32(save_p, mobj->cvmem);
if (diff2 & MD2_SKIN) if (diff2 & MD2_SKIN)
WRITEUINT8(save_p, (UINT8)((skin_t *)mobj->skin - skins)); WRITEUINT8(save_p, (UINT8)(((skin_t *)mobj->skin)->skinnum));
if (diff2 & MD2_COLOR) if (diff2 & MD2_COLOR)
WRITEUINT16(save_p, mobj->color); WRITEUINT16(save_p, mobj->color);
if (diff2 & MD2_EXTVAL1) if (diff2 & MD2_EXTVAL1)
@ -3112,7 +3112,7 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker)
if (diff2 & MD2_CVMEM) if (diff2 & MD2_CVMEM)
mobj->cvmem = READINT32(save_p); mobj->cvmem = READINT32(save_p);
if (diff2 & MD2_SKIN) if (diff2 & MD2_SKIN)
mobj->skin = &skins[READUINT8(save_p)]; mobj->skin = skins[READUINT8(save_p)];
if (diff2 & MD2_COLOR) if (diff2 & MD2_COLOR)
mobj->color = READUINT16(save_p); mobj->color = READUINT16(save_p);
if (diff2 & MD2_EXTVAL1) if (diff2 & MD2_EXTVAL1)

View file

@ -7267,7 +7267,7 @@ static void P_ForceCharacter(const char *forcecharskin)
SetPlayerSkinByNum(i, skinnum); SetPlayerSkinByNum(i, skinnum);
if (!netgame) if (!netgame)
players[i].skincolor = skins[skinnum].prefcolor; players[i].skincolor = skins[skinnum]->prefcolor;
} }
} }
@ -7310,8 +7310,8 @@ static void P_LoadRecordGhosts(void)
if (cv_ghost_bestscore.value == 1 && players[consoleplayer].skin != i) if (cv_ghost_bestscore.value == 1 && players[consoleplayer].skin != i)
continue; continue;
if (FIL_FileExists(va("%s-%s-score-best.lmp", gpath, skins[i].name))) if (FIL_FileExists(va("%s-%s-score-best.lmp", gpath, skins[i]->name)))
G_AddGhost(va("%s-%s-score-best.lmp", gpath, skins[i].name)); G_AddGhost(va("%s-%s-score-best.lmp", gpath, skins[i]->name));
} }
} }
@ -7323,8 +7323,8 @@ static void P_LoadRecordGhosts(void)
if (cv_ghost_besttime.value == 1 && players[consoleplayer].skin != i) if (cv_ghost_besttime.value == 1 && players[consoleplayer].skin != i)
continue; continue;
if (FIL_FileExists(va("%s-%s-time-best.lmp", gpath, skins[i].name))) if (FIL_FileExists(va("%s-%s-time-best.lmp", gpath, skins[i]->name)))
G_AddGhost(va("%s-%s-time-best.lmp", gpath, skins[i].name)); G_AddGhost(va("%s-%s-time-best.lmp", gpath, skins[i]->name));
} }
} }
@ -7336,8 +7336,8 @@ static void P_LoadRecordGhosts(void)
if (cv_ghost_bestrings.value == 1 && players[consoleplayer].skin != i) if (cv_ghost_bestrings.value == 1 && players[consoleplayer].skin != i)
continue; continue;
if (FIL_FileExists(va("%s-%s-rings-best.lmp", gpath, skins[i].name))) if (FIL_FileExists(va("%s-%s-rings-best.lmp", gpath, skins[i]->name)))
G_AddGhost(va("%s-%s-rings-best.lmp", gpath, skins[i].name)); G_AddGhost(va("%s-%s-rings-best.lmp", gpath, skins[i]->name));
} }
} }
@ -7349,8 +7349,8 @@ static void P_LoadRecordGhosts(void)
if (cv_ghost_last.value == 1 && players[consoleplayer].skin != i) if (cv_ghost_last.value == 1 && players[consoleplayer].skin != i)
continue; continue;
if (FIL_FileExists(va("%s-%s-last.lmp", gpath, skins[i].name))) if (FIL_FileExists(va("%s-%s-last.lmp", gpath, skins[i]->name)))
G_AddGhost(va("%s-%s-last.lmp", gpath, skins[i].name)); G_AddGhost(va("%s-%s-last.lmp", gpath, skins[i]->name));
} }
} }
@ -7380,8 +7380,8 @@ static void P_LoadNightsGhosts(void)
if (cv_ghost_bestscore.value == 1 && players[consoleplayer].skin != i) if (cv_ghost_bestscore.value == 1 && players[consoleplayer].skin != i)
continue; continue;
if (FIL_FileExists(va("%s-%s-score-best.lmp", gpath, skins[i].name))) if (FIL_FileExists(va("%s-%s-score-best.lmp", gpath, skins[i]->name)))
G_AddGhost(va("%s-%s-score-best.lmp", gpath, skins[i].name)); G_AddGhost(va("%s-%s-score-best.lmp", gpath, skins[i]->name));
} }
} }
@ -7393,8 +7393,8 @@ static void P_LoadNightsGhosts(void)
if (cv_ghost_besttime.value == 1 && players[consoleplayer].skin != i) if (cv_ghost_besttime.value == 1 && players[consoleplayer].skin != i)
continue; continue;
if (FIL_FileExists(va("%s-%s-time-best.lmp", gpath, skins[i].name))) if (FIL_FileExists(va("%s-%s-time-best.lmp", gpath, skins[i]->name)))
G_AddGhost(va("%s-%s-time-best.lmp", gpath, skins[i].name)); G_AddGhost(va("%s-%s-time-best.lmp", gpath, skins[i]->name));
} }
} }
@ -7406,8 +7406,8 @@ static void P_LoadNightsGhosts(void)
if (cv_ghost_last.value == 1 && players[consoleplayer].skin != i) if (cv_ghost_last.value == 1 && players[consoleplayer].skin != i)
continue; continue;
if (FIL_FileExists(va("%s-%s-last.lmp", gpath, skins[i].name))) if (FIL_FileExists(va("%s-%s-last.lmp", gpath, skins[i]->name)))
G_AddGhost(va("%s-%s-last.lmp", gpath, skins[i].name)); G_AddGhost(va("%s-%s-last.lmp", gpath, skins[i]->name));
} }
} }

View file

@ -1836,7 +1836,7 @@ void P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller)
return; return;
if (!triggerline->stringargs[0]) if (!triggerline->stringargs[0])
return; return;
if (!(stricmp(triggerline->stringargs[0], skins[actor->player->skin].name) == 0) ^ !!(triggerline->args[1])) if (!(stricmp(triggerline->stringargs[0], skins[actor->player->skin]->name) == 0) ^ !!(triggerline->args[1]))
return; return;
break; break;
case 334: // object dye case 334: // object dye

View file

@ -685,8 +685,8 @@ static void P_DeNightserizePlayer(player_t *player)
player->mo->flags &= ~MF_NOGRAVITY; player->mo->flags &= ~MF_NOGRAVITY;
player->mo->skin = &skins[player->skin]; player->mo->skin = skins[player->skin];
player->followitem = skins[player->skin].followitem; player->followitem = skins[player->skin]->followitem;
player->mo->color = P_GetPlayerColor(player); player->mo->color = P_GetPlayerColor(player);
G_GhostAddColor(GHC_RETURNSKIN); G_GhostAddColor(GHC_RETURNSKIN);
@ -786,12 +786,12 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
player->mo->height = P_GetPlayerHeight(player); // Just to make sure jumping into the drone doesn't result in a squashed hitbox. player->mo->height = P_GetPlayerHeight(player); // Just to make sure jumping into the drone doesn't result in a squashed hitbox.
player->oldscale = player->mo->scale; player->oldscale = player->mo->scale;
if (skins[player->skin].sprites[SPR2_NFLY].numframes == 0) // If you don't have a sprite for flying horizontally, use the default NiGHTS skin. if (skins[player->skin]->sprites[SPR2_NFLY].numframes == 0) // If you don't have a sprite for flying horizontally, use the default NiGHTS skin.
{ {
player->mo->skin = &skins[DEFAULTNIGHTSSKIN]; player->mo->skin = skins[DEFAULTNIGHTSSKIN];
if (!(cv_debug || devparm) && !(netgame || multiplayer || demoplayback)) if (!(cv_debug || devparm) && !(netgame || multiplayer || demoplayback))
player->mo->color = skins[DEFAULTNIGHTSSKIN].prefcolor; player->mo->color = skins[DEFAULTNIGHTSSKIN]->prefcolor;
player->followitem = skins[DEFAULTNIGHTSSKIN].followitem; player->followitem = skins[DEFAULTNIGHTSSKIN]->followitem;
G_GhostAddColor(GHC_NIGHTSSKIN); G_GhostAddColor(GHC_NIGHTSSKIN);
} }
} }
@ -4417,7 +4417,7 @@ static void P_DoSuperStuff(player_t *player)
player->mo->color = (player->pflags & PF_GODMODE && cv_debug == 0) player->mo->color = (player->pflags & PF_GODMODE && cv_debug == 0)
? (SKINCOLOR_SUPERSILVER1 + 5*(((signed)leveltime >> 1) % 7)) // A wholesome easter egg. ? (SKINCOLOR_SUPERSILVER1 + 5*(((signed)leveltime >> 1) % 7)) // A wholesome easter egg.
: skins[player->skin].supercolor + abs( ( (player->powers[pw_super] >> 1) % 9) - 4); // This is where super flashing is handled. : skins[player->skin]->supercolor + abs( ( (player->powers[pw_super] >> 1) % 9) - 4); // This is where super flashing is handled.
G_GhostAddColor(GHC_SUPER); G_GhostAddColor(GHC_SUPER);
@ -11643,7 +11643,7 @@ void P_DoMetalJetFume(player_t *player, mobj_t *fume)
if (resetinterp) R_ResetMobjInterpolationState(fume); if (resetinterp) R_ResetMobjInterpolationState(fume);
// If dashmode is high enough, spawn a trail // If dashmode is high enough, spawn a trail
if (player->normalspeed >= skins[player->skin].normalspeed*2) if (player->normalspeed >= skins[player->skin]->normalspeed*2)
{ {
mobj_t *ghost = P_SpawnGhostMobj(fume); mobj_t *ghost = P_SpawnGhostMobj(fume);
if (!P_MobjWasRemoved(ghost)) if (!P_MobjWasRemoved(ghost))
@ -12517,25 +12517,25 @@ void P_PlayerThink(player_t *player)
{ {
if (prevdashmode >= DASHMODE_THRESHOLD) if (prevdashmode >= DASHMODE_THRESHOLD)
{ {
player->normalspeed = skins[player->skin].normalspeed; // Reset to default if not capable of entering dash mode. player->normalspeed = skins[player->skin]->normalspeed; // Reset to default if not capable of entering dash mode.
player->jumpfactor = skins[player->skin].jumpfactor; player->jumpfactor = skins[player->skin]->jumpfactor;
if (player->powers[pw_strong] & STR_DASH) if (player->powers[pw_strong] & STR_DASH)
player->powers[pw_strong] = STR_NONE; player->powers[pw_strong] = STR_NONE;
} }
} }
else if (P_IsObjectOnGround(player->mo)) // Activate dash mode if we're on the ground. else if (P_IsObjectOnGround(player->mo)) // Activate dash mode if we're on the ground.
{ {
if (player->normalspeed < skins[player->skin].normalspeed*2) // If the player normalspeed is not currently at normalspeed*2 in dash mode, add speed each tic if (player->normalspeed < skins[player->skin]->normalspeed*2) // If the player normalspeed is not currently at normalspeed*2 in dash mode, add speed each tic
player->normalspeed += FRACUNIT/5; // Enter Dash Mode smoothly. player->normalspeed += FRACUNIT/5; // Enter Dash Mode smoothly.
if (player->jumpfactor < FixedMul(skins[player->skin].jumpfactor, 5*FRACUNIT/4)) // Boost jump height. if (player->jumpfactor < FixedMul(skins[player->skin]->jumpfactor, 5*FRACUNIT/4)) // Boost jump height.
player->jumpfactor += FRACUNIT/300; player->jumpfactor += FRACUNIT/300;
if ((player->charflags & SF_MACHINE) && (!(player->powers[pw_strong] == STR_METAL))) if ((player->charflags & SF_MACHINE) && (!(player->powers[pw_strong] == STR_METAL)))
player->powers[pw_strong] = STR_METAL; player->powers[pw_strong] = STR_METAL;
} }
if (player->normalspeed >= skins[player->skin].normalspeed*2) if (player->normalspeed >= skins[player->skin]->normalspeed*2)
{ {
mobj_t *ghost = P_SpawnGhostMobj(player->mo); // Spawns afterimages mobj_t *ghost = P_SpawnGhostMobj(player->mo); // Spawns afterimages
if (!P_MobjWasRemoved(ghost)) if (!P_MobjWasRemoved(ghost))
@ -12550,8 +12550,8 @@ void P_PlayerThink(player_t *player)
{ {
if (dashmode >= DASHMODE_THRESHOLD) // catch getting the flag! if (dashmode >= DASHMODE_THRESHOLD) // catch getting the flag!
{ {
player->normalspeed = skins[player->skin].normalspeed; player->normalspeed = skins[player->skin]->normalspeed;
player->jumpfactor = skins[player->skin].jumpfactor; player->jumpfactor = skins[player->skin]->jumpfactor;
S_StartSound(player->mo, sfx_kc65); S_StartSound(player->mo, sfx_kc65);
if (player->powers[pw_strong] & STR_DASH) if (player->powers[pw_strong] & STR_DASH)
player->powers[pw_strong] = STR_NONE; player->powers[pw_strong] = STR_NONE;

View file

@ -121,52 +121,53 @@ float focallengthf, zeroheight;
UINT32 nflatxshift, nflatyshift, nflatshiftup, nflatmask; UINT32 nflatxshift, nflatyshift, nflatshiftup, nflatmask;
// ========================================================================= // =========================================================================
// TRANSLATION COLORMAP CODE // TRANSLATION COLORMAP CODE
// ========================================================================= // =========================================================================
#define DEFAULT_TT_CACHE_INDEX MAXSKINS enum
#define BOSS_TT_CACHE_INDEX (MAXSKINS + 1)
#define METALSONIC_TT_CACHE_INDEX (MAXSKINS + 2)
#define ALLWHITE_TT_CACHE_INDEX (MAXSKINS + 3)
#define RAINBOW_TT_CACHE_INDEX (MAXSKINS + 4)
#define BLINK_TT_CACHE_INDEX (MAXSKINS + 5)
#define DASHMODE_TT_CACHE_INDEX (MAXSKINS + 6)
static UINT8 **translationtablecache[MAXSKINS + 7] = {NULL};
UINT8 skincolor_modified[MAXSKINCOLORS];
static INT32 SkinToCacheIndex(INT32 skinnum)
{ {
switch (skinnum) DEFAULT_TT_CACHE_INDEX,
BOSS_TT_CACHE_INDEX,
METALSONIC_TT_CACHE_INDEX,
ALLWHITE_TT_CACHE_INDEX,
RAINBOW_TT_CACHE_INDEX,
BLINK_TT_CACHE_INDEX,
DASHMODE_TT_CACHE_INDEX,
TT_CACHE_SIZE
};
static UINT8 **translationtablecache[TT_CACHE_SIZE] = {NULL};
static UINT8 **skintranslationcache[NUM_PALETTE_ENTRIES] = {NULL};
boolean skincolor_modified[MAXSKINCOLORS];
static INT32 TranslationToCacheIndex(INT32 translation)
{
switch (translation)
{ {
case TC_DEFAULT: return DEFAULT_TT_CACHE_INDEX;
case TC_BOSS: return BOSS_TT_CACHE_INDEX; case TC_BOSS: return BOSS_TT_CACHE_INDEX;
case TC_METALSONIC: return METALSONIC_TT_CACHE_INDEX; case TC_METALSONIC: return METALSONIC_TT_CACHE_INDEX;
case TC_ALLWHITE: return ALLWHITE_TT_CACHE_INDEX; case TC_ALLWHITE: return ALLWHITE_TT_CACHE_INDEX;
case TC_RAINBOW: return RAINBOW_TT_CACHE_INDEX; case TC_RAINBOW: return RAINBOW_TT_CACHE_INDEX;
case TC_BLINK: return BLINK_TT_CACHE_INDEX; case TC_BLINK: return BLINK_TT_CACHE_INDEX;
case TC_DASHMODE: return DASHMODE_TT_CACHE_INDEX; case TC_DASHMODE: return DASHMODE_TT_CACHE_INDEX;
default: break; default: return DEFAULT_TT_CACHE_INDEX;
} }
return skinnum;
} }
static INT32 CacheIndexToSkin(INT32 ttc) static INT32 CacheIndexToTranslation(INT32 index)
{ {
switch (ttc) switch (index)
{ {
case DEFAULT_TT_CACHE_INDEX: return TC_DEFAULT;
case BOSS_TT_CACHE_INDEX: return TC_BOSS; case BOSS_TT_CACHE_INDEX: return TC_BOSS;
case METALSONIC_TT_CACHE_INDEX: return TC_METALSONIC; case METALSONIC_TT_CACHE_INDEX: return TC_METALSONIC;
case ALLWHITE_TT_CACHE_INDEX: return TC_ALLWHITE; case ALLWHITE_TT_CACHE_INDEX: return TC_ALLWHITE;
case RAINBOW_TT_CACHE_INDEX: return TC_RAINBOW; case RAINBOW_TT_CACHE_INDEX: return TC_RAINBOW;
case BLINK_TT_CACHE_INDEX: return TC_BLINK; case BLINK_TT_CACHE_INDEX: return TC_BLINK;
case DASHMODE_TT_CACHE_INDEX: return TC_DASHMODE; case DASHMODE_TT_CACHE_INDEX: return TC_DASHMODE;
default: break; default: return TC_DEFAULT;
} }
return ttc;
} }
CV_PossibleValue_t Color_cons_t[MAXSKINCOLORS+1]; CV_PossibleValue_t Color_cons_t[MAXSKINCOLORS+1];
@ -396,18 +397,18 @@ static void R_RainbowColormap(UINT8 *dest_colormap, UINT16 skincolor)
RGBA_t color; RGBA_t color;
UINT8 brightness; UINT8 brightness;
INT32 j; INT32 j;
UINT8 colorbrightnesses[16]; UINT8 colorbrightnesses[COLORRAMPSIZE];
UINT16 brightdif; UINT16 brightdif;
INT32 temp; INT32 temp;
// first generate the brightness of all the colours of that skincolour // first generate the brightness of all the colours of that skincolour
for (i = 0; i < 16; i++) for (i = 0; i < COLORRAMPSIZE; i++)
{ {
color = V_GetColor(skincolors[skincolor].ramp[i]); color = V_GetColor(skincolors[skincolor].ramp[i]);
SETBRIGHTNESS(colorbrightnesses[i], color.s.red, color.s.green, color.s.blue); SETBRIGHTNESS(colorbrightnesses[i], color.s.red, color.s.green, color.s.blue);
} }
// next, for every colour in the palette, choose the transcolor that has the closest brightness // next, for every colour in the palette, choose the translated colour that has the closest brightness
for (i = 0; i < NUM_PALETTE_ENTRIES; i++) for (i = 0; i < NUM_PALETTE_ENTRIES; i++)
{ {
if (i == 0 || i == 31) // pure black and pure white don't change if (i == 0 || i == 31) // pure black and pure white don't change
@ -418,7 +419,7 @@ static void R_RainbowColormap(UINT8 *dest_colormap, UINT16 skincolor)
color = V_GetColor(i); color = V_GetColor(i);
SETBRIGHTNESS(brightness, color.s.red, color.s.green, color.s.blue); SETBRIGHTNESS(brightness, color.s.red, color.s.green, color.s.blue);
brightdif = 256; brightdif = 256;
for (j = 0; j < 16; j++) for (j = 0; j < COLORRAMPSIZE; j++)
{ {
temp = abs((INT16)brightness - (INT16)colorbrightnesses[j]); temp = abs((INT16)brightness - (INT16)colorbrightnesses[j]);
if (temp < brightdif) if (temp < brightdif)
@ -434,28 +435,29 @@ static void R_RainbowColormap(UINT8 *dest_colormap, UINT16 skincolor)
/** \brief Generates a translation colormap. /** \brief Generates a translation colormap.
\param dest_colormap colormap to populate \param dest_colormap colormap to populate
\param skinnum skin number, or a translation mode \param translation translation mode
\param color translation color \param color translation color
\param starttranscolor starting point of the translation
\return void \return void
*/ */
static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, UINT16 color) static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 translation, UINT16 color, INT32 starttranscolor)
{ {
INT32 i, starttranscolor, skinramplength; INT32 i, skinramplength;
// Handle a couple of simple special cases // Handle a couple of simple special cases
if (skinnum < TC_DEFAULT) if (translation < TC_DEFAULT)
{ {
switch (skinnum) switch (translation)
{ {
case TC_ALLWHITE: case TC_ALLWHITE:
memset(dest_colormap, 0, NUM_PALETTE_ENTRIES * sizeof(UINT8)); memset(dest_colormap, 0, NUM_PALETTE_ENTRIES * sizeof(UINT8));
return; return;
case TC_RAINBOW: case TC_RAINBOW:
if (color >= numskincolors) if (color >= numskincolors)
I_Error("Invalid skin color #%hu.", (UINT16)color); I_Error("Invalid skin color #%hu", (UINT16)color);
if (color != SKINCOLOR_NONE) else if (color != SKINCOLOR_NONE)
{ {
R_RainbowColormap(dest_colormap, color); R_RainbowColormap(dest_colormap, color);
return; return;
@ -463,8 +465,8 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U
break; break;
case TC_BLINK: case TC_BLINK:
if (color >= numskincolors) if (color >= numskincolors)
I_Error("Invalid skin color #%hu.", (UINT16)color); I_Error("Invalid skin color #%hu", (UINT16)color);
if (color != SKINCOLOR_NONE) else if (color != SKINCOLOR_NONE)
{ {
memset(dest_colormap, skincolors[color].ramp[3], NUM_PALETTE_ENTRIES * sizeof(UINT8)); memset(dest_colormap, skincolors[color].ramp[3], NUM_PALETTE_ENTRIES * sizeof(UINT8));
return; return;
@ -478,26 +480,28 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U
dest_colormap[i] = (UINT8)i; dest_colormap[i] = (UINT8)i;
// White! // White!
if (skinnum == TC_BOSS) if (translation == TC_BOSS)
{ {
UINT8 *originalColormap = R_GetTranslationColormap(TC_DEFAULT, (skincolornum_t)color, GTC_CACHE); UINT8 *originalColormap = R_GetTranslationColormap(TC_DEFAULT, (skincolornum_t)color, GTC_CACHE);
for (i = 0; i < 16; i++) if (starttranscolor >= NUM_PALETTE_ENTRIES)
I_Error("Invalid startcolor #%d", starttranscolor);
for (i = 0; i < COLORRAMPSIZE; i++)
{ {
dest_colormap[DEFAULT_STARTTRANSCOLOR + i] = originalColormap[DEFAULT_STARTTRANSCOLOR + i]; dest_colormap[starttranscolor + i] = originalColormap[starttranscolor + i];
dest_colormap[31-i] = i; dest_colormap[31-i] = i;
} }
} }
else if (skinnum == TC_METALSONIC) else if (translation == TC_METALSONIC)
{ {
for (i = 0; i < 6; i++) for (i = 0; i < 6; i++)
{ {
dest_colormap[skincolors[SKINCOLOR_BLUE].ramp[12-i]] = skincolors[SKINCOLOR_BLUE].ramp[i]; dest_colormap[skincolors[SKINCOLOR_BLUE].ramp[12-i]] = skincolors[SKINCOLOR_BLUE].ramp[i];
} }
dest_colormap[159] = dest_colormap[253] = dest_colormap[254] = 0; dest_colormap[159] = dest_colormap[253] = dest_colormap[254] = 0;
for (i = 0; i < 16; i++) for (i = 0; i < COLORRAMPSIZE; i++)
dest_colormap[96+i] = dest_colormap[skincolors[SKINCOLOR_COBALT].ramp[i]]; dest_colormap[96+i] = dest_colormap[skincolors[SKINCOLOR_COBALT].ramp[i]];
} }
else if (skinnum == TC_DASHMODE) // This is a long one, because MotorRoach basically hand-picked the indices else if (translation == TC_DASHMODE) // This is a long one, because MotorRoach basically hand-picked the indices
{ {
// greens -> ketchups // greens -> ketchups
dest_colormap[96] = dest_colormap[97] = 48; dest_colormap[96] = dest_colormap[97] = 48;
@ -541,26 +545,21 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U
} }
if (color >= numskincolors) if (color >= numskincolors)
I_Error("Invalid skin color #%hu.", (UINT16)color); I_Error("Invalid skin color #%hu", (UINT16)color);
if (skinnum < 0 && skinnum > TC_DEFAULT)
I_Error("Invalid translation colormap index %d.", skinnum);
starttranscolor = (skinnum != TC_DEFAULT) ? skins[skinnum].starttranscolor : DEFAULT_STARTTRANSCOLOR;
if (starttranscolor >= NUM_PALETTE_ENTRIES) if (starttranscolor >= NUM_PALETTE_ENTRIES)
I_Error("Invalid startcolor #%d.", starttranscolor); I_Error("Invalid startcolor #%d", starttranscolor);
// Fill in the entries of the palette that are fixed // Fill in the entries of the palette that are fixed
for (i = 0; i < starttranscolor; i++) for (i = 0; i < starttranscolor; i++)
dest_colormap[i] = (UINT8)i; dest_colormap[i] = (UINT8)i;
i = starttranscolor + 16; i = starttranscolor + COLORRAMPSIZE;
if (i < NUM_PALETTE_ENTRIES) if (i < NUM_PALETTE_ENTRIES)
{ {
for (i = (UINT8)i; i < NUM_PALETTE_ENTRIES; i++) for (i = (UINT8)i; i < NUM_PALETTE_ENTRIES; i++)
dest_colormap[i] = (UINT8)i; dest_colormap[i] = (UINT8)i;
skinramplength = 16; skinramplength = COLORRAMPSIZE;
} }
else else
skinramplength = i - NUM_PALETTE_ENTRIES; // shouldn't this be NUM_PALETTE_ENTRIES - starttranscolor? skinramplength = i - NUM_PALETTE_ENTRIES; // shouldn't this be NUM_PALETTE_ENTRIES - starttranscolor?
@ -573,7 +572,7 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U
/** \brief Retrieves a translation colormap from the cache. /** \brief Retrieves a translation colormap from the cache.
\param skinnum number of skin, TC_DEFAULT or TC_BOSS \param skinnum number of skin, or translation modes
\param color translation color \param color translation color
\param flags set GTC_CACHE to use the cache \param flags set GTC_CACHE to use the cache
@ -581,25 +580,47 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U
*/ */
UINT8* R_GetTranslationColormap(INT32 skinnum, skincolornum_t color, UINT8 flags) UINT8* R_GetTranslationColormap(INT32 skinnum, skincolornum_t color, UINT8 flags)
{ {
UINT8* ret; UINT8 ***cache = NULL;
INT32 skintableindex = SkinToCacheIndex(skinnum); // Adjust if we want the default colormap INT32 index, starttranscolor;
INT32 i; UINT8 *ret;
// Adjust if we want the default colormap
if (skinnum >= numskins)
I_Error("Invalid skin number %d", skinnum);
else if (skinnum >= 0)
{
cache = skintranslationcache;
starttranscolor = index = skins[skinnum]->starttranscolor;
}
else if (skinnum <= TC_DEFAULT)
{
cache = translationtablecache;
starttranscolor = DEFAULT_STARTTRANSCOLOR;
index = TranslationToCacheIndex(skinnum);
}
else
I_Error("Invalid translation %d", skinnum);
if (flags & GTC_CACHE) if (flags & GTC_CACHE)
{ {
// Allocate table for skin if necessary // Allocate table for skin if necessary
if (!translationtablecache[skintableindex]) if (!cache[index])
translationtablecache[skintableindex] = Z_Calloc(MAXSKINCOLORS * sizeof(UINT8**), PU_STATIC, NULL); cache[index] = Z_Calloc(MAXSKINCOLORS * sizeof(UINT8**), PU_STATIC, NULL);
// Get colormap // Get colormap
ret = translationtablecache[skintableindex][color]; ret = cache[index][color];
// Rebuild the cache if necessary // Rebuild the cache if necessary
if (skincolor_modified[color]) if (skincolor_modified[color])
{ {
for (i = 0; i < (INT32)(sizeof(translationtablecache) / sizeof(translationtablecache[0])); i++) INT32 i;
for (i = 0; i < TT_CACHE_SIZE; i++)
if (translationtablecache[i] && translationtablecache[i][color]) if (translationtablecache[i] && translationtablecache[i][color])
R_GenerateTranslationColormap(translationtablecache[i][color], CacheIndexToSkin(i), color); R_GenerateTranslationColormap(translationtablecache[i][color], CacheIndexToTranslation(i), color, starttranscolor);
for (i = 0; i < NUM_PALETTE_ENTRIES; i++)
if (skintranslationcache[i] && skintranslationcache[i][color])
R_GenerateTranslationColormap(skintranslationcache[i][color], 0, color, i);
skincolor_modified[color] = false; skincolor_modified[color] = false;
} }
@ -610,11 +631,11 @@ UINT8* R_GetTranslationColormap(INT32 skinnum, skincolornum_t color, UINT8 flags
if (!ret) if (!ret)
{ {
ret = Z_MallocAlign(NUM_PALETTE_ENTRIES, (flags & GTC_CACHE) ? PU_LEVEL : PU_STATIC, NULL, 8); ret = Z_MallocAlign(NUM_PALETTE_ENTRIES, (flags & GTC_CACHE) ? PU_LEVEL : PU_STATIC, NULL, 8);
R_GenerateTranslationColormap(ret, skinnum, color); R_GenerateTranslationColormap(ret, skinnum, color, starttranscolor);
// Cache the colormap if desired // Cache the colormap if desired
if (flags & GTC_CACHE) if (flags & GTC_CACHE)
translationtablecache[skintableindex][color] = ret; cache[index][color] = ret;
} }
return ret; return ret;
@ -632,9 +653,12 @@ void R_FlushTranslationColormapCache(void)
{ {
INT32 i; INT32 i;
for (i = 0; i < (INT32)(sizeof(translationtablecache) / sizeof(translationtablecache[0])); i++) for (i = 0; i < TT_CACHE_SIZE; i++)
if (translationtablecache[i]) if (translationtablecache[i])
memset(translationtablecache[i], 0, MAXSKINCOLORS * sizeof(UINT8**)); memset(translationtablecache[i], 0, MAXSKINCOLORS * sizeof(UINT8**));
for (i = 0; i < NUM_PALETTE_ENTRIES; i++)
if (skintranslationcache[i])
memset(skintranslationcache[i], 0, MAXSKINCOLORS * sizeof(UINT8**));
} }
UINT16 R_GetColorByName(const char *name) UINT16 R_GetColorByName(const char *name)

View file

@ -146,7 +146,7 @@ UINT8 *R_GetBlendTable(int style, INT32 alphalevel);
boolean R_BlendLevelVisible(INT32 blendmode, INT32 alphalevel); boolean R_BlendLevelVisible(INT32 blendmode, INT32 alphalevel);
// Color ramp modification should force a recache // Color ramp modification should force a recache
extern UINT8 skincolor_modified[]; extern boolean skincolor_modified[];
void R_InitViewBuffer(INT32 width, INT32 height); void R_InitViewBuffer(INT32 width, INT32 height);
void R_InitViewBorder(void); void R_InitViewBorder(void);

View file

@ -1489,7 +1489,7 @@ static void R_ParseSpriteInfo(boolean spr2)
spritenum_t sprnum = NUMSPRITES; spritenum_t sprnum = NUMSPRITES;
playersprite_t spr2num = NUMPLAYERSPRITES; playersprite_t spr2num = NUMPLAYERSPRITES;
INT32 i; INT32 i;
INT32 skinnumbers[MAXSKINS]; UINT8 *skinnumbers = NULL;
INT32 foundskins = 0; INT32 foundskins = 0;
// Sprite name // Sprite name
@ -1587,7 +1587,9 @@ static void R_ParseSpriteInfo(boolean spr2)
if (skinnum == -1) if (skinnum == -1)
I_Error("Error parsing SPRTINFO lump: Unknown skin \"%s\"", skinName); I_Error("Error parsing SPRTINFO lump: Unknown skin \"%s\"", skinName);
skinnumbers[foundskins] = skinnum; if (skinnumbers == NULL)
skinnumbers = Z_Malloc(sizeof(UINT8) * numskins, PU_STATIC, NULL);
skinnumbers[foundskins] = (UINT8)skinnum;
foundskins++; foundskins++;
} }
else if (stricmp(sprinfoToken, "FRAME")==0) else if (stricmp(sprinfoToken, "FRAME")==0)
@ -1600,8 +1602,7 @@ static void R_ParseSpriteInfo(boolean spr2)
I_Error("Error parsing SPRTINFO lump: No skins specified in this sprite2 definition"); I_Error("Error parsing SPRTINFO lump: No skins specified in this sprite2 definition");
for (i = 0; i < foundskins; i++) for (i = 0; i < foundskins; i++)
{ {
size_t skinnum = skinnumbers[i]; skin_t *skin = skins[skinnumbers[i]];
skin_t *skin = &skins[skinnum];
spriteinfo_t *sprinfo = skin->sprinfo; spriteinfo_t *sprinfo = skin->sprinfo;
M_Memcpy(&sprinfo[spr2num], info, sizeof(spriteinfo_t)); M_Memcpy(&sprinfo[spr2num], info, sizeof(spriteinfo_t));
} }
@ -1625,8 +1626,11 @@ static void R_ParseSpriteInfo(boolean spr2)
{ {
I_Error("Error parsing SPRTINFO lump: Expected \"{\" for sprite \"%s\", got \"%s\"",newSpriteName,sprinfoToken); I_Error("Error parsing SPRTINFO lump: Expected \"{\" for sprite \"%s\", got \"%s\"",newSpriteName,sprinfoToken);
} }
Z_Free(sprinfoToken); Z_Free(sprinfoToken);
Z_Free(info); Z_Free(info);
if (skinnumbers)
Z_Free(skinnumbers);
} }
// //

View file

@ -18,6 +18,7 @@
#include "st_stuff.h" #include "st_stuff.h"
#include "w_wad.h" #include "w_wad.h"
#include "z_zone.h" #include "z_zone.h"
#include "m_menu.h"
#include "m_misc.h" #include "m_misc.h"
#include "info.h" // spr2names #include "info.h" // spr2names
#include "i_video.h" // rendermode #include "i_video.h" // rendermode
@ -32,13 +33,7 @@
#endif #endif
INT32 numskins = 0; INT32 numskins = 0;
skin_t skins[MAXSKINS]; skin_t **skins = NULL;
// FIXTHIS: don't work because it must be inistilised before the config load
//#define SKINVALUES
#ifdef SKINVALUES
CV_PossibleValue_t skin_cons_t[MAXSKINS+1];
#endif
// //
// P_GetSkinSprite2 // P_GetSkinSprite2
@ -105,7 +100,7 @@ static void Sk_SetDefaultValue(skin_t *skin)
// //
memset(skin, 0, sizeof (skin_t)); memset(skin, 0, sizeof (skin_t));
snprintf(skin->name, snprintf(skin->name,
sizeof skin->name, "skin %u", (UINT32)(skin-skins)); sizeof skin->name, "skin %u", (UINT32)(skin->skinnum));
skin->name[sizeof skin->name - 1] = '\0'; skin->name[sizeof skin->name - 1] = '\0';
skin->wadnum = INT16_MAX; skin->wadnum = INT16_MAX;
@ -159,16 +154,6 @@ static void Sk_SetDefaultValue(skin_t *skin)
// //
void R_InitSkins(void) void R_InitSkins(void)
{ {
#ifdef SKINVALUES
INT32 i;
for (i = 0; i <= MAXSKINS; i++)
{
skin_cons_t[i].value = 0;
skin_cons_t[i].strvalue = NULL;
}
#endif
// no default skin! // no default skin!
numskins = 0; numskins = 0;
} }
@ -291,7 +276,7 @@ boolean R_SkinUsable(INT32 playernum, INT32 skinnum)
} }
} }
// returns true if the skin name is found (loaded from pwad) // returns the skin number if the skin name is found (loaded from pwad)
// warning return -1 if not found // warning return -1 if not found
INT32 R_SkinAvailable(const char *name) INT32 R_SkinAvailable(const char *name)
{ {
@ -300,7 +285,7 @@ INT32 R_SkinAvailable(const char *name)
for (i = 0; i < numskins; i++) for (i = 0; i < numskins; i++)
{ {
// search in the skin list // search in the skin list
if (stricmp(skins[i].name,name)==0) if (!stricmp(skins[i]->name,name))
return i; return i;
} }
return -1; return -1;
@ -324,7 +309,7 @@ INT32 R_GetForcedSkin(INT32 playernum)
// Auxillary function that actually sets the skin // Auxillary function that actually sets the skin
static void SetSkin(player_t *player, INT32 skinnum) static void SetSkin(player_t *player, INT32 skinnum)
{ {
skin_t *skin = &skins[skinnum]; skin_t *skin = skins[skinnum];
UINT16 newcolor = 0; UINT16 newcolor = 0;
player->skin = skinnum; player->skin = skinnum;
@ -381,7 +366,7 @@ static void SetSkin(player_t *player, INT32 skinnum)
fixed_t radius = FixedMul(skin->radius, player->mo->scale); fixed_t radius = FixedMul(skin->radius, player->mo->scale);
if ((player->powers[pw_carry] == CR_NIGHTSMODE) && (skin->sprites[SPR2_NFLY].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_NFLY].numframes == 0)) // If you don't have a sprite for flying horizontally, use the default NiGHTS skin.
{ {
skin = &skins[DEFAULTNIGHTSSKIN]; skin = skins[DEFAULTNIGHTSSKIN];
player->followitem = skin->followitem; player->followitem = skin->followitem;
if (!(cv_debug || devparm) && !(netgame || multiplayer || demoplayback)) if (!(cv_debug || devparm) && !(netgame || multiplayer || demoplayback))
newcolor = skin->prefcolor; // will be updated in thinker to flashing newcolor = skin->prefcolor; // will be updated in thinker to flashing
@ -721,8 +706,10 @@ void R_AddSkins(UINT16 wadnum, boolean mainfile)
buf2[size] = '\0'; buf2[size] = '\0';
// set defaults // set defaults
skin = &skins[numskins]; skins = Z_Realloc(skins, sizeof(skin_t*) * (numskins + 1), PU_STATIC, NULL);
skin = skins[numskins] = Z_Calloc(sizeof(skin_t), PU_STATIC, NULL);
Sk_SetDefaultValue(skin); Sk_SetDefaultValue(skin);
skin->skinnum = numskins;
skin->wadnum = wadnum; skin->wadnum = wadnum;
hudname = realname = supername = false; hudname = realname = supername = false;
// parse // parse
@ -836,15 +823,6 @@ next_token:
if (mainfile == false) if (mainfile == false)
CONS_Printf(M_GetText("Added skin '%s'\n"), skin->name); CONS_Printf(M_GetText("Added skin '%s'\n"), skin->name);
#ifdef SKINVALUES
skin_cons_t[numskins].value = numskins;
skin_cons_t[numskins].strvalue = skin->name;
#endif
#ifdef HWRENDER
if (rendermode == render_opengl)
HWR_AddPlayerModel(numskins);
#endif
numskins++; numskins++;
} }
@ -915,7 +893,7 @@ void R_PatchSkins(UINT16 wadnum, boolean mainfile)
strlwr(value); strlwr(value);
skinnum = R_SkinAvailable(value); skinnum = R_SkinAvailable(value);
if (skinnum != -1) if (skinnum != -1)
skin = &skins[skinnum]; skin = skins[skinnum];
else 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); 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);
@ -1066,7 +1044,7 @@ static void R_RefreshSprite2ForWad(UINT16 wadnum, UINT8 start_spr2)
strlwr(value); strlwr(value);
skinnum = R_SkinAvailable(value); skinnum = R_SkinAvailable(value);
if (skinnum != -1) if (skinnum != -1)
skin = &skins[skinnum]; skin = skins[skinnum];
else else
{ {
CONS_Debug(DBG_SETUP, "R_RefreshSprite2ForWad: unknown skin name in P_SKIN lump# %d(%s) in WAD %s\n", lump, W_CheckNameForNumPwad(wadnum,lump), wadfiles[wadnum]->filename); CONS_Debug(DBG_SETUP, "R_RefreshSprite2ForWad: unknown skin name in P_SKIN lump# %d(%s) in WAD %s\n", lump, W_CheckNameForNumPwad(wadnum,lump), wadfiles[wadnum]->filename);

View file

@ -31,7 +31,8 @@
/// The skin_t struct /// The skin_t struct
typedef struct typedef struct
{ {
char name[SKINNAMESIZE+1]; // INT16 descriptive name of the skin char name[SKINNAMESIZE+1]; // name of the skin
UINT8 skinnum;
UINT16 wadnum; UINT16 wadnum;
skinflags_t flags; skinflags_t flags;
@ -85,7 +86,7 @@ typedef struct
/// Externs /// Externs
extern INT32 numskins; extern INT32 numskins;
extern skin_t skins[MAXSKINS]; extern skin_t **skins;
/// Function prototypes /// Function prototypes
void R_InitSkins(void); void R_InitSkins(void);

View file

@ -509,10 +509,6 @@ void R_AddSpriteDefs(UINT16 wadnum)
if (R_AddSingleSpriteDef(sprnames[i], &sprites[i], wadnum, start, end)) if (R_AddSingleSpriteDef(sprnames[i], &sprites[i], wadnum, start, end))
{ {
#ifdef HWRENDER
if (rendermode == render_opengl)
HWR_AddSpriteModel(i);
#endif
// if a new sprite was added (not just replaced) // if a new sprite was added (not just replaced)
addsprites++; addsprites++;
#ifndef ZDEBUG #ifndef ZDEBUG
@ -587,14 +583,10 @@ void R_InitSprites(void)
} }
ST_ReloadSkinFaceGraphics(); ST_ReloadSkinFaceGraphics();
// #ifdef HWRENDER
// check if all sprites have frames if (rendermode == render_opengl)
// HWR_LoadModels();
/* #endif
for (i = 0; i < numsprites; i++)
if (sprites[i].numframes < 1)
CONS_Debug(DBG_SETUP, "R_InitSprites: sprite %s has no frames at all\n", sprnames[i]);
*/
} }
// //
@ -806,8 +798,8 @@ UINT8 *R_GetSpriteTranslation(vissprite_t *vis)
} }
else if (!(vis->cut & SC_PRECIP) && vis->mobj->skin && vis->mobj->sprite == SPR_PLAY) // This thing is a player! else if (!(vis->cut & SC_PRECIP) && vis->mobj->skin && vis->mobj->sprite == SPR_PLAY) // This thing is a player!
{ {
size_t skinnum = (skin_t*)vis->mobj->skin-skins; UINT8 skinnum = ((skin_t*)vis->mobj->skin)->skinnum;
return R_GetTranslationColormap((INT32)skinnum, vis->color, GTC_CACHE); return R_GetTranslationColormap(skinnum, vis->color, GTC_CACHE);
} }
else // Use the defaults else // Use the defaults
return R_GetTranslationColormap(TC_DEFAULT, vis->color, GTC_CACHE); return R_GetTranslationColormap(TC_DEFAULT, vis->color, GTC_CACHE);

View file

@ -43,7 +43,7 @@ typedef enum
// free sfx for S_AddSoundFx() // free sfx for S_AddSoundFx()
#define NUMSFXFREESLOTS 1600 // Matches SOC Editor. #define NUMSFXFREESLOTS 1600 // Matches SOC Editor.
#define NUMSKINSFXSLOTS (MAXSKINS*NUMSKINSOUNDS) #define NUMSKINSFXSLOTS (128*NUMSKINSOUNDS)
// //
// SoundFX struct. // SoundFX struct.
@ -874,7 +874,7 @@ typedef enum
// free slots for S_AddSoundFx() at run-time -------------------- // free slots for S_AddSoundFx() at run-time --------------------
sfx_freeslot0, sfx_freeslot0,
// //
// ... 60 free sounds here ... // ... 1600 free sounds here ...
// //
sfx_lastfreeslot = sfx_freeslot0 + NUMSFXFREESLOTS-1, sfx_lastfreeslot = sfx_freeslot0 + NUMSFXFREESLOTS-1,
// end of freeslots --------------------------------------------- // end of freeslots ---------------------------------------------

View file

@ -54,8 +54,8 @@ UINT16 objectsdrawn = 0;
// STATUS BAR DATA // STATUS BAR DATA
// //
patch_t *faceprefix[MAXSKINS]; // face status patches patch_t **faceprefix; // face status patches
patch_t *superprefix[MAXSKINS]; // super face status patches patch_t **superprefix; // super face status patches
// ------------------------------------------ // ------------------------------------------
// status bar overlay // status bar overlay
@ -135,8 +135,6 @@ static patch_t *gotrflag;
static patch_t *gotbflag; static patch_t *gotbflag;
static patch_t *fnshico; static patch_t *fnshico;
static boolean facefreed[MAXPLAYERS];
hudinfo_t hudinfo[NUMHUDITEMS] = hudinfo_t hudinfo[NUMHUDITEMS] =
{ {
{ 16, 176, V_SNAPTOLEFT|V_SNAPTOBOTTOM}, // HUD_LIVES { 16, 176, V_SNAPTOLEFT|V_SNAPTOBOTTOM}, // HUD_LIVES
@ -368,14 +366,14 @@ void ST_LoadGraphics(void)
// made separate so that skins code can reload custom face graphics // made separate so that skins code can reload custom face graphics
void ST_LoadFaceGraphics(INT32 skinnum) void ST_LoadFaceGraphics(INT32 skinnum)
{ {
if (skins[skinnum].sprites[SPR2_XTRA].numframes > XTRA_LIFEPIC) if (skins[skinnum]->sprites[SPR2_XTRA].numframes > XTRA_LIFEPIC)
{ {
spritedef_t *sprdef = &skins[skinnum].sprites[SPR2_XTRA]; spritedef_t *sprdef = &skins[skinnum]->sprites[SPR2_XTRA];
spriteframe_t *sprframe = &sprdef->spriteframes[XTRA_LIFEPIC]; spriteframe_t *sprframe = &sprdef->spriteframes[XTRA_LIFEPIC];
faceprefix[skinnum] = W_CachePatchNum(sprframe->lumppat[0], PU_HUDGFX); faceprefix[skinnum] = W_CachePatchNum(sprframe->lumppat[0], PU_HUDGFX);
if (skins[skinnum].sprites[(SPR2_XTRA|FF_SPR2SUPER)].numframes > XTRA_LIFEPIC) if (skins[skinnum]->sprites[(SPR2_XTRA|FF_SPR2SUPER)].numframes > XTRA_LIFEPIC)
{ {
sprdef = &skins[skinnum].sprites[SPR2_XTRA|FF_SPR2SUPER]; sprdef = &skins[skinnum]->sprites[SPR2_XTRA|FF_SPR2SUPER];
sprframe = &sprdef->spriteframes[0]; sprframe = &sprdef->spriteframes[0];
superprefix[skinnum] = W_CachePatchNum(sprframe->lumppat[0], PU_HUDGFX); superprefix[skinnum] = W_CachePatchNum(sprframe->lumppat[0], PU_HUDGFX);
} }
@ -384,13 +382,21 @@ void ST_LoadFaceGraphics(INT32 skinnum)
} }
else else
faceprefix[skinnum] = superprefix[skinnum] = W_CachePatchName("MISSING", PU_HUDGFX); // ditto faceprefix[skinnum] = superprefix[skinnum] = W_CachePatchName("MISSING", PU_HUDGFX); // ditto
facefreed[skinnum] = false;
} }
void ST_ReloadSkinFaceGraphics(void) void ST_ReloadSkinFaceGraphics(void)
{ {
INT32 i; INT32 i;
Z_Free(faceprefix);
Z_Free(superprefix);
if (!numskins)
return;
faceprefix = Z_Malloc(sizeof(patch_t *) * numskins, PU_STATIC, NULL);
superprefix = Z_Malloc(sizeof(patch_t *) * numskins, PU_STATIC, NULL);
for (i = 0; i < numskins; i++) for (i = 0; i < numskins; i++)
ST_LoadFaceGraphics(i); ST_LoadFaceGraphics(i);
} }
@ -433,11 +439,6 @@ lumpnum_t st_borderpatchnum;
void ST_Init(void) void ST_Init(void)
{ {
INT32 i;
for (i = 0; i < MAXPLAYERS; i++)
facefreed[i] = true;
if (dedicated) if (dedicated)
return; return;
@ -997,14 +998,14 @@ static void ST_drawLivesArea(void)
// name // name
v_colmap |= (V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER); v_colmap |= (V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER);
if (strlen(skins[stplyr->skin].hudname) <= 5) if (strlen(skins[stplyr->skin]->hudname) <= 5)
V_DrawRightAlignedString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y, v_colmap, skins[stplyr->skin].hudname); V_DrawRightAlignedString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y, v_colmap, skins[stplyr->skin]->hudname);
else if (V_StringWidth(skins[stplyr->skin].hudname, v_colmap) <= 48) else if (V_StringWidth(skins[stplyr->skin]->hudname, v_colmap) <= 48)
V_DrawString(hudinfo[HUD_LIVES].x+18, hudinfo[HUD_LIVES].y, v_colmap, skins[stplyr->skin].hudname); V_DrawString(hudinfo[HUD_LIVES].x+18, hudinfo[HUD_LIVES].y, v_colmap, skins[stplyr->skin]->hudname);
else if (V_ThinStringWidth(skins[stplyr->skin].hudname, v_colmap) <= 40) else if (V_ThinStringWidth(skins[stplyr->skin]->hudname, v_colmap) <= 40)
V_DrawRightAlignedThinString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y, v_colmap, skins[stplyr->skin].hudname); V_DrawRightAlignedThinString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y, v_colmap, skins[stplyr->skin]->hudname);
else else
V_DrawThinString(hudinfo[HUD_LIVES].x+18, hudinfo[HUD_LIVES].y, v_colmap, skins[stplyr->skin].hudname); V_DrawThinString(hudinfo[HUD_LIVES].x+18, hudinfo[HUD_LIVES].y, v_colmap, skins[stplyr->skin]->hudname);
// Power Stones collected // Power Stones collected
if (G_RingSlingerGametype() && LUA_HudEnabled(hud_powerstones)) if (G_RingSlingerGametype() && LUA_HudEnabled(hud_powerstones))

View file

@ -42,7 +42,7 @@ void ST_UnloadGraphics(void);
void ST_LoadGraphics(void); void ST_LoadGraphics(void);
// face load graphics, called when skin changes // face load graphics, called when skin changes
void ST_LoadFaceGraphics(INT32 playernum); void ST_LoadFaceGraphics(INT32 skinnum);
void ST_ReloadSkinFaceGraphics(void); void ST_ReloadSkinFaceGraphics(void);
void ST_doPaletteStuff(void); void ST_doPaletteStuff(void);
@ -76,8 +76,8 @@ extern patch_t *sboscore;
extern patch_t *sbotime; extern patch_t *sbotime;
extern patch_t *sbocolon; extern patch_t *sbocolon;
extern patch_t *sboperiod; extern patch_t *sboperiod;
extern patch_t *faceprefix[MAXSKINS]; // face status patches extern patch_t **faceprefix; // face status patches
extern patch_t *superprefix[MAXSKINS]; // super face status patches extern patch_t **superprefix; // super face status patches
extern patch_t *livesback; extern patch_t *livesback;
extern patch_t *stlivex; extern patch_t *stlivex;
extern patch_t *ngradeletters[7]; extern patch_t *ngradeletters[7];

View file

@ -1060,9 +1060,9 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, IN
// //
void V_DrawContinueIcon(INT32 x, INT32 y, INT32 flags, INT32 skinnum, UINT16 skincolor) void V_DrawContinueIcon(INT32 x, INT32 y, INT32 flags, INT32 skinnum, UINT16 skincolor)
{ {
if (skinnum >= 0 && skinnum < numskins && skins[skinnum].sprites[SPR2_XTRA].numframes > XTRA_CONTINUE) if (skinnum >= 0 && skinnum < numskins && skins[skinnum]->sprites[SPR2_XTRA].numframes > XTRA_CONTINUE)
{ {
spritedef_t *sprdef = &skins[skinnum].sprites[SPR2_XTRA]; spritedef_t *sprdef = &skins[skinnum]->sprites[SPR2_XTRA];
spriteframe_t *sprframe = &sprdef->spriteframes[XTRA_CONTINUE]; spriteframe_t *sprframe = &sprdef->spriteframes[XTRA_CONTINUE];
patch_t *patch = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH); patch_t *patch = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH);
const UINT8 *colormap = R_GetTranslationColormap(skinnum, skincolor, GTC_CACHE); const UINT8 *colormap = R_GetTranslationColormap(skinnum, skincolor, GTC_CACHE);

View file

@ -97,7 +97,7 @@ typedef union
// Continues // Continues
UINT8 continues; UINT8 continues;
patch_t *pcontinues; patch_t *pcontinues;
INT32 *playerchar; // Continue HUD UINT8 *playerchar; // Continue HUD
UINT16 *playercolor; UINT16 *playercolor;
UINT8 gotlife; // Number of extra lives obtained UINT8 gotlife; // Number of extra lives obtained
@ -108,7 +108,7 @@ typedef union
UINT32 scores[MAXPLAYERS]; // Winner's score UINT32 scores[MAXPLAYERS]; // Winner's score
UINT16 *color[MAXPLAYERS]; // Winner's color # UINT16 *color[MAXPLAYERS]; // Winner's color #
boolean spectator[MAXPLAYERS]; // Spectator list boolean spectator[MAXPLAYERS]; // Spectator list
INT32 *character[MAXPLAYERS]; // Winner's character # UINT8 *character[MAXPLAYERS]; // Winner's character #
INT32 num[MAXPLAYERS]; // Winner's player # INT32 num[MAXPLAYERS]; // Winner's player #
char *name[MAXPLAYERS]; // Winner's name char *name[MAXPLAYERS]; // Winner's name
patch_t *result; // RESULT patch_t *result; // RESULT
@ -121,7 +121,7 @@ typedef union
struct struct
{ {
UINT16 *color[MAXPLAYERS]; // Winner's color # UINT16 *color[MAXPLAYERS]; // Winner's color #
INT32 *character[MAXPLAYERS]; // Winner's character # UINT8 *character[MAXPLAYERS]; // Winner's character #
INT32 num[MAXPLAYERS]; // Winner's player # INT32 num[MAXPLAYERS]; // Winner's player #
char name[MAXPLAYERS][9]; // Winner's name char name[MAXPLAYERS][9]; // Winner's name
UINT32 times[MAXPLAYERS]; UINT32 times[MAXPLAYERS];
@ -1382,22 +1382,22 @@ void Y_StartIntermission(void)
else else
{ {
// too long so just show "YOU GOT THROUGH THE ACT" // too long so just show "YOU GOT THROUGH THE ACT"
if (strlen(skins[players[consoleplayer].skin].realname) > 13) if (strlen(skins[players[consoleplayer].skin]->realname) > 13)
{ {
strcpy(data.coop.passed1, "you got"); strcpy(data.coop.passed1, "you got");
strcpy(data.coop.passed2, (mapheaderinfo[gamemap-1]->actnum) ? "through act" : "through the act"); strcpy(data.coop.passed2, (mapheaderinfo[gamemap-1]->actnum) ? "through act" : "through the act");
} }
// long enough that "X GOT" won't fit so use "X PASSED THE ACT" // long enough that "X GOT" won't fit so use "X PASSED THE ACT"
else if (strlen(skins[players[consoleplayer].skin].realname) > 8) else if (strlen(skins[players[consoleplayer].skin]->realname) > 8)
{ {
strcpy(data.coop.passed1, skins[players[consoleplayer].skin].realname); strcpy(data.coop.passed1, skins[players[consoleplayer].skin]->realname);
strcpy(data.coop.passed2, (mapheaderinfo[gamemap-1]->actnum) ? "passed act" : "passed the act"); strcpy(data.coop.passed2, (mapheaderinfo[gamemap-1]->actnum) ? "passed act" : "passed the act");
} }
// length is okay for normal use // length is okay for normal use
else else
{ {
snprintf(data.coop.passed1, sizeof data.coop.passed1, "%s got", snprintf(data.coop.passed1, sizeof data.coop.passed1, "%s got",
skins[players[consoleplayer].skin].realname); skins[players[consoleplayer].skin]->realname);
strcpy(data.coop.passed2, (mapheaderinfo[gamemap-1]->actnum) ? "through act" : "through the act"); strcpy(data.coop.passed2, (mapheaderinfo[gamemap-1]->actnum) ? "through act" : "through the act");
} }
} }
@ -1469,26 +1469,26 @@ void Y_StartIntermission(void)
{ {
snprintf(data.spec.passed1, snprintf(data.spec.passed1,
sizeof data.spec.passed1, "%s", sizeof data.spec.passed1, "%s",
skins[players[consoleplayer].skin].realname); skins[players[consoleplayer].skin]->realname);
data.spec.passed1[sizeof data.spec.passed1 - 1] = '\0'; data.spec.passed1[sizeof data.spec.passed1 - 1] = '\0';
strcpy(data.spec.passed2, "got them all!"); strcpy(data.spec.passed2, "got them all!");
if (players[consoleplayer].charflags & SF_SUPER) if (players[consoleplayer].charflags & SF_SUPER)
{ {
strcpy(data.spec.passed3, "can now become"); strcpy(data.spec.passed3, "can now become");
if (strlen(skins[players[consoleplayer].skin].supername) > 20) //too long, use generic if (strlen(skins[players[consoleplayer].skin]->supername) > 20) //too long, use generic
strcpy(data.spec.passed4, "their super form"); strcpy(data.spec.passed4, "their super form");
else else
strcpy(data.spec.passed4, skins[players[consoleplayer].skin].supername); strcpy(data.spec.passed4, skins[players[consoleplayer].skin]->supername);
} }
} }
else else
{ {
if (strlen(skins[players[consoleplayer].skin].realname) <= SKINNAMESIZE-5) if (strlen(skins[players[consoleplayer].skin]->realname) <= SKINNAMESIZE-5)
{ {
snprintf(data.spec.passed1, snprintf(data.spec.passed1,
sizeof data.spec.passed1, "%s got", sizeof data.spec.passed1, "%s got",
skins[players[consoleplayer].skin].realname); skins[players[consoleplayer].skin]->realname);
data.spec.passed1[sizeof data.spec.passed1 - 1] = '\0'; data.spec.passed1[sizeof data.spec.passed1 - 1] = '\0';
} }
else else