diff --git a/src/deh_lua.c b/src/deh_lua.c
index cc4e0ef3d8b3d0a9b67f8eabc6ccf46b1ab40682..fc3495d06231a883ffcb389ca9c0aadac032675b 100644
--- a/src/deh_lua.c
+++ b/src/deh_lua.c
@@ -60,10 +60,8 @@ static inline int lib_freeslot(lua_State *L)
 		else if (fastcmp(type, "SPR"))
 		{
 			spritenum_t j;
-			if (strlen(word) > MAXSPRITENAME)
-				I_Error("Sprite name is longer than %d characters\n", MAXSPRITENAME);
 			CONS_Printf("Sprite SPR_%s allocated.\n",word);
-			j = P_AllocateSpriteinfo(word);
+			j = P_AllocateSpriteinfo(Z_StrDup(word));
 			LUA_UpdateSprName(word, j);
 			lua_pushinteger(L, j);
 			r++;
@@ -100,21 +98,15 @@ static inline int lib_freeslot(lua_State *L)
 		{
 			// Search if we already have an SPR2 by that name...
 			playersprite_t i;
-			for (i = SPR2_FIRSTFREESLOT; i < free_spr2; i++)
-				if (memcmp(spr2names[i],word,4) == 0)
+			for (i = 0; i < numplayersprites; i++)
+				if (memcmp(playersprites[i]->name,word,4) == 0)
 					break;
-			// We don't, so allocate a new one.
-			if (i >= free_spr2) {
-				if (free_spr2 < NUMPLAYERSPRITES)
-				{
-					CONS_Printf("Sprite SPR2_%s allocated.\n",word);
-					strncpy(spr2names[free_spr2],word,4);
-					spr2defaults[free_spr2] = 0;
-					lua_pushinteger(L, free_spr2);
-					r++;
-					spr2names[free_spr2++][4] = 0;
-				} else
-					CONS_Alert(CONS_WARNING, "Ran out of free SPR2 slots!\n");
+			if (i >= numplayersprites)
+			{
+				// We don't, so allocate a new one.
+				CONS_Printf("Sprite SPR2_%s allocated.\n",word);
+				lua_pushinteger(L, P_AllocatePlayersprite(Z_StrDup(word)));
+				r++;
 			}
 		}
 		else if (fastcmp(type, "TOL"))
@@ -424,18 +416,20 @@ static int ScanConstants(lua_State *L, boolean mathlib, const char *word)
 	}
 	else if (fastncmp("SPR2_",word,5)) {
 		p = word+5;
-		for (i = 0; i < (fixed_t)free_spr2; i++)
-			if (!spr2names[i][4])
+		for (i = 0; i < (fixed_t)numplayersprites; i++)
+			if (!playersprites[i]->name[4])
 			{
 				// special 3-char cases, e.g. SPR2_RUN
-				// the spr2names entry will have "_" on the end, as in "RUN_"
-				if (spr2names[i][3] == '_' && !p[3]) {
-					if (fastncmp(p,spr2names[i],3)) {
+				// the playersprites entry will have "_" on the end, as in "RUN_"
+				if (playersprites[i]->name[3] == '_' && !p[3])
+				{
+					if (fastncmp(p,playersprites[i]->name,3))
+					{
 						CacheAndPushConstant(L, word, i);
 						return 1;
 					}
 				}
-				else if (fastncmp(p,spr2names[i],4)) {
+				else if (fastncmp(p,playersprites[i]->name,4)) {
 					CacheAndPushConstant(L, word, i);
 					return 1;
 				}
diff --git a/src/deh_soc.c b/src/deh_soc.c
index 131274e972e243a3467d1657241c10d113848dc5..f7946ccc9c099c07666ce21a83bbd1f7e9221bcd 100644
--- a/src/deh_soc.c
+++ b/src/deh_soc.c
@@ -446,7 +446,7 @@ void readfreeslots(MYFILE *f)
 					I_Error("Sprite name is longer than %d characters\n", MAXSPRITENAME);
 
 				CONS_Printf("Sprite SPR_%s allocated.\n",word);
-				i = P_AllocateSpriteinfo(word);
+				i = P_AllocateSpriteinfo(Z_StrDup(word));
 				LUA_UpdateSprName(word, i);
 			}
 			else if (fastcmp(type, "S"))
@@ -472,19 +472,14 @@ void readfreeslots(MYFILE *f)
 			else if (fastcmp(type, "SPR2"))
 			{
 				// Search if we already have an SPR2 by that name...
-				for (i = SPR2_FIRSTFREESLOT; i < (int)free_spr2; i++)
-					if (memcmp(spr2names[i],word,4) == 0)
+				for (i = 0; i < (int)numplayersprites; i++)
+					if (memcmp(playersprites[i]->name,word,4) == 0)
 						break;
 				// We found it? (Two mods using the same SPR2 name?) Then don't allocate another one.
-				if (i < (int)free_spr2)
+				if (i < (int)numplayersprites)
 					continue;
-				// Copy in the spr2 name and increment free_spr2.
-				if (free_spr2 < NUMPLAYERSPRITES) {
-					strncpy(spr2names[free_spr2],word,4);
-					spr2defaults[free_spr2] = 0;
-					spr2names[free_spr2++][4] = 0;
-				} else
-					deh_warning("Ran out of free SPR2 slots!\n");
+				CONS_Printf("Sprite SPR2_%s allocated.\n",word);
+				P_AllocatePlayersprite(Z_StrDup(word));
 			}
 			else if (fastcmp(type, "TOL"))
 			{
@@ -989,7 +984,7 @@ void readspriteinfo(MYFILE *f, INT32 num, boolean sprite2)
 			if (fastcmp(word, "LIGHTTYPE"))
 			{
 				if (sprite2)
-					deh_warning("Sprite2 %s: invalid word '%s'", spr2names[num], word);
+					deh_warning("Sprite2 %s: invalid word '%s'", playersprites[num]->name, word);
 				else
 				{
 					INT32 oldvar;
@@ -1005,7 +1000,7 @@ void readspriteinfo(MYFILE *f, INT32 num, boolean sprite2)
 				INT32 skinnum = -1;
 				if (!sprite2)
 				{
-					deh_warning("Sprite %s: %s keyword found outside of SPRITE2INFO block, ignoring", spr2names[num], word);
+					deh_warning("Sprite %s: %s keyword found outside of SPRITE2INFO block, ignoring", playersprites[num]->name, word);
 					continue;
 				}
 
@@ -1014,7 +1009,7 @@ void readspriteinfo(MYFILE *f, INT32 num, boolean sprite2)
 				skinnum = R_SkinAvailable(word2);
 				if (skinnum == -1)
 				{
-					deh_warning("Sprite2 %s: unknown skin %s", spr2names[num], word2);
+					deh_warning("Sprite2 %s: unknown skin %s", playersprites[num]->name, word2);
 					break;
 				}
 
@@ -1027,14 +1022,14 @@ void readspriteinfo(MYFILE *f, INT32 num, boolean sprite2)
 			{
 				if (!sprite2)
 				{
-					deh_warning("Sprite %s: %s keyword found outside of SPRITE2INFO block, ignoring", spr2names[num], word);
+					deh_warning("Sprite %s: %s keyword found outside of SPRITE2INFO block, ignoring", playersprites[num]->name, word);
 					continue;
 				}
-				if (num < (INT32)free_spr2 && num >= (INT32)SPR2_FIRSTFREESLOT)
-					spr2defaults[num] = get_number(word2);
+				if (num > 0 && num < (INT32)numplayersprites)
+					playersprites[num]->defaults = get_number(word2);
 				else
 				{
-					deh_warning("Sprite2 %s: out of range (%d - %d), ignoring", spr2names[num], SPR2_FIRSTFREESLOT, free_spr2-1);
+					deh_warning("Sprite2 %s: out of range (1 - %d), ignoring", playersprites[num]->name, numplayersprites-1);
 					continue;
 				}
 			}
@@ -1045,7 +1040,7 @@ void readspriteinfo(MYFILE *f, INT32 num, boolean sprite2)
 				if (frame >= 64)
 				{
 					if (sprite2)
-						deh_warning("Sprite2 %s: invalid frame %s", spr2names[num], word2);
+						deh_warning("Sprite2 %s: invalid frame %s", playersprites[num]->name, word2);
 					else
 						deh_warning("Sprite %s: invalid frame %s", spriteinfo[num]->name, word2);
 					break;
@@ -1058,7 +1053,7 @@ void readspriteinfo(MYFILE *f, INT32 num, boolean sprite2)
 					INT32 i;
 					if (!foundskins)
 					{
-						deh_warning("Sprite2 %s: no skins specified", spr2names[num]);
+						deh_warning("Sprite2 %s: no skins specified", playersprites[num]->name);
 						break;
 					}
 					for (i = 0; i < foundskins; i++)
@@ -1120,9 +1115,9 @@ void readsprite2(MYFILE *f, INT32 num)
 				word2[strlen(word2)-1] = '\0';
 
 			if (fastcmp(word, "DEFAULT"))
-				spr2defaults[num] = get_number(word2);
+				playersprites[num]->defaults = get_number(word2);
 			else
-				deh_warning("Sprite2 %s: unknown word '%s'", spr2names[num], word);
+				deh_warning("Sprite2 %s: unknown word '%s'", playersprites[num]->name, word);
 		}
 	} while (!myfeof(f)); // finish when the line is empty
 
@@ -4169,8 +4164,8 @@ playersprite_t get_sprite2(const char *word)
 		return atoi(word);
 	if (fastncmp("SPR2_",word,5))
 		word += 5; // take off the SPR2_
-	for (i = 0; i < NUMPLAYERSPRITES; i++)
-		if (!spr2names[i][4] && memcmp(word,spr2names[i],4)==0)
+	for (i = 0; i < numplayersprites; i++)
+		if (!playersprites[i]->name[4] && memcmp(word,playersprites[i]->name,4)==0)
 			return i;
 	deh_warning("Couldn't find sprite named 'SPR2_%s'",word);
 	return SPR2_STND;
diff --git a/src/dehacked.c b/src/dehacked.c
index 05183dc27c01e1dba92b21045af196c95609b7ae..07070e7cb89ee87766a0d12da9e803999ef25ce7 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -325,11 +325,11 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
 				{
 					if (i == 0 && word2[0] != '0') // If word2 isn't a number
 						i = get_sprite2(word2); // find a sprite by name
-					if (i < (INT32)free_spr2 && i >= (INT32)SPR2_FIRSTFREESLOT)
+					if (i < (INT32)numplayersprites && i >= 0)
 						readsprite2(f, i);
 					else
 					{
-						deh_warning("Sprite2 number %d out of range (%d - %d)", i, SPR2_FIRSTFREESLOT, free_spr2-1);
+						deh_warning("Sprite2 number %d out of range (1 - %d)", i, numplayersprites-1);
 						ignorelines(f);
 					}
 				}
@@ -362,11 +362,11 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
 				{
 					if (i == 0 && word2[0] != '0') // If word2 isn't a number
 						i = get_sprite2(word2); // find a sprite by name
-					if (i < NUMPLAYERSPRITES && i >= 0)
+					if ((UINT32)i < numplayersprites && i >= 0)
 						readspriteinfo(f, i, true);
 					else
 					{
-						deh_warning("Sprite2 number %d out of range (0 - %d)", i, NUMPLAYERSPRITES-1);
+						deh_warning("Sprite2 number %d out of range (0 - %d)", i, numplayersprites-1);
 						ignorelines(f);
 					}
 				}
diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c
index 9917058a3a0f557d88707b22bfadb1a668f818e3..4e152e3951053362a4d292b0d330486748762d38 100644
--- a/src/hardware/hw_md2.c
+++ b/src/hardware/hw_md2.c
@@ -1105,7 +1105,7 @@ static modelspr2frames_t *HWR_GetModelSprite2Frames(md2_t *md2, UINT16 spr2)
 
 	spr2 &= SPR2F_MASK;
 
-	if (spr2 >= free_spr2)
+	if (spr2 >= numplayersprites)
 		return NULL;
 
 	if (is_super)
@@ -1157,7 +1157,7 @@ static modelspr2frames_t *HWR_GetModelSprite2(md2_t *md2, skin_t *skin, UINT16 s
 			break;
 		// Use the handy list, that's what it's there for!
 		default:
-			spr2 = spr2defaults[spr2];
+			spr2 = playersprites[spr2]->defaults;
 			break;
 		}
 
diff --git a/src/hardware/hw_model.c b/src/hardware/hw_model.c
index 5856473e4c9855c6416f97843cd476fde2c587d2..1205bcd366f6abb248666de1e293f66cee585ab8 100644
--- a/src/hardware/hw_model.c
+++ b/src/hardware/hw_model.c
@@ -334,19 +334,19 @@ void LoadModelSprite2(model_t *model)
 			if ((super = (!memcmp(prefix, "SUPER", 5))) || (!memcmp(prefix, "SPR2_", 5)))
 			{
 				spr2idx = 0;
-				while (spr2idx < free_spr2)
+				while (spr2idx < numplayersprites)
 				{
 					modelspr2frames_t *frames = NULL;
-					if (!memcmp(spr2names[spr2idx], name, 4))
+					if (!memcmp(playersprites[spr2idx]->name, name, 4))
 					{
 						if (!spr2frames)
-							spr2frames = (modelspr2frames_t*)Z_Calloc(sizeof(modelspr2frames_t)*NUMPLAYERSPRITES, PU_STATIC, NULL);
+							spr2frames = (modelspr2frames_t*)Z_Calloc(sizeof(modelspr2frames_t)*numplayersprites, PU_STATIC, NULL);
 						frames = spr2frames;
 
 						if (super)
 						{
 							if (!superspr2frames)
-								superspr2frames = (modelspr2frames_t*)Z_Calloc(sizeof(modelspr2frames_t)*NUMPLAYERSPRITES, PU_STATIC, NULL);
+								superspr2frames = (modelspr2frames_t*)Z_Calloc(sizeof(modelspr2frames_t)*numplayersprites, PU_STATIC, NULL);
 							frames = superspr2frames;
 						}
 
diff --git a/src/info.c b/src/info.c
index 59d3243733a9f8b655f5ed4315d0d79a9de97f3c..aab2a7dee65e35b64602ff71c02644135c96da3c 100644
--- a/src/info.c
+++ b/src/info.c
@@ -529,162 +529,87 @@ static const char sprnames[][MAXSPRITENAME + 1] =
 UINT32 numspriteinfo;
 spriteinfo_t **spriteinfo;
 
-char spr2names[NUMPLAYERSPRITES][MAXSPRITENAME + 1] =
+static const sprite2_t startplayersprites[] =
 {
-	"STND",
-	"WAIT",
-	"WALK",
-	"SKID",
-	"RUN_",
-	"DASH",
-	"PAIN",
-	"STUN",
-	"DEAD",
-	"DRWN",
-	"ROLL",
-	"GASP",
-	"JUMP",
-	"SPNG",
-	"FALL",
-	"EDGE",
-	"RIDE",
-
-	"SPIN",
-
-	"FLY_",
-	"SWIM",
-	"TIRE",
-
-	"GLID",
-	"LAND",
-	"CLNG",
-	"CLMB",
-
-	"FLT_",
-	"FRUN",
-
-	"BNCE",
-
-	"FIRE",
-
-	"TWIN",
-
-	"MLEE",
-	"MLEL",
-
-	"TRNS",
-
-	"NSTD",
-	"NFLT",
-	"NFLY",
-	"NDRL",
-	"NSTN",
-	"NPUL",
-	"NATK",
-
-	"TAL0",
-	"TAL1",
-	"TAL2",
-	"TAL3",
-	"TAL4",
-	"TAL5",
-	"TAL6",
-	"TAL7",
-	"TAL8",
-	"TAL9",
-	"TALA",
-	"TALB",
-	"TALC",
-
-	"CNT1",
-	"CNT2",
-	"CNT3",
-	"CNT4",
-
-	"SIGN",
-	"LIFE",
-
-	"XTRA",
-};
-playersprite_t free_spr2 = SPR2_FIRSTFREESLOT;
-
-playersprite_t spr2defaults[NUMPLAYERSPRITES] = {
-	0, // SPR2_STND,
-	0, // SPR2_WAIT,
-	0, // SPR2_WALK,
-	SPR2_WALK, // SPR2_SKID,
-	SPR2_WALK, // SPR2_RUN ,
-	SPR2_FRUN, // SPR2_DASH,
-	0, // SPR2_PAIN,
-	SPR2_PAIN, // SPR2_STUN,
-	SPR2_PAIN, // SPR2_DEAD,
-	SPR2_DEAD, // SPR2_DRWN,
-	0, // SPR2_ROLL,
-	SPR2_SPNG, // SPR2_GASP,
-	0, // SPR2_JUMP, (conditional, will never be referenced)
-	SPR2_FALL, // SPR2_SPNG,
-	SPR2_WALK, // SPR2_FALL,
-	0, // SPR2_EDGE,
-	SPR2_FALL, // SPR2_RIDE,
-
-	SPR2_ROLL, // SPR2_SPIN,
-
-	SPR2_SPNG, // SPR2_FLY ,
-	SPR2_FLY , // SPR2_SWIM,
-	0, // SPR2_TIRE, (conditional, will never be referenced)
-
-	SPR2_FLY , // SPR2_GLID,
-	SPR2_ROLL, // SPR2_LAND,
-	SPR2_CLMB, // SPR2_CLNG,
-	SPR2_ROLL, // SPR2_CLMB,
-
-	SPR2_WALK, // SPR2_FLT ,
-	SPR2_RUN , // SPR2_FRUN,
-
-	SPR2_FALL, // SPR2_BNCE,
-
-	0, // SPR2_FIRE,
-
-	SPR2_ROLL, // SPR2_TWIN,
-
-	SPR2_TWIN, // SPR2_MLEE,
-	0, // SPR2_MLEL,
-
-	0, // SPR2_TRNS,
-
-	SPR2_STND, // SPR2_NSTD,
-	SPR2_FALL, // SPR2_NFLT,
-	0, // SPR2_NFLY, (will never be referenced unless skin 0 lacks this)
-	SPR2_NFLY, // SPR2_NDRL,
-	SPR2_STUN, // SPR2_NSTN,
-	SPR2_NSTN, // SPR2_NPUL,
-	SPR2_ROLL, // SPR2_NATK,
-
-	0, // SPR2_TAL0, (this will look mighty stupid but oh well)
-	SPR2_TAL0, // SPR2_TAL1,
-	SPR2_TAL1, // SPR2_TAL2,
-	SPR2_TAL2, // SPR2_TAL3,
-	SPR2_TAL1, // SPR2_TAL4,
-	SPR2_TAL4, // SPR2_TAL5,
-	SPR2_TAL0, // SPR2_TAL6,
-	SPR2_TAL3, // SPR2_TAL7,
-	SPR2_TAL7, // SPR2_TAL8,
-	SPR2_TAL0, // SPR2_TAL9,
-	SPR2_TAL9, // SPR2_TALA,
-	SPR2_TAL0, // SPR2_TALB,
-	SPR2_TAL6, // SPR2_TALC,
-
-	SPR2_WAIT, // SPR2_CNT1,
-	SPR2_FALL, // SPR2_CNT2,
-	SPR2_SPNG, // SPR2_CNT3,
-	SPR2_CNT1, // SPR2_CNT4,
-
-	0, // SPR2_SIGN,
-	0, // SPR2_LIFE,
-
-	0, // SPR2_XTRA (should never be referenced)
+	{"STND", 0}, 
+	{"WAIT", 0}, 
+	{"WALK", 0}, 
+	{"SKID", SPR2_WALK}, 
+	{"RUN", SPR2_WALK},
+	{"DASH", SPR2_FRUN}, 
+	{"PAIN", 0}, 
+	{"STUN", SPR2_PAIN}, 
+	{"DEAD", SPR2_PAIN}, 
+	{"DRWN", SPR2_DEAD}, 
+	{"ROLL", 0}, 
+	{"GASP", SPR2_SPNG}, 
+	{"JUMP", 0}, // (conditional, will never be referenced)
+	{"SPNG", SPR2_FALL}, 
+	{"FALL", SPR2_WALK}, 
+	{"EDGE", 0}, 
+	{"RIDE", SPR2_FALL}, 
+
+	{"SPIN", SPR2_ROLL}, 
+
+	{"FLY", SPR2_SPNG},
+	{"SWIM", SPR2_FLY}, 
+	{"TIRE", 0}, // (conditional, will never be referenced)
+
+	{"GLID", SPR2_FLY} , 
+	{"LAND", SPR2_ROLL}, 
+	{"CLNG", SPR2_CLMB}, 
+	{"CLMB", SPR2_ROLL}, 
+
+	{"FLT", SPR2_WALK},
+	{"FRUN", SPR2_RUN}, 
+
+	{"BNCE", SPR2_FALL}, 
+
+	{"FIRE", 0}, 
+
+	{"TWIN", SPR2_ROLL}, 
+
+	{"MLEE", SPR2_TWIN}, 
+	{"MLEL", 0}, 
+
+	{"TRNS", 0}, 
+
+	{"NSTD", SPR2_STND}, 
+	{"NFLT", SPR2_FALL}, 
+	{"NFLY", 0}, // (will never be referenced unless skin 0 lacks this)
+	{"NDRL", SPR2_NFLY}, 
+	{"NSTN", SPR2_STUN}, 
+	{"NPUL", SPR2_NSTN}, 
+	{"NATK", SPR2_ROLL}, 
+
+	{"TAL0", 0}, // (this will look mighty stupid but oh well)
+	{"TAL1", SPR2_TAL0}, 
+	{"TAL2", SPR2_TAL1}, 
+	{"TAL3", SPR2_TAL2}, 
+	{"TAL4", SPR2_TAL1}, 
+	{"TAL5", SPR2_TAL4}, 
+	{"TAL6", SPR2_TAL0}, 
+	{"TAL7", SPR2_TAL3}, 
+	{"TAL8", SPR2_TAL7}, 
+	{"TAL9", SPR2_TAL0}, 
+	{"TALA", SPR2_TAL9}, 
+	{"TALB", SPR2_TAL0}, 
+	{"TALC", SPR2_TAL6}, 
+
+	{"CNT1", SPR2_WAIT}, 
+	{"CNT2", SPR2_FALL}, 
+	{"CNT3", SPR2_SPNG}, 
+	{"CNT4", SPR2_CNT1}, 
+
+	{"SIGN", 0}, 
+	{"LIFE", 0}, 
+
+	{"XTRA", 0}, // (should never be referenced)
 };
 
+UINT32 numplayersprites;
+sprite2_t **playersprites;
+
 // Doesn't work with g++, needs actionf_p1 (don't modify this comment)
 static const state_t startstates[] =
 {
@@ -22497,13 +22422,22 @@ UINT32 P_AllocateSpriteinfo(const char *name)
 	spriteinfo = Z_Realloc(spriteinfo, sizeof(*spriteinfo) * ++numspriteinfo, PU_STATIC, NULL);
 	spriteinfo[numspriteinfo-1] = Z_Malloc(sizeof(spriteinfo_t), PU_STATIC, NULL);
 	memset(spriteinfo[numspriteinfo-1], 0, sizeof(spriteinfo_t));
-	strcpy(spriteinfo[numspriteinfo-1]->name, name);
+	spriteinfo[numspriteinfo-1]->name = name;
 	R_ResizeSprites();
 	HWR_AllocateMD2Model();
 	HWR_AllocateLSpr();
 	return numspriteinfo-1;
 }
 
+UINT32 P_AllocatePlayersprite(const char *name)
+{
+	playersprites = Z_Realloc(playersprites, sizeof(*playersprites) * ++numplayersprites, PU_STATIC, NULL);
+	playersprites[numplayersprites-1] = Z_Malloc(sizeof(playersprite_t), PU_STATIC, NULL);
+	memset(playersprites[numplayersprites-1], 0, sizeof(playersprite_t));
+	playersprites[numplayersprites-1]->name = name;
+	return numplayersprites-1;
+}
+
 UINT32 P_GetMobjinfoIndex(mobjinfo_t *info)
 {
 	UINT32 i;
@@ -22552,10 +22486,18 @@ void P_InitializeTables(void)
 	{
 		spriteinfo[i] = Z_Malloc(sizeof(spriteinfo_t), PU_STATIC, NULL);
 		memset(spriteinfo[i], 0, sizeof(spriteinfo_t));
-		strcpy(spriteinfo[i]->name, sprnames[i]);
+		spriteinfo[i]->name = sprnames[i];
 	}
 	HWR_AllocateMD2Model();
 	HWR_AllocateLSpr();
+
+	numplayersprites = sizeof(startplayersprites) / sizeof(startplayersprites[0]);
+	playersprites = Z_Malloc(sizeof(*playersprites) * numplayersprites, PU_STATIC, NULL);
+	for (i = 0; i < numplayersprites; i++)
+	{
+		playersprites[i] = Z_Malloc(sizeof(sprite2_t), PU_STATIC, NULL);
+		memcpy(playersprites[i], &startplayersprites[i], sizeof(sprite2_t));
+	}
 }
 
 void P_BackupTables(void)
@@ -22585,7 +22527,7 @@ void P_ResetData(INT32 flags)
 		for (i = 0; i < sizeof(sprnames) / sizeof(sprnames[0]); i++)
 		{
 			memset(spriteinfo[numspriteinfo-1], 0, sizeof(spriteinfo_t));
-			strcpy(spriteinfo[i]->name, sprnames[i]);
+			spriteinfo[i]->name = sprnames[i];
 		}
 	}
 
diff --git a/src/info.h b/src/info.h
index e9f4e1a547738f3ec68748e22cd8e1ed8c803fa9..10865ebc9ed667059f5f25af36f216df804aee2e 100644
--- a/src/info.h
+++ b/src/info.h
@@ -1151,10 +1151,6 @@ typedef enum playersprite
 	SPR2_LIFE, // life monitor icon
 
 	SPR2_XTRA, // stuff that isn't in-map - "would this ever need an md2 or variable length animation?"
-
-	SPR2_FIRSTFREESLOT,
-	SPR2_LASTFREESLOT = 1024, // Do not make higher than SPR2F_MASK (currently 0x3FF) plus one
-	NUMPLAYERSPRITES
 } playersprite_t;
 
 #define MAXFRAMENUM 256
@@ -1166,7 +1162,7 @@ typedef struct
 
 typedef struct
 {
-	char name[MAXSPRITENAME+1];
+	const char *name;
 	spriteframepivot_t pivot[MAXFRAMENUM];
 	boolean available;
 } spriteinfo_t;
@@ -1174,6 +1170,15 @@ typedef struct
 extern UINT32 numspriteinfo;
 extern spriteinfo_t **spriteinfo;
 
+typedef struct
+{
+	const char *name;
+	playersprite_t defaults;
+} sprite2_t;
+
+extern UINT32 numplayersprites;
+extern sprite2_t **playersprites;
+
 enum
 {
 	XTRA_LIFEPIC,
@@ -4395,11 +4400,7 @@ typedef struct
 
 extern state_t **states;
 extern UINT32 numstates;
-
-extern char spr2names[NUMPLAYERSPRITES][MAXSPRITENAME + 1];
-extern playersprite_t spr2defaults[NUMPLAYERSPRITES];
 extern state_t *astate;
-extern playersprite_t free_spr2;
 
 typedef enum mobj_type
 {
@@ -5211,6 +5212,7 @@ extern UINT32 nummobjinfo;
 UINT32 P_AllocateMobjinfo(const char *name);
 UINT32 P_AllocateState(const char *name);
 UINT32 P_AllocateSpriteinfo(const char *name);
+UINT32 P_AllocatePlayersprite(const char *name);
 UINT32 P_GetMobjinfoIndex(mobjinfo_t *info);
 UINT32 P_GetSpriteinfoIndex(spriteinfo_t *info);
 void P_InitializeTables(void);
diff --git a/src/lua_baselib.c b/src/lua_baselib.c
index 6575a5f43b4c2f6efa591eaa7a9be7c4163d1f01..a1e22ea57f85509ba75af6e8ee1d9045d5aae087 100644
--- a/src/lua_baselib.c
+++ b/src/lua_baselib.c
@@ -3139,8 +3139,8 @@ static int lib_pIsStateSprite2Super(lua_State *L)
 static int lib_pGetSuperSprite2(lua_State *L)
 {
 	int animID = luaL_checkinteger(L, 1) & SPR2F_MASK;
-	if (animID < 0 || animID >= NUMPLAYERSPRITES)
-		return luaL_error(L, "sprite2 %d out of range (0 - %d)", animID, NUMPLAYERSPRITES-1);
+	if (animID < 0 || animID >= numplayersprites)
+		return luaL_error(L, "sprite2 %d out of range (0 - %d)", animID, numplayersprites-1);
 
 	lua_pushinteger(L, animID | SPR2F_SUPER);
 	return 1;
diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c
index 57544947da5b0b6263ec17c56d9808b7246d2596..45e879a6e85595eafec0c1ef5d838bf1c3d9e47a 100644
--- a/src/lua_hudlib.c
+++ b/src/lua_hudlib.c
@@ -587,17 +587,17 @@ static int libd_getSprite2Patch(lua_State *L)
 			j &= ~SPR2F_SUPER; // remove flag so the next check doesn't fail
 		}
 
-		if (j >= free_spr2)
+		if (j >= numplayersprites)
 			return 0;
 	}
 	else if (lua_isstring(L, 1)) // sprite prefix name given, e.g. "STND"
 	{
 		const char *name = lua_tostring(L, 1);
-		for (j = 0; j < free_spr2; j++)
-			if (fastcmp(name, spr2names[j]))
+		for (j = 0; j < numplayersprites; j++)
+			if (fastcmp(name, playersprites[j]->name))
 				break;
 		// if you want super flags you'll have to use the optional boolean following this
-		if (j >= free_spr2)
+		if (j >= numplayersprites)
 			return 0;
 	}
 	else
diff --git a/src/lua_infolib.c b/src/lua_infolib.c
index 1b2322f116b5672ae485aa77be97423816adbb21..3adabc517e1ec8dd7707e79d17d73740b2c666c2 100644
--- a/src/lua_infolib.c
+++ b/src/lua_infolib.c
@@ -119,16 +119,16 @@ static int lib_getSpr2name(lua_State *L)
 	if (lua_isnumber(L, 1))
 	{
 		i = lua_tonumber(L, 1);
-		if (i >= free_spr2)
+		if (i >= numplayersprites)
 			return 0;
-		lua_pushlstring(L, spr2names[i], 4);
+		lua_pushlstring(L, playersprites[i]->name, 4);
 		return 1;
 	}
 	else if (lua_isstring(L, 1))
 	{
 		const char *name = lua_tostring(L, 1);
-		for (i = 0; i < free_spr2; i++)
-			if (fastcmp(name, spr2names[i]))
+		for (i = 0; i < numplayersprites; i++)
+			if (fastcmp(name, playersprites[i]->name))
 			{
 				lua_pushinteger(L, i);
 				return 1;
@@ -148,17 +148,17 @@ static int lib_getSpr2default(lua_State *L)
 	else if (lua_isstring(L, 1))
 	{
 		const char *name = lua_tostring(L, 1);
-		for (i = 0; i < free_spr2; i++)
-			if (fastcmp(name, spr2names[i]))
+		for (i = 0; i < numplayersprites; i++)
+			if (fastcmp(name, playersprites[i]->name))
 				break;
 	}
 	else
 		return luaL_error(L, "spr2defaults[] invalid index");
 
-	if (i >= free_spr2)
-		return luaL_error(L, "spr2defaults[] index %d out of range (%d - %d)", i, 0, free_spr2-1);
+	if (i >= numplayersprites)
+		return luaL_error(L, "spr2defaults[] index %d out of range (%d - %d)", i, 0, numplayersprites-1);
 
-	lua_pushinteger(L, spr2defaults[i]);
+	lua_pushinteger(L, playersprites[i]->defaults);
 	return 1;
 }
 
@@ -173,13 +173,6 @@ static int lib_setSpr2default(lua_State *L)
 		return luaL_error(L, "Do not alter spr2defaults[] in CMD building code!");
 
 // todo: maybe allow setting below first freeslot..? step 1 is toggling this, step 2 is testing to see whether it's net-safe
-#ifdef SETALLSPR2DEFAULTS
-#define FIRSTMODIFY 0
-#else
-#define FIRSTMODIFY SPR2_FIRSTFREESLOT
-	if (free_spr2 == SPR2_FIRSTFREESLOT)
-		return luaL_error(L, "You can only modify the spr2defaults[] entries of sprite2 freeslots, and none are currently added.");
-#endif
 
 	lua_remove(L, 1); // don't care about spr2defaults[] dummy userdata.
 
@@ -188,19 +181,19 @@ static int lib_setSpr2default(lua_State *L)
 	else if (lua_isstring(L, 1))
 	{
 		const char *name = lua_tostring(L, 1);
-		for (i = 0; i < free_spr2; i++)
+		for (i = 0; i < numplayersprites; i++)
 		{
-			if (fastcmp(name, spr2names[i]))
+			if (fastcmp(name, playersprites[i]->name))
 				break;
 		}
-		if (i == free_spr2)
+		if (i == numplayersprites)
 			return luaL_error(L, "spr2defaults[] invalid index");
 	}
 	else
 		return luaL_error(L, "spr2defaults[] invalid index");
 
-	if (i < FIRSTMODIFY || i >= free_spr2)
-		return luaL_error(L, "spr2defaults[] index %d out of range (%d - %d)", i, FIRSTMODIFY, free_spr2-1);
+	if (i < 0 || i >= numplayersprites)
+		return luaL_error(L, "spr2defaults[] index %d out of range (0 - %d)", i, numplayersprites-1);
 #undef FIRSTMODIFY
 
 	if (lua_isnumber(L, 2))
@@ -208,27 +201,27 @@ static int lib_setSpr2default(lua_State *L)
 	else if (lua_isstring(L, 2))
 	{
 		const char *name = lua_tostring(L, 2);
-		for (j = 0; j < free_spr2; j++)
+		for (j = 0; j < numplayersprites; j++)
 		{
-			if (fastcmp(name, spr2names[j]))
+			if (fastcmp(name, playersprites[j]->name))
 				break;
 		}
-		if (j == free_spr2)
+		if (j == numplayersprites)
 			return luaL_error(L, "spr2defaults[] invalid set");
 	}
 	else
 		return luaL_error(L, "spr2defaults[] invalid set");
 
-	if (j >= free_spr2)
-		return luaL_error(L, "spr2defaults[] set %d out of range (%d - %d)", j, 0, free_spr2-1);
+	if (j >= numplayersprites)
+		return luaL_error(L, "spr2defaults[] set %d out of range (0 - %d)", j, numplayersprites-1);
 
-	spr2defaults[i] = j;
+	playersprites[i]->defaults = j;
 	return 0;
 }
 
 static int lib_spr2namelen(lua_State *L)
 {
-	lua_pushinteger(L, free_spr2);
+	lua_pushinteger(L, numplayersprites);
 	return 1;
 }
 
diff --git a/src/lua_skinlib.c b/src/lua_skinlib.c
index 24d948a6735c3c723dcbf86c285a23c8367090dd..598f26fc24204f4d33a20bda1e0e1dd991658235 100644
--- a/src/lua_skinlib.c
+++ b/src/lua_skinlib.c
@@ -352,8 +352,8 @@ static int lib_getSkinSprite(lua_State *L)
 	spritedef_t *sksprites = *(spritedef_t **)luaL_checkudata(L, 1, META_SKINSPRITES);
 	playersprite_t i = luaL_checkinteger(L, 2);
 
-	if (i < 0 || i >= NUMPLAYERSPRITES)
-		return luaL_error(L, "skin sprites index %d out of range (0 - %d)", i, NUMPLAYERSPRITES-1);
+	if (i < 0 || i >= numplayersprites)
+		return luaL_error(L, "skin sprites index %d out of range (0 - %d)", i, numplayersprites-1);
 
 	LUA_PushUserdata(L, &sksprites[i], META_SKINSPRITESLIST);
 	return 1;
@@ -362,7 +362,7 @@ static int lib_getSkinSprite(lua_State *L)
 // #skin.sprites -> NUMPLAYERSPRITES
 static int lib_numSkinsSprites(lua_State *L)
 {
-	lua_pushinteger(L, NUMPLAYERSPRITES);
+	lua_pushinteger(L, numplayersprites);
 	return 1;
 }
 
diff --git a/src/p_pspr.h b/src/p_pspr.h
index 5fb6767633398d1e304001123dcda541599b1aba..ce7487f61e398d1f0aaf5fd9a5ee3c70636741a9 100644
--- a/src/p_pspr.h
+++ b/src/p_pspr.h
@@ -98,9 +98,9 @@
 #define FF_RANDOMANIM 0x40000000
 
 /// \brief Animation flags: Bits used for the animation ID
-#define SPR2F_MASK 0x3FF
+#define SPR2F_MASK 0x7FFFFFFF
 /// \brief Animation flags: "Super" flag
-#define SPR2F_SUPER 0x400
+#define SPR2F_SUPER 0x80000000
 
 /**	\brief translucency tables
 
diff --git a/src/r_picformats.c b/src/r_picformats.c
index bacb5fc263891d5a8a39ad45ff0d25dedec23df2..195fa9c94f834838d8e00ab4939fca7bcfe4e195 100644
--- a/src/r_picformats.c
+++ b/src/r_picformats.c
@@ -1572,7 +1572,7 @@ static void R_ParseSpriteInfo(boolean spr2)
 	size_t sprinfoTokenLength;
 	char newSpriteName[MAXSPRITENAME + 1]; // no longer dynamically allocated
 	spritenum_t sprnum = numspriteinfo;
-	playersprite_t spr2num = NUMPLAYERSPRITES;
+	playersprite_t spr2num = numplayersprites;
 	INT32 i;
 	UINT8 *skinnumbers = NULL;
 	INT32 foundskins = 0;
@@ -1598,11 +1598,11 @@ static void R_ParseSpriteInfo(boolean spr2)
 	}
 	else
 	{
-		for (i = 0; i <= NUMPLAYERSPRITES; i++)
+		for (i = 0; i <= numplayersprites; i++)
 		{
-			if (i == NUMPLAYERSPRITES)
+			if (i == numplayersprites)
 				I_Error("Error parsing SPRTINFO lump: Unknown sprite2 name \"%s\"", newSpriteName);
-			if (!memcmp(newSpriteName,spr2names[i],4))
+			if (!memcmp(newSpriteName,playersprites[i]->name,4))
 			{
 				spr2num = i;
 				break;
diff --git a/src/r_skins.c b/src/r_skins.c
index f378f30d379739ade7073fe6ec0484f48a049369..fc9232db8ac63f9621de81082eb9ad0198a4118f 100644
--- a/src/r_skins.c
+++ b/src/r_skins.c
@@ -36,7 +36,7 @@ INT32 numskins = 0;
 skin_t **skins = NULL;
 
 // Gets the animation ID of a state
-UINT16 P_GetStateSprite2(state_t *state)
+UINT32 P_GetStateSprite2(state_t *state)
 {
 	if (state->sprite2)
 		return state->sprite2;
@@ -54,7 +54,7 @@ UINT16 P_GetStateSprite2(state_t *state)
 }
 
 // Gets the starting frame of an animation
-UINT16 P_GetSprite2StateFrame(state_t *state)
+UINT32 P_GetSprite2StateFrame(state_t *state)
 {
 	if (state->sprite2)
 		return state->frame & FF_FRAMEMASK;
@@ -77,7 +77,7 @@ boolean P_IsStateSprite2Super(state_t *state)
 }
 
 // Applies SPR2F_SUPER to an animation based on the actor's state
-UINT16 P_ApplySuperFlagToSprite2(UINT16 spr2, mobj_t *mobj)
+UINT32 P_ApplySuperFlagToSprite2(UINT32 spr2, mobj_t *mobj)
 {
 	if (mobj->player)
 	{
@@ -100,9 +100,9 @@ UINT16 P_ApplySuperFlagToSprite2(UINT16 spr2, mobj_t *mobj)
 
 // For non-super players, this tries each sprite2's immediate predecessor until it finds one with a number of frames or ends up at standing.
 // For super players, does the same as above - but tries the super equivalent for each sprite2 before the non-super version.
-UINT16 P_GetSkinSprite2(skin_t *skin, UINT16 spr2, player_t *player)
+UINT32 P_GetSkinSprite2(skin_t *skin, UINT32 spr2, player_t *player)
 {
-	UINT16 super = 0;
+	UINT32 super = 0;
 	UINT8 i = 0;
 
 	if (!skin)
@@ -136,7 +136,7 @@ UINT16 P_GetSkinSprite2(skin_t *skin, UINT16 spr2, player_t *player)
 			break;
 		// Use the handy list, that's what it's there for!
 		default:
-			spr2 = spr2defaults[spr2];
+			spr2 = playersprites[spr2]->defaults;
 			break;
 		}
 
@@ -150,7 +150,7 @@ UINT16 P_GetSkinSprite2(skin_t *skin, UINT16 spr2, player_t *player)
 }
 
 // Gets the spritedef of a skin animation
-spritedef_t *P_GetSkinSpritedef(skin_t *skin, UINT16 spr2)
+spritedef_t *P_GetSkinSpritedef(skin_t *skin, UINT32 spr2)
 {
 	if (!skin)
 		return NULL;
@@ -159,7 +159,7 @@ spritedef_t *P_GetSkinSpritedef(skin_t *skin, UINT16 spr2)
 
 	spr2 &= SPR2F_MASK;
 
-	if (spr2 >= free_spr2)
+	if (spr2 >= numplayersprites)
 		return NULL;
 
 	if (is_super)
@@ -169,7 +169,7 @@ spritedef_t *P_GetSkinSpritedef(skin_t *skin, UINT16 spr2)
 }
 
 // Gets the spriteinfo of a skin animation
-spriteinfo_t *P_GetSkinSpriteInfo(skin_t *skin, UINT16 spr2)
+spriteinfo_t *P_GetSkinSpriteInfo(skin_t *skin, UINT32 spr2)
 {
 	if (!skin)
 		return NULL;
@@ -178,7 +178,7 @@ spriteinfo_t *P_GetSkinSpriteInfo(skin_t *skin, UINT16 spr2)
 
 	spr2 &= SPR2F_MASK;
 
-	if (spr2 >= free_spr2)
+	if (spr2 >= numplayersprites)
 		return NULL;
 
 	if (is_super)
@@ -188,7 +188,7 @@ spriteinfo_t *P_GetSkinSpriteInfo(skin_t *skin, UINT16 spr2)
 }
 
 // Checks if a skin animation is valid
-boolean P_IsValidSprite2(skin_t *skin, UINT16 spr2)
+boolean P_IsValidSprite2(skin_t *skin, UINT32 spr2)
 {
 	spritedef_t *sprdef = P_GetSkinSpritedef(skin, spr2);
 	return sprdef && sprdef->numframes;
@@ -602,10 +602,18 @@ static UINT16 W_CheckForPatchSkinMarkerInPwad(UINT16 wadid, UINT16 startlump)
 	return INT16_MAX; // not found
 }
 
-static void R_LoadSkinSprites(UINT16 wadnum, UINT16 *lump, UINT16 *lastlump, skin_t *skin, UINT16 start_spr2)
+static void R_LoadSkinSprites(UINT16 wadnum, UINT16 *lump, UINT16 *lastlump, skin_t *skin, UINT32 start_spr2)
 {
 	UINT16 newlastlump;
-	UINT16 sprite2;
+	UINT32 sprite2;
+
+	skin->sprites = Z_Realloc(skin->sprites, sizeof(*skin->sprites) * numplayersprites, PU_STATIC, NULL);
+	skin->sprinfo = Z_Realloc(skin->sprinfo, sizeof(*skin->sprinfo) * numplayersprites, PU_STATIC, NULL);
+	memset(&skin->sprinfo[skin->numsprites], 0, sizeof(*skin->sprinfo) * (numplayersprites < skin->numsprites));
+	skin->super.sprites = Z_Realloc(skin->super.sprites, sizeof(*skin->super.sprites) * numplayersprites, PU_STATIC, NULL);
+	skin->super.sprinfo = Z_Realloc(skin->super.sprinfo, sizeof(*skin->super.sprinfo) * numplayersprites, PU_STATIC, NULL);
+	memset(&skin->super.sprinfo[skin->numsprites], 0, sizeof(*skin->super.sprinfo) * (numplayersprites < skin->numsprites));
+	skin->numsprites = numplayersprites;
 
 	*lump += 1; // start after S_SKIN
 	*lastlump = W_CheckNumForNamePwad("S_END",wadnum,*lump); // stop at S_END
@@ -624,19 +632,19 @@ static void R_LoadSkinSprites(UINT16 wadnum, UINT16 *lump, UINT16 *lastlump, ski
 	{
 		newlastlump++;
 		// load all sprite sets we are aware of... for super!
-		for (sprite2 = start_spr2; sprite2 < free_spr2; sprite2++)
-			R_AddSingleSpriteDef(spr2names[sprite2], &skin->super.sprites[sprite2], wadnum, newlastlump, *lastlump, false);
+		for (sprite2 = start_spr2; sprite2 < numplayersprites; sprite2++)
+			R_AddSingleSpriteDef(playersprites[sprite2]->name, &skin->super.sprites[sprite2], wadnum, newlastlump, *lastlump, false);
 
 		newlastlump--;
 		*lastlump = newlastlump; // okay, make the normal sprite set loading end there
 	}
 
 	// load all sprite sets we are aware of... for normal stuff.
-	for (sprite2 = start_spr2; sprite2 < free_spr2; sprite2++)
-		R_AddSingleSpriteDef(spr2names[sprite2], &skin->sprites[sprite2], wadnum, *lump, *lastlump, false);
+	for (sprite2 = start_spr2; sprite2 < numplayersprites; sprite2++)
+		R_AddSingleSpriteDef(playersprites[sprite2]->name, &skin->sprites[sprite2], wadnum, *lump, *lastlump, false);
 
 	if (skin->sprites[0].numframes == 0)
-		CONS_Alert(CONS_ERROR, M_GetText("No frames found for sprite SPR2_%s\n"), spr2names[0]);
+		CONS_Alert(CONS_ERROR, M_GetText("No frames found for sprite SPR2_%s\n"), playersprites[0]->name);
 }
 
 // returns whether found appropriate property
@@ -1173,13 +1181,13 @@ next_token:
 			continue;
 		}
 
-		// Update sprites, in the range of (start_spr2 - free_spr2-1)
+		// Update sprites, in the range of (start_spr2 - numplayersprites-1)
 		R_LoadSkinSprites(wadnum, &lump, &lastlump, skin, start_spr2);
 		//R_FlushTranslationColormapCache(); // I don't think this is needed for what we're doing?
 	}
 }
 
-static playersprite_t old_spr2 = SPR2_FIRSTFREESLOT;
+static playersprite_t old_spr2 = 0;
 void R_RefreshSprite2(void)
 {
 	// Sprite2s being defined by custom wads can create situations where
@@ -1194,17 +1202,17 @@ void R_RefreshSprite2(void)
 
 	INT32 i;
 
-	if (old_spr2 > free_spr2)
+	if (old_spr2 > numplayersprites)
 	{
 #ifdef PARANOIA
-		I_Error("R_RefreshSprite2: old_spr2 is too high?! (old_spr2: %d, free_spr2: %d)\n", old_spr2, free_spr2);
+		I_Error("R_RefreshSprite2: old_spr2 is too high?! (old_spr2: %d, numplayersprites: %d)\n", old_spr2, numplayersprites);
 #else
 		// Just silently fix
-		old_spr2 = free_spr2;
+		old_spr2 = numplayersprites;
 #endif
 	}
 
-	if (old_spr2 == free_spr2)
+	if (old_spr2 == numplayersprites)
 	{
 		// No sprite2s were added since the last time we did freeslots.
 		return;
@@ -1216,5 +1224,5 @@ void R_RefreshSprite2(void)
 	}
 
 	// Update previous value.
-	old_spr2 = free_spr2;
+	old_spr2 = numplayersprites;
 }
diff --git a/src/r_skins.h b/src/r_skins.h
index 1f2c57472d23ffd3026f0370e591dcd18ad77193..7da91af875c62f11705b46b0cfc28d2bf188a76b 100644
--- a/src/r_skins.h
+++ b/src/r_skins.h
@@ -80,13 +80,14 @@ typedef struct
 	// specific sounds per skin
 	sfxenum_t soundsid[NUMSKINSOUNDS]; // sound # in S_sfx table
 
-	spritedef_t sprites[NUMPLAYERSPRITES];
-	spriteinfo_t sprinfo[NUMPLAYERSPRITES];
+	spritedef_t *sprites;
+	spriteinfo_t *sprinfo;
+	UINT32 numsprites;
 
 	// contains super versions too
 	struct {
-		spritedef_t sprites[NUMPLAYERSPRITES];
-		spriteinfo_t sprinfo[NUMPLAYERSPRITES];
+		spritedef_t *sprites;
+		spriteinfo_t *sprinfo;
 	} super;
 } skin_t;
 
@@ -107,13 +108,13 @@ INT32 R_GetForcedSkin(INT32 playernum);
 void R_AddSkins(UINT16 wadnum, boolean mainfile);
 void R_PatchSkins(UINT16 wadnum, boolean mainfile);
 
-UINT16 P_GetStateSprite2(state_t *state);
-UINT16 P_GetSprite2StateFrame(state_t *state);
-UINT16 P_GetSkinSprite2(skin_t *skin, UINT16 spr2, player_t *player);
-UINT16 P_ApplySuperFlagToSprite2(UINT16 spr2, mobj_t *mobj);
-spritedef_t *P_GetSkinSpritedef(skin_t *skin, UINT16 spr2);
-spriteinfo_t *P_GetSkinSpriteInfo(skin_t *skin, UINT16 spr2);
-boolean P_IsValidSprite2(skin_t *skin, UINT16 spr2);
+UINT32 P_GetStateSprite2(state_t *state);
+UINT32 P_GetSprite2StateFrame(state_t *state);
+UINT32 P_GetSkinSprite2(skin_t *skin, UINT32 spr2, player_t *player);
+UINT32 P_ApplySuperFlagToSprite2(UINT32 spr2, mobj_t *mobj);
+spritedef_t *P_GetSkinSpritedef(skin_t *skin, UINT32 spr2);
+spriteinfo_t *P_GetSkinSpriteInfo(skin_t *skin, UINT32 spr2);
+boolean P_IsValidSprite2(skin_t *skin, UINT32 spr2);
 boolean P_IsStateSprite2Super(state_t *state);
 
 void R_RefreshSprite2(void);
diff --git a/src/r_things.c b/src/r_things.c
index 00ae3ba696e104c25700d01428a1a4a5fc4623b6..a733e8bd8bf3a29b23e22782160f682ad674bdee 100644
--- a/src/r_things.c
+++ b/src/r_things.c
@@ -1813,7 +1813,7 @@ static void R_ProjectSprite(mobj_t *thing)
 
 		if (frame >= sprdef->numframes)
 		{
-			CONS_Alert(CONS_ERROR, M_GetText("R_ProjectSprite: invalid skins[\"%s\"].sprites[SPR2_%s] %sframe %s\n"), ((skin_t *)thing->skin)->name, spr2names[thing->sprite2 & SPR2F_MASK], (thing->sprite2 & SPR2F_SUPER) ? "super ": "", sizeu5(frame));
+			CONS_Alert(CONS_ERROR, M_GetText("R_ProjectSprite: invalid skins[\"%s\"].sprites[SPR2_%s] %sframe %s\n"), ((skin_t *)thing->skin)->name, playersprites[thing->sprite2 & SPR2F_MASK]->name, (thing->sprite2 & SPR2F_SUPER) ? "super ": "", sizeu5(frame));
 			thing->sprite = states[S_UNKNOWN]->sprite;
 			thing->frame = states[S_UNKNOWN]->frame;
 			sprdef = &sprites[thing->sprite];