// // R_InitSpriteDefs // Pass a null terminated list of sprite names // (4 chars exactly) to be used. // Builds the sprite rotation matrices to account // for horizontally flipped sprites. // Will report an error if the lumps are inconsistant. // Only called at startup. // // Sprite lump names are 4 characters for the actor, // a letter for the frame, and a number for the rotation. // A sprite that is flippable will have an additional // letter/number appended. // The rotation character can be 0 to signify no rotations. // void R_InitSpriteDefs (const char **namelist) { int i; int l; int intname; int start; int end; int realsprites; // count the number of sprite names for (numsprites = 0; namelist[numsprites]; numsprites++) ; // [RH] include skins in the count realsprites = numsprites; numsprites += numskins - 1; if (!numsprites) return; sprites = (spritedef_t *)Z_Malloc (numsprites * sizeof(*sprites), PU_STATIC, NULL); start = firstspritelump - 1; end = lastspritelump + 1; // scan all the lump names for each of the names, // noting the highest frame letter. // Just compare 4 characters as ints for (i = 0; i < realsprites; i++) { spritename = namelist[i]; memset (sprtemp, -1, sizeof(sprtemp)); maxframe = -1; intname = *(int *)namelist[i]; // scan the lumps, // filling in the frames for whatever is found for (l = lastspritelump; l >= firstspritelump; l--) { if (*(int *)lumpinfo[l].name == intname) { R_InstallSpriteLump (l, lumpinfo[l].name[4] - 'A', // denis - fixme - security lumpinfo[l].name[5] - '0', false); if (lumpinfo[l].name[6]) R_InstallSpriteLump (l, lumpinfo[l].name[6] - 'A', lumpinfo[l].name[7] - '0', true); } } R_InstallSprite (namelist[i], i); } }
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; PClassPlayerPawn *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].Scale.X = clamp(atof (sc.String), 1./65536, 256.); skins[i].Scale.Y = skins[i].Scale.X; } else if (0 == stricmp (key, "game")) { if (gameinfo.gametype == GAME_Heretic) basetype = dyn_cast<PClassPlayerPawn>(PClass::FindActor(NAME_HereticPlayer)); else if (gameinfo.gametype == GAME_Strife) basetype = dyn_cast<PClassPlayerPawn>(PClass::FindActor(NAME_StrifePlayer)); else basetype = dyn_cast<PClassPlayerPawn>(PClass::FindActor(NAME_DoomPlayer)); transtype = basetype; if (stricmp (sc.String, "heretic") == 0) { if (gameinfo.gametype & GAME_DoomChex) { transtype = dyn_cast<PClassPlayerPawn>(PClass::FindActor(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 = dyn_cast<PClassPlayerPawn>(PClass::FindActor(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 = dyn_cast<PClassPlayerPawn>(PClass::FindActor(NAME_DoomPlayer)); } else if (gameinfo.gametype == GAME_Heretic) { basetype = dyn_cast<PClassPlayerPawn>(PClass::FindActor(NAME_HereticPlayer)); transtype = dyn_cast<PClassPlayerPawn>(PClass::FindActor(NAME_DoomPlayer)); skins[i].othergame = true; } else { remove = true; } } if (!remove) { skins[i].range0start = transtype->ColorRangeStart; skins[i].range0end = transtype->ColorRangeEnd; remove = true; for (j = 0; j < (int)PlayerClasses.Size (); j++) { PClassPlayerPawn *type = PlayerClasses[j].Type; if (type->IsDescendantOf (basetype) && GetDefaultByType(type)->SpawnState->sprite == GetDefaultByType(basetype)->SpawnState->sprite && type->ColorRangeStart == basetype->ColorRangeStart && type->ColorRangeEnd == basetype->ColorRangeEnd) { 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++) { spriteframewithrotate sprtemp[MAX_SPRITE_FRAMES]; memset (sprtemp, 0xFFFF, sizeof(sprtemp)); for (k = 0; k < MAX_SPRITE_FRAMES; ++k) { sprtemp[k].Flip = 0; sprtemp[k].Voxel = NULL; } int 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, sprtemp, maxframe); if (lname[6] && res) R_InstallSpriteLump (picnum, lname[6] - 'A', lname[7], true, sprtemp, maxframe); } } 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, sprtemp, maxframe); } } 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 (); } }
void R_InitSpriteDefs () { struct Hasher { int Head, Next; } *hashes; struct VHasher { int Head, Next, Name, Spin; char Frame; } *vhashes; unsigned int i, j, smax, vmax; DWORD intname; spriteframewithrotate sprtemp[MAX_SPRITE_FRAMES]; // Create a hash table to speed up the process smax = TexMan.NumTextures(); hashes = new Hasher[smax]; memset(hashes, -1, sizeof(Hasher)*smax); for (i = 0; i < smax; ++i) { FTexture *tex = TexMan.ByIndex(i); if (tex->UseType == FTexture::TEX_Sprite && strlen(tex->Name) >= 6) { size_t bucket = TEX_DWNAME(tex) % smax; hashes[i].Next = hashes[bucket].Head; hashes[bucket].Head = i; } } // Repeat, for voxels vmax = Wads.GetNumLumps(); vhashes = new VHasher[vmax]; memset(vhashes, -1, sizeof(VHasher)*vmax); for (i = 0; i < vmax; ++i) { if (Wads.GetLumpNamespace(i) == ns_voxels) { char name[9]; size_t namelen; int spin; int sign; Wads.GetLumpName(name, i); name[8] = 0; namelen = strlen(name); if (namelen < 4) { // name is too short continue; } if (name[4] != '\0' && name[4] != ' ' && (name[4] < 'A' || name[4] >= 'A' + MAX_SPRITE_FRAMES)) { // frame char is invalid continue; } spin = 0; sign = 2; // 2 to convert from deg/halfsec to deg/sec j = 5; if (j < namelen && name[j] == '-') { // a minus sign is okay, but only before any digits j++; sign = -2; } for (; j < namelen; ++j) { // the remainder to the end of the name must be digits if (name[j] >= '0' && name[j] <= '9') { spin = spin * 10 + name[j] - '0'; } else { break; } } if (j < namelen) { // the spin part is invalid continue; } memcpy(&vhashes[i].Name, name, 4); vhashes[i].Frame = name[4]; vhashes[i].Spin = spin * sign; size_t bucket = vhashes[i].Name % vmax; vhashes[i].Next = vhashes[bucket].Head; vhashes[bucket].Head = i; } } // scan all the lump names for each of the names, noting the highest frame letter. for (i = 0; i < sprites.Size(); ++i) { memset (sprtemp, 0xFF, sizeof(sprtemp)); for (j = 0; j < MAX_SPRITE_FRAMES; ++j) { sprtemp[j].Flip = 0; sprtemp[j].Voxel = NULL; } int maxframe = -1; intname = sprites[i].dwName; // scan the lumps, filling in the frames for whatever is found int hash = hashes[intname % smax].Head; while (hash != -1) { FTexture *tex = TexMan[hash]; if (TEX_DWNAME(tex) == intname) { bool res = R_InstallSpriteLump (FTextureID(hash), tex->Name[4] - 'A', tex->Name[5], false, sprtemp, maxframe); if (tex->Name[6] && res) R_InstallSpriteLump (FTextureID(hash), tex->Name[6] - 'A', tex->Name[7], true, sprtemp, maxframe); } hash = hashes[hash].Next; } // repeat, for voxels hash = vhashes[intname % vmax].Head; while (hash != -1) { VHasher *vh = &vhashes[hash]; if (vh->Name == (int)intname) { FVoxelDef *voxdef = R_LoadVoxelDef(hash, vh->Spin); if (voxdef != NULL) { if (vh->Frame == ' ' || vh->Frame == '\0') { // voxel applies to every sprite frame for (j = 0; j < MAX_SPRITE_FRAMES; ++j) { if (sprtemp[j].Voxel == NULL) { sprtemp[j].Voxel = voxdef; } } maxframe = MAX_SPRITE_FRAMES-1; } else { // voxel applies to a specific frame j = vh->Frame - 'A'; sprtemp[j].Voxel = voxdef; maxframe = MAX<int>(maxframe, j); } } } hash = vh->Next; } R_InstallSprite ((int)i, sprtemp, maxframe); } delete[] hashes; delete[] vhashes; }
void R_InitSkins (void) { char sndname[128]; int sndlumps[8]; char key[10]; int intname; size_t i; int j, k, base; int stop; char *def; key[9] = 0; for (i = 1; i < numskins; i++) { for (j = 0; j < 8; j++) sndlumps[j] = -1; base = W_CheckNumForName ("S_SKIN", skins[i].namespc); // The player sprite has 23 frames. This means that the S_SKIN // marker needs a minimum of 23 lumps after it (probably more). if (base + 23 >= (int)numlumps || base == -1) continue; def = (char *)W_CacheLumpNum (base, PU_CACHE); intname = 0; // Data is stored as "key = data". while ( (def = COM_Parse (def)) ) { strncpy (key, com_token, 9); def = COM_Parse (def); if (com_token[0] != '=') { Printf (PRINT_HIGH, "Bad format for skin %d: %s %s", i, key, com_token); break; } def = COM_Parse (def); if (!stricmp (key, "name")) { strncpy (skins[i].name, com_token, 16); } else if (!stricmp (key, "sprite")) { for (j = 3; j >= 0; j--) com_token[j] = toupper (com_token[j]); intname = *((int *)com_token); } else if (!stricmp (key, "face")) { for (j = 2; j >= 0; j--) skins[i].face[j] = toupper (com_token[j]); } else { for (j = 0; j < 8; j++) { if (!stricmp (key, skinsoundnames[j][0])) { // Can't use W_CheckNumForName because skin sounds // haven't been assigned a namespace yet. for (k = base + 1; k < (int)numlumps && lumpinfo[k].handle == lumpinfo[base].handle; k++) { if (!strnicmp (com_token, lumpinfo[k].name, 8)) { //W_SetLumpNamespace (k, skins[i].namespc); sndlumps[j] = k; break; } } if (sndlumps[j] == -1) { // Replacement not found, try finding it in the global namespace sndlumps[j] = W_CheckNumForName (com_token); } break; } } //if (j == 8) // Printf (PRINT_HIGH, "Funny info for skin %i: %s = %s\n", i, key, com_token); } } if (skins[i].name[0] == 0) sprintf (skins[i].name, "skin%d", (unsigned)i); // Register any sounds this skin provides for (j = 0; j < 8; j++) { if (sndlumps[j] != -1) { if (j > 1) { sprintf (sndname, "player/%s/%s", skins[i].name, skinsoundnames[j][1]); S_AddSoundLump (sndname, sndlumps[j]); } else if (j == 1) { int r; for (r = 1; r <= 4; r++) { sprintf (sndname, "player/%s/death%d", skins[i].name, r); S_AddSoundLump (sndname, sndlumps[j]); } } else { // j == 0 int l, r; for (l = 1; l <= 4; l++) for (r = 1; r <= 2; r++) { sprintf (sndname, "player/%s/pain%d_%d", skins[i].name, l*25, r); S_AddSoundLump (sndname, sndlumps[j]); } } } } // 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) { intname = *(int *)(lumpinfo[base+1].name); for (stop = base + 2; stop < (int)numlumps && lumpinfo[stop].handle == lumpinfo[base].handle && *(int *)lumpinfo[stop].name == intname; stop++) ; } else { stop = numlumps; } memset (sprtemp, -1, sizeof(sprtemp)); maxframe = -1; for (k = base + 1; k < stop && lumpinfo[k].handle == lumpinfo[base].handle; k++) { if (*(int *)lumpinfo[k].name == intname) { R_InstallSpriteLump (k, lumpinfo[k].name[4] - 'A', // denis - fixme - security lumpinfo[k].name[5] - '0', false); if (lumpinfo[k].name[6]) R_InstallSpriteLump (k, lumpinfo[k].name[6] - 'A', lumpinfo[k].name[7] - '0', true); //W_SetLumpNamespace (k, skins[i].namespc); } } R_InstallSprite ((char *)&intname, (skins[i].sprite = (spritenum_t)(numsprites - numskins + i))); // Now go back and check for face graphics (if necessary) if (skins[i].face[0] == 0 || skins[i].face[1] == 0 || skins[i].face[2] == 0) { // No face name specified, so this skin doesn't replace it skins[i].face[0] = 0; } else { // Need to go through and find all face graphics for the skin // and assign them to the skin's namespace. for (j = 0; j < 8; j++) strncpy (facenames[j], skins[i].face, 3); for (k = base + 1; k < (int)numlumps && lumpinfo[k].handle == lumpinfo[base].handle; k++) { for (j = 0; j < 8; j++) if (!strncmp (facenames[j], lumpinfo[k].name, facelens[j])) { //W_SetLumpNamespace (k, skins[i].namespc); break; } } } } // Grrk. May have changed sound table. Fix it. if (numskins > 1) S_HashSounds (); }