void R_InitSkins()

in doom_py/src/vizdoom/src/r_data/sprites.cpp [506:854]


void R_InitSkins (void)
{
	FSoundID playersoundrefs[NUMSKINSOUNDS];
	spritedef_t temp;
	int sndlumps[NUMSKINSOUNDS];
	char key[65];
	DWORD intname, crouchname;
	size_t i;
	int j, k, base;
	int lastlump;
	int aliasid;
	bool remove;
	const PClass *basetype, *transtype;

	key[sizeof(key)-1] = 0;
	i = PlayerClasses.Size () - 1;
	lastlump = 0;

	for (j = 0; j < NUMSKINSOUNDS; ++j)
	{
		playersoundrefs[j] = skinsoundnames[j][1];
	}

	while ((base = Wads.FindLump ("S_SKIN", &lastlump, true)) != -1)
	{
		// The player sprite has 23 frames. This means that the S_SKIN
		// marker needs a minimum of 23 lumps after it.
		if (base >= Wads.GetNumLumps() - 23 || base == -1)
			continue;

		i++;
		for (j = 0; j < NUMSKINSOUNDS; j++)
			sndlumps[j] = -1;
		skins[i].namespc = Wads.GetLumpNamespace (base);

		FScanner sc(base);
		intname = 0;
		crouchname = 0;

		remove = false;
		basetype = NULL;
		transtype = NULL;

		// Data is stored as "key = data".
		while (sc.GetString ())
		{
			strncpy (key, sc.String, sizeof(key)-1);
			if (!sc.GetString() || sc.String[0] != '=')
			{
				Printf (PRINT_BOLD, "Bad format for skin %d: %s\n", (int)i, key);
				break;
			}
			sc.GetString ();
			if (0 == stricmp (key, "name"))
			{
				strncpy (skins[i].name, sc.String, 16);
				for (j = 0; (size_t)j < i; j++)
				{
					if (stricmp (skins[i].name, skins[j].name) == 0)
					{
						mysnprintf (skins[i].name, countof(skins[i].name), "skin%d", (int)i);
						Printf (PRINT_BOLD, "Skin %s duplicated as %s\n",
							skins[j].name, skins[i].name);
						break;
					}
				}
			}
			else if (0 == stricmp (key, "sprite"))
			{
				for (j = 3; j >= 0; j--)
					sc.String[j] = toupper (sc.String[j]);
				intname = *((DWORD *)sc.String);
			}
			else if (0 == stricmp (key, "crouchsprite"))
			{
				for (j = 3; j >= 0; j--)
					sc.String[j] = toupper (sc.String[j]);
				crouchname = *((DWORD *)sc.String);
			}
			else if (0 == stricmp (key, "face"))
			{
				for (j = 2; j >= 0; j--)
					skins[i].face[j] = toupper (sc.String[j]);
				skins[i].face[3] = '\0';
			}
			else if (0 == stricmp (key, "gender"))
			{
				skins[i].gender = D_GenderToInt (sc.String);
			}
			else if (0 == stricmp (key, "scale"))
			{
				skins[i].ScaleX = clamp<fixed_t> (FLOAT2FIXED(atof (sc.String)), 1, 256*FRACUNIT);
				skins[i].ScaleY = skins[i].ScaleX;
			}
			else if (0 == stricmp (key, "game"))
			{
				if (gameinfo.gametype == GAME_Heretic)
					basetype = PClass::FindClass (NAME_HereticPlayer);
				else if (gameinfo.gametype == GAME_Strife)
					basetype = PClass::FindClass (NAME_StrifePlayer);
				else
					basetype = PClass::FindClass (NAME_DoomPlayer);

				transtype = basetype;

				if (stricmp (sc.String, "heretic") == 0)
				{
					if (gameinfo.gametype & GAME_DoomChex)
					{
						transtype = PClass::FindClass (NAME_HereticPlayer);
						skins[i].othergame = true;
					}
					else if (gameinfo.gametype != GAME_Heretic)
					{
						remove = true;
					}
				}
				else if (stricmp (sc.String, "strife") == 0)
				{
					if (gameinfo.gametype != GAME_Strife)
					{
						remove = true;
					}
				}
				else
				{
					if (gameinfo.gametype == GAME_Heretic)
					{
						transtype = PClass::FindClass (NAME_DoomPlayer);
						skins[i].othergame = true;
					}
					else if (!(gameinfo.gametype & GAME_DoomChex))
					{
						remove = true;
					}
				}

				if (remove)
					break;
			}
			else if (0 == stricmp (key, "class"))
			{ // [GRB] Define the skin for a specific player class
				int pclass = D_PlayerClassToInt (sc.String);

				if (pclass < 0)
				{
					remove = true;
					break;
				}

				basetype = transtype = PlayerClasses[pclass].Type;
			}
			else if (key[0] == '*')
			{ // Player sound replacment (ZDoom extension)
				int lump = Wads.CheckNumForName (sc.String, skins[i].namespc);
				if (lump == -1)
				{
					lump = Wads.CheckNumForFullName (sc.String, true, ns_sounds);
				}
				if (lump != -1)
				{
					if (stricmp (key, "*pain") == 0)
					{ // Replace all pain sounds in one go
						aliasid = S_AddPlayerSound (skins[i].name, skins[i].gender,
							playersoundrefs[0], lump, true);
						for (int l = 3; l > 0; --l)
						{
							S_AddPlayerSoundExisting (skins[i].name, skins[i].gender,
								playersoundrefs[l], aliasid, true);
						}
					}
					else
					{
						int sndref = S_FindSoundNoHash (key);
						if (sndref != 0)
						{
							S_AddPlayerSound (skins[i].name, skins[i].gender, sndref, lump, true);
						}
					}
				}
			}
			else
			{
				for (j = 0; j < NUMSKINSOUNDS; j++)
				{
					if (stricmp (key, skinsoundnames[j][0]) == 0)
					{
						sndlumps[j] = Wads.CheckNumForName (sc.String, skins[i].namespc);
						if (sndlumps[j] == -1)
						{ // Replacement not found, try finding it in the global namespace
							sndlumps[j] = Wads.CheckNumForFullName (sc.String, true, ns_sounds);
						}
					}
				}
				//if (j == 8)
				//	Printf ("Funny info for skin %i: %s = %s\n", i, key, sc.String);
			}
		}

		// [GRB] Assume Doom skin by default
		if (!remove && basetype == NULL)
		{
			if (gameinfo.gametype & GAME_DoomChex)
			{
				basetype = transtype = PClass::FindClass (NAME_DoomPlayer);
			}
			else if (gameinfo.gametype == GAME_Heretic)
			{
				basetype = PClass::FindClass (NAME_HereticPlayer);
				transtype = PClass::FindClass (NAME_DoomPlayer);
				skins[i].othergame = true;
			}
			else
			{
				remove = true;
			}
		}

		if (!remove)
		{
			skins[i].range0start = transtype->Meta.GetMetaInt (APMETA_ColorRange) & 0xff;
			skins[i].range0end = transtype->Meta.GetMetaInt (APMETA_ColorRange) >> 8;

			remove = true;
			for (j = 0; j < (int)PlayerClasses.Size (); j++)
			{
				const PClass *type = PlayerClasses[j].Type;

				if (type->IsDescendantOf (basetype) &&
					GetDefaultByType (type)->SpawnState->sprite == GetDefaultByType (basetype)->SpawnState->sprite &&
					type->Meta.GetMetaInt (APMETA_ColorRange) == basetype->Meta.GetMetaInt (APMETA_ColorRange))
				{
					PlayerClasses[j].Skins.Push ((int)i);
					remove = false;
				}
			}
		}

		if (!remove)
		{
			if (skins[i].name[0] == 0)
				mysnprintf (skins[i].name, countof(skins[i].name), "skin%d", (int)i);

			// Now collect the sprite frames for this skin. If the sprite name was not
			// specified, use whatever immediately follows the specifier lump.
			if (intname == 0)
			{
				char name[9];
				Wads.GetLumpName (name, base+1);
				memcpy(&intname, name, 4);
			}

			int basens = Wads.GetLumpNamespace(base);

			for(int spr = 0; spr<2; spr++)
			{
				memset (sprtemp, 0xFFFF, sizeof(sprtemp));
				for (k = 0; k < MAX_SPRITE_FRAMES; ++k)
				{
					sprtemp[k].Flip = 0;
					sprtemp[k].Voxel = NULL;
				}
				maxframe = -1;

				if (spr == 1)
				{
					if (crouchname !=0 && crouchname != intname)
					{
						intname = crouchname;
					}
					else
					{
						skins[i].crouchsprite = -1;
						break;
					}
				}

				for (k = base + 1; Wads.GetLumpNamespace(k) == basens; k++)
				{
					char lname[9];
					DWORD lnameint;
					Wads.GetLumpName (lname, k);
					memcpy(&lnameint, lname, 4);
					if (lnameint == intname)
					{
						FTextureID picnum = TexMan.CreateTexture(k, FTexture::TEX_SkinSprite);
						bool res = R_InstallSpriteLump (picnum, lname[4] - 'A', lname[5], false);

						if (lname[6] && res)
							R_InstallSpriteLump (picnum, lname[6] - 'A', lname[7], true);
					}
				}

				if (spr == 0 && maxframe <= 0)
				{
					Printf (PRINT_BOLD, "Skin %s (#%d) has no frames. Removing.\n", skins[i].name, (int)i);
					remove = true;
					break;
				}

				Wads.GetLumpName (temp.name, base+1);
				temp.name[4] = 0;
				int sprno = (int)sprites.Push (temp);
				if (spr==0)	skins[i].sprite = sprno;
				else skins[i].crouchsprite = sprno;
				R_InstallSprite (sprno);
			}
		}

		if (remove)
		{
			if (i < numskins-1)
				memmove (&skins[i], &skins[i+1], sizeof(skins[0])*(numskins-i-1));
			i--;
			continue;
		}

		// Register any sounds this skin provides
		aliasid = 0;
		for (j = 0; j < NUMSKINSOUNDS; j++)
		{
			if (sndlumps[j] != -1)
			{
				if (j == 0 || sndlumps[j] != sndlumps[j-1])
				{
					aliasid = S_AddPlayerSound (skins[i].name, skins[i].gender,
						playersoundrefs[j], sndlumps[j], true);
				}
				else
				{
					S_AddPlayerSoundExisting (skins[i].name, skins[i].gender,
						playersoundrefs[j], aliasid, true);
				}
			}
		}

		// Make sure face prefix is a full 3 chars
		if (skins[i].face[1] == 0 || skins[i].face[2] == 0)
		{
			skins[i].face[0] = 0;
		}
	}

	if (numskins > PlayerClasses.Size ())
	{ // The sound table may have changed, so rehash it.
		S_HashSounds ();
		S_ShrinkPlayerSoundLists ();
	}
}