void CStringEdPackage::SetupNewFileParse( const char *psFileName, SE_BOOL bLoadDebug ) { char sString[ iSE_MAX_FILENAME_LENGTH ]; strcpy(sString, Filename_WithoutPath( Filename_WithoutExt( psFileName ) )); Q_strupr(sString); m_strCurrentFileRef_ParseOnly = sString; // eg "OBJECTIVES" m_strLoadingLanguage_ParseOnly = ExtractLanguageFromPath( psFileName ); m_bLoadingEnglish_ParseOnly = (!Q_stricmp( m_strLoadingLanguage_ParseOnly.c_str(), "english" )) ? SE_TRUE : SE_FALSE; m_bLoadDebug = bLoadDebug; }
void CMainFrame::OnViewScreenshotFile() { if (Model_Loaded()) { CWaitCursor wait; // slightly iffy here, I'm going to assume that the rendering context is still valid from last time. // I can't do much else because I need to supply DC shit that I don't have in order to issue an OnDraw // command to do it legally, so f**k it... // gbTextInhibit = AppVars.bCleanScreenShots; //true; { ModelList_Render( g_iScreenWidth, g_iScreenHeight ); // render to back buffer // generate a filename... // char sBaseName[MAX_PATH]; sprintf(sBaseName, Filename_WithoutPath(Filename_PathOnly(Model_GetFullPrimaryFilename()))); // // look for a numbered slot to snapshot to... // #define NUM_SAVE_SLOTS 1000 for (int iName=0; iName<NUM_SAVE_SLOTS; iName++) { char sFilename[MAX_PATH]; if (iName==NUM_SAVE_SLOTS) { ErrorBox(va("Couldn't find a free save slot! (tried %d slots)",NUM_SAVE_SLOTS)); } sprintf(sFilename, "c:\\%s_%03d.bmp",sBaseName,iName); if (!FileExists(sFilename)) { ScreenShot(sFilename,va("(C) Raven Software %s",GetYearAsString())); BMP_Free(); break; } } } gbTextInhibit = false; } else { ErrorBox("No model loaded to work out path from!\n\n( So duhhhh... why try to take a snapshot? )"); } m_splitter.Invalidate(false); }
bool Anims_ReadFile_FRAMES(ModelContainer_t *pContainer, LPCSTR psLocalFilename_GLA) { LPCSTR psFilename = va("%s%s.frames",gamedir,Filename_WithoutExt(psLocalFilename_GLA)); FILE *fHandle = fopen(psFilename,"rt"); if (fHandle) { // file format is like this per XSI... // // models/test/m4/m44keith.xsi // { // startframe "0" // duration "2" // } // // so... Sequence_t Sequence; bool bStartFrameRead = false; bool bDurationRead = false; bool bFPSRead = false; char sLine[1024]; while (fgets(sLine,sizeof(sLine)-1,fHandle)!=NULL) { if (bStartFrameRead && bDurationRead && bFPSRead) { pContainer->SequenceList.push_back(Sequence); bStartFrameRead = false; bDurationRead = false; bFPSRead = false; } sLine[sizeof(sLine)-1]='\0'; strlwr(sLine); // :-) CString str(sLine); str.TrimLeft(); str.TrimRight(); str.Replace("\"",""); strcpy(sLine,str); if (strstr(sLine,".xsi")) { Sequence_Clear(&Sequence); strcpy(Sequence.sName,Filename_WithoutPath(Filename_WithoutExt(sLine))); // these can be really long... strncpy(Sequence.sNameWithPath,Filename_WithoutExt(sLine),sizeof(Sequence.sNameWithPath)); Sequence.sNameWithPath[sizeof(Sequence.sNameWithPath)-1]='\0'; } else if (strnicmp(sLine,"startframe",strlen("startframe"))==0) { CString str(&sLine[strlen("startframe")]); str.Replace("\"",""); Sequence.iStartFrame = atoi(str); bStartFrameRead = true; } else if (strnicmp(sLine,"duration",strlen("duration"))==0) { CString str(&sLine[strlen("duration")]); str.Replace("\"",""); Sequence.iFrameCount = atoi(str); bDurationRead = true; } else if (strnicmp(sLine,"fps",strlen("fps"))==0) { CString str(&sLine[strlen("fps")]); str.Replace("\"",""); Sequence.iFPS = atoi(str); bFPSRead = true; } } fclose(fHandle); } /* else { ErrorBox( va("Couldn't open file: %s\n", psFilename)); return false; } */ return !!(pContainer->SequenceList.size()); }
void *Z_Malloc(int iSize, memtag_t eTag, qboolean bZeroit) #endif { gbMemFreeupOccured = qfalse; if (iSize == 0) { zoneHeader_t *pMemory = (zoneHeader_t *) &gZeroMalloc; return &pMemory[1]; } // Add in tracking info and round to a longword... (ignore longword aligning now we're not using contiguous blocks) // // int iRealSize = (iSize + sizeof(zoneHeader_t) + sizeof(zoneTail_t) + 3) & 0xfffffffc; int iRealSize = (iSize + sizeof(zoneHeader_t) + sizeof(zoneTail_t)); // Allocate a chunk... // zoneHeader_t *pMemory = NULL; while (pMemory == NULL) { #ifdef _WIN32 if (gbMemFreeupOccured) { Sleep(100); // sleep for 1/10 of a second, so Windows has a chance to shuffle mem to de-swiss-cheese it } #endif pMemory = (zoneHeader_t *) malloc ( iRealSize ); if (!pMemory) { // new bit, if we fail to malloc memory, try dumping some of the cached stuff that's non-vital and try again... // // ditch the BSP cache... // if (CM_DeleteCachedMap(qfalse)) { gbMemFreeupOccured = qtrue; continue; // we've just ditched a whole load of memory, so try again with the malloc } // ditch any sounds not used on this level... // extern qboolean SND_RegisterAudio_LevelLoadEnd(qboolean bDeleteEverythingNotUsedThisLevel); if (SND_RegisterAudio_LevelLoadEnd(qtrue)) { gbMemFreeupOccured = qtrue; continue; // we've dropped at least one sound, so try again with the malloc } // ditch any image_t's (and associated GL texture mem) not used on this level... // extern qboolean RE_RegisterImages_LevelLoadEnd(void); if (RE_RegisterImages_LevelLoadEnd()) { gbMemFreeupOccured = qtrue; continue; // we've dropped at least one image, so try again with the malloc } // ditch the model-binaries cache... (must be getting desperate here!) // extern qboolean RE_RegisterModels_LevelLoadEnd(qboolean bDeleteEverythingNotUsedThisLevel); if (RE_RegisterModels_LevelLoadEnd(qtrue)) { gbMemFreeupOccured = qtrue; continue; } // as a last panic measure, dump all the audio memory, but not if we're in the audio loader // (which is annoying, but I'm not sure how to ensure we're not dumping any memory needed by the sound // currently being loaded if that was the case)... // // note that this keeps querying until it's freed up as many bytes as the requested size, but freeing // several small blocks might not mean that one larger one is satisfiable after freeup, however that'll // just make it go round again and try for freeing up another bunch of blocks until the total is satisfied // again (though this will have freed twice the requested amount in that case), so it'll either work // eventually or not free up enough and drop through to the final ERR_DROP. No worries... // extern qboolean gbInsideLoadSound; extern int SND_FreeOldestSound(void); // I had to add a void-arg version of this because of link issues, sigh if (!gbInsideLoadSound) { int iBytesFreed = SND_FreeOldestSound(); if (iBytesFreed) { int iTheseBytesFreed = 0; while ( (iTheseBytesFreed = SND_FreeOldestSound()) != 0) { iBytesFreed += iTheseBytesFreed; if (iBytesFreed >= iRealSize) break; // early opt-out since we've managed to recover enough (mem-contiguity issues aside) } gbMemFreeupOccured = qtrue; continue; } } // sigh, dunno what else to try, I guess we'll have to give up and report this as an out-of-mem error... // // findlabel: "recovermem" Com_Printf(S_COLOR_RED"Z_Malloc(): Failed to alloc %d bytes (TAG_%s) !!!!!\n", iSize, psTagStrings[eTag]); Z_Details_f(); Com_Error(ERR_FATAL,"(Repeat): Z_Malloc(): Failed to alloc %d bytes (TAG_%s) !!!!!\n", iSize, psTagStrings[eTag]); return NULL; } } #ifdef DEBUG_ZONE_ALLOCS extern char *Filename_WithoutPath(const char *psFilename); Q_strncpyz(pMemory->sSrcFileBaseName, Filename_WithoutPath(psFile), sizeof(pMemory->sSrcFileBaseName)); pMemory->iSrcFileLineNum = iLine; pMemory->sOptionalLabel[0] = '\0'; pMemory->iSnapshotNumber = giZoneSnaphotNum; #endif // Link in pMemory->iMagic = ZONE_MAGIC; pMemory->eTag = eTag; pMemory->iSize = iSize; pMemory->pNext = TheZone.Header.pNext; TheZone.Header.pNext = pMemory; if (pMemory->pNext) { pMemory->pNext->pPrev = pMemory; } pMemory->pPrev = &TheZone.Header; // // add tail... // ZoneTailFromHeader(pMemory)->iMagic = ZONE_MAGIC; // Update stats... // TheZone.Stats.iCurrent += iSize; TheZone.Stats.iCount++; TheZone.Stats.iSizesPerTag [eTag] += iSize; TheZone.Stats.iCountsPerTag [eTag]++; if (TheZone.Stats.iCurrent > TheZone.Stats.iPeak) { TheZone.Stats.iPeak = TheZone.Stats.iCurrent; } #ifdef DETAILED_ZONE_DEBUG_CODE mapAllocatedZones[pMemory]++; #endif Z_Validate(); // check for corruption void *pvReturnMem = &pMemory[1]; if (bZeroit) { memset(pvReturnMem, 0, iSize); } return pvReturnMem; }
const char *CStringEdPackage::ExtractLanguageFromPath( const char *psFileName ) { return Filename_WithoutPath( Filename_PathOnly( psFileName ) ); }
void R_CheckMP3s( const char *psDir ) { // Com_Printf(va("Scanning Dir: %s\n",psDir)); Com_Printf("."); // stops useful info scrolling off screen char **sysFiles, **dirFiles; int numSysFiles, i, numdirs; dirFiles = FS_ListFiles( psDir, "/", &numdirs); if (numdirs > 2) { for (i=2;i<numdirs;i++) { char sDirName[MAX_QPATH]; sprintf(sDirName, "%s\\%s", psDir, dirFiles[i]); R_CheckMP3s(sDirName); } } sysFiles = FS_ListFiles( psDir, ".mp3", &numSysFiles ); for(i=0; i<numSysFiles; i++) { char sFilename[MAX_QPATH]; sprintf(sFilename,"%s\\%s", psDir, sysFiles[i]); Com_Printf("%sFound file: %s",!i?"\n":"",sFilename); iFilesFound++; // read it in... // byte *pbData = NULL; int iSize = FS_ReadFile( sFilename, (void **)&pbData); if (pbData) { id3v1_1* pTAG; // do NOT check 'qbForceRescan' here as an opt, because we need to actually fill in 'pTAG' if there is one... // qboolean qbTagNeedsUpdating = (/* qbForceRescan || */ !MP3_ReadSpecialTagInfo(pbData, iSize, &pTAG))?qtrue:qfalse; if (pTAG == NULL || qbTagNeedsUpdating || qbForceRescan) { Com_Printf(" ( Updating )\n"); // I need to scan this file to get the volume... // // For EF1 I used a temp sfx_t struct, but I can't do that now with this new alloc scheme, // I have to ask for it legally, so I'll keep re-using one, and restoring it's name after use. // (slightly dodgy, but works ok if no-one else changes stuff) // //sfx_t SFX = {0}; extern sfx_t *S_FindName( const char *name ); // static sfx_t *pSFX = NULL; const char sReservedSFXEntrynameForMP3[] = "reserved_for_mp3"; // ( strlen() < MAX_QPATH ) if (pSFX == NULL) // once only { pSFX = S_FindName(sReservedSFXEntrynameForMP3); // always returns, else ERR_FATAL } if (MP3_IsValid(sFilename,pbData, iSize, qbForceStereo)) { wavinfo_t info; int iRawPCMDataSize = MP3_GetUnpackedSize(sFilename, pbData, iSize, qtrue, qbForceStereo); if (iRawPCMDataSize) // should always be true, unless file is f****d, in which case, stop this conversion process { float fMaxVol = 128; // any old default int iActualUnpackedSize = iRawPCMDataSize; // default, override later if not doing music if (!qbForceStereo) // no point for stereo files, which are for music and therefore no lip-sync { byte *pbUnpackBuffer = (byte *) Z_Malloc ( iRawPCMDataSize+10, TAG_TEMP_WORKSPACE ); // won't return if fails iActualUnpackedSize = MP3_UnpackRawPCM( sFilename, pbData, iSize, pbUnpackBuffer ); if (iActualUnpackedSize != iRawPCMDataSize) { Com_Error(ERR_DROP, "******* Whoah! MP3 %s unpacked to %d bytes, but size calc said %d!\n",sFilename,iActualUnpackedSize,iRawPCMDataSize); } // fake up a WAV structure so I can use the other post-load sound code such as volume calc for lip-synching // MP3_FakeUpWAVInfo( sFilename, pbData, iSize, iActualUnpackedSize, // these params are all references... info.format, info.rate, info.width, info.channels, info.samples, info.dataofs ); extern void S_LoadSound_Finalize(wavinfo_t *info, sfx_t *sfx, byte *data); S_LoadSound_Finalize(&info, pSFX, pbUnpackBuffer); // all this just for lipsynch. Oh well. fMaxVol = pSFX->fVolRange; // free sfx->data... // { // Hunk_FreeTempMemory( SFX.data ); // this will have been allocated inside S_LoadSound_Finalise() // // I want a big thankyou from the Mac guys for providing this define... :-) -ste // // #ifndef INT_MIN // #define INT_MIN (-2147483647 - 1) /* minimum (signed) int value */ // #endif // pSFX->iLastTimeUsed = INT_MIN; // force this to be oldest sound file, therefore disposable... pSFX->bInMemory = qtrue; SND_FreeOldestSound(); // ... and do the disposal // now set our temp SFX struct back to default name so nothing else accidentally uses it... // strcpy(pSFX->sSoundName, sReservedSFXEntrynameForMP3); pSFX->bDefaultSound = qfalse; } // other stuff... // Z_Free(pbUnpackBuffer); } // well, time to update the file now... // fileHandle_t f = FS_FOpenFileWrite( sFilename ); if (f) { // write the file back out, but omitting the tag if there was one... // int iWritten = FS_Write(pbData, iSize-(pTAG?sizeof(*pTAG):0), f); if (iWritten) { // make up a new tag if we didn't find one in the original file... // id3v1_1 TAG; if (!pTAG) { pTAG = &TAG; memset(&TAG,0,sizeof(TAG)); strncpy(pTAG->id,"TAG",3); } strncpy(pTAG->title, Filename_WithoutPath(Filename_WithoutExt(sFilename)), sizeof(pTAG->title)); strncpy(pTAG->artist, "Raven Software", sizeof(pTAG->artist) ); strncpy(pTAG->year, "2001", sizeof(pTAG->year) ); strncpy(pTAG->comment, va("%s %g",sKEY_MAXVOL,fMaxVol), sizeof(pTAG->comment) ); strncpy(pTAG->album, va("%s %d",sKEY_UNCOMP,iActualUnpackedSize),sizeof(pTAG->album) ); if (FS_Write( pTAG, sizeof(*pTAG), f )) // NZ = success { iFilesUpdated++; } else { Com_Printf("*********** Failed write to file!\n"); iErrors++; } } else { Com_Printf("*********** Failed write to file!\n"); iErrors++; } FS_FCloseFile( f ); } else { Com_Printf("*********** Failed to re-open for write!\n"); iErrors++; } } else { Com_Error(ERR_DROP, "******* This MP3 should be deleted: %s\n",sFilename); } } else { Com_Printf("*********** File was not a valid MP3!\n"); iErrors++; } } else { Com_Printf(" ( OK )\n"); } FS_FreeFile( pbData ); } } FS_FreeFileList( sysFiles ); FS_FreeFileList( dirFiles ); }
// returns true if at least one set of skin data was read, else false... // static bool Skins_Read(LPCSTR psModelFilename) { LPCSTR psError = NULL; CWaitCursor; LPCSTR psSkinsPath = Skins_ModelNameToSkinPath(psModelFilename); // eg "models/characters/skins" if (psSkinsPath) { string strThisModelBaseName(String_ToLower(Filename_WithoutExt(Filename_WithoutPath(psModelFilename)))); char **ppsSkinFiles; int iSkinFiles; // scan for skin files... // ppsSkinFiles = //ri.FS_ListFiles( "shaders", ".shader", &iSkinFiles ); Sys_ListFiles( va("%s%s",gamedir,psSkinsPath),// const char *directory, ".g2skin", // const char *extension, NULL, // char *filter, &iSkinFiles,// int *numfiles, qfalse // qboolean wantsubs ); if ( !ppsSkinFiles || !iSkinFiles ) { CurrentSkins.clear(); CurrentSkinsSurfacePrefs.clear(); return false; } if ( iSkinFiles > MAX_SKIN_FILES ) { WarningBox(va("%d skin files found, capping to %d\n\n(tell me if this ever happens -Ste)", iSkinFiles, MAX_SKIN_FILES )); iSkinFiles = MAX_SKIN_FILES; } // load and parse skin files... // // for now, I just scan each file and if it's out of date then I invalidate it's model-prefs info... // extern bool GetFileTime(LPCSTR psFileName, FILETIME &ft); for (int i=0; i<iSkinFiles; i++) { bool bReParseThisFile = false; char sFileName[MAX_QPATH]; LPCSTR psFileName = ppsSkinFiles[i]; Com_sprintf( sFileName, sizeof( sFileName ), "%s/%s", psSkinsPath, psFileName ); psFileName = &sFileName[0]; // have a go at getting this time/date stamp if not already present... // if (!SkinFileTimeDates[psFileName].bValid) { FILETIME ft; if (GetFileTime(psFileName, ft)) { SkinFileTimeDates[psFileName].ft = ft; SkinFileTimeDates[psFileName].bValid = true; } } // now see if there's a valid time-stamp, and use it if so, else give up and re-scan all files... // if (SkinFileTimeDates[psFileName].bValid) { FILETIME ft; if (GetFileTime(psFileName, ft)) { LONG l = CompareFileTime( &SkinFileTimeDates[psFileName].ft, &ft); bReParseThisFile = (l<0); } else { bReParseThisFile = true; } } else { bReParseThisFile = true; } if (bReParseThisFile) { G2SkinModelPrefs[sFileName].clear(); } } if (1)//bReParseSkinFiles || !CurrentSkins.size()) { CurrentSkins.clear(); CurrentSkinsSurfacePrefs.clear(); char *buffers[MAX_SKIN_FILES]={0}; // long iTotalBytesLoaded = 0; for ( int i=0; i<iSkinFiles && !psError; i++ ) { char sFileName[MAX_QPATH]; string strThisSkinFile(ppsSkinFiles[i]); Com_sprintf( sFileName, sizeof( sFileName ), "%s/%s", psSkinsPath, strThisSkinFile.c_str() ); StatusMessage( va("Scanning skin %d/%d: \"%s\"...",i+1,iSkinFiles,sFileName)); //ri.Printf( PRINT_ALL, "...loading '%s'\n", sFileName ); bool _bDiskLoadOccured = false; // debug use only, but wtf? #define LOAD_SKIN_FILE \ /*iTotalBytesLoaded += */ ri.FS_ReadFile( sFileName, (void **)&buffers[i] ); \ if ( !buffers[i] ) \ { \ CurrentSkins.clear(); \ CurrentSkinsSurfacePrefs.clear(); \ \ ri.Error( ERR_DROP, "Couldn't load %s", sFileName );\ } \ _bDiskLoadOccured = true; // see if we should pay attention to the contents of this file... // CGPGroup *pFileGroup = NULL; CGPGroup *pParseGroup_Prefs = NULL; CGenericParser2 SkinParser; // bool bParseThisFile = false; // // if we have any information about this skin file as regards what models it refers to, use the info... // if (G2SkinModelPrefs[sFileName].size()) { map<string, int>::iterator it = G2SkinModelPrefs[sFileName].find( strThisModelBaseName ); if (it != G2SkinModelPrefs[sFileName].end()) { // this skin file contains this entry, so just check that we can setup the parse groups ok... // LOAD_SKIN_FILE; char *psDataPtr = buffers[i]; if (SkinParser.Parse(&psDataPtr, true)) { pFileGroup = SkinParser.GetBaseParseGroup(); if (pFileGroup) { pParseGroup_Prefs = pFileGroup->FindSubGroup(sSKINKEYWORD_PREFS);//, true); if (pParseGroup_Prefs) { bParseThisFile = true; } } } else { ErrorBox(va("{} - Brace mismatch error in file \"%s\"!",sFileName)); } } } else { // no size info for this file, so check it manually... // LOAD_SKIN_FILE; if (Skins_ParseThisFile(SkinParser, buffers[i], strThisModelBaseName, pFileGroup, pParseGroup_Prefs, sFileName, G2SkinModelPrefs) ) { bParseThisFile = true; } } if (bParseThisFile) { psError = Skins_Parse( strThisSkinFile, pFileGroup, pParseGroup_Prefs); if (psError) { ErrorBox(va("Skins_Read(): Error reading file \"%s\"!\n\n( Skins will be ignored for this model )\n\nError was:\n\n",sFileName,psError)); } } else { //OutputDebugString(va("Skipping parse of file \"%s\" %s\n",sFileName, _bDiskLoadOccured?"":"( and no load! )")); } } // // free loaded skin files... // for ( i=0; i<iSkinFiles; i++ ) { if (buffers[i]) { ri.FS_FreeFile( buffers[i] ); } } } StatusMessage(NULL); Sys_FreeFileList( ppsSkinFiles ); } else { CurrentSkins.clear(); CurrentSkinsSurfacePrefs.clear(); } if (psError) { return false; } return !!(CurrentSkins.size()); }
// if psLOD0Filename != NULL, then we're loading an MD3 LOD model, and psLOD0Filename is a pointer to original name // bool loadmdl_original( char *filename, LPCSTR psLOD0Filename, gl_model* pLOD1, gl_model* pLOD2 ) { gl_model* model = new gl_model; memset( model, 0, sizeof(gl_model) ); if (pLOD1) { model->pModel_LOD1 = pLOD1; pLOD1->pModel_LOD0 = model; } if (pLOD2) { model->pModel_LOD2 = pLOD2; pLOD2->pModel_LOD0 = model; } // if there's a default skin for this model, don't try and load the internal shaders, this is just so // we don't get bugged by loads of file-missing errors if the model is only designed to use skin files... // bool bDefaultSkinExists = file_exists(SkinName_FromPathedModelName(filename)); if (bDefaultSkinExists) { gbIgnoreTextureLoad = true; } if (!loadmdx( *model, filename )) { gbIgnoreTextureLoad = false; delete_gl_model( model );model = NULL; return false; } gbIgnoreTextureLoad = false; pLastLoadedModel = model; strcpy( model->sHeadSkinName,"default"); strcpy( model->sMDXFullPathname, filename); strcpy( model->sMD3BaseName,Filename_WithoutPath( // Filename_WithoutExt( filename // ) ) ); if (psLOD0Filename) return true; // don't bother with the rest of this stuff now... giTagMenuSubtractValue_Torso = giTagMenuSubtractValue_Head = giTagMenuSubtractValue_Weapon = giTagMenuSubtractValue_Barrel = giTagMenuSubtractValue_Barrel2= giTagMenuSubtractValue_Barrel3= giTagMenuSubtractValue_Barrel4= -1; Model_ApplySkin(model, SkinName_FromPathedModelName(model->sMDXFullPathname)); model->modelListPosition = mdview.modelList->insertLast( model ); mdview.baseModel = (gl_model *)mdview.modelList->first()->element(); tagMenu_seperatorAppend( filename ); for (unsigned int i=0 ; i<model->iNumTags ; i++) { tagMenu_append( model->tags[0][i].Name, (GLMODEL_DBLPTR)&model->linkedModels[i] ); if (!stricmp(model->tags[0][i].Name,"tag_torso")) { giTagMenuSubtractValue_Torso = i; } else if (!stricmp(model->tags[0][i].Name,"tag_head")) { giTagMenuSubtractValue_Head = i; } else if (!stricmp(model->tags[0][i].Name,"tag_weapon")) { giTagMenuSubtractValue_Weapon = i; } else if (!stricmp(model->tags[0][i].Name,"tag_barrel")) { giTagMenuSubtractValue_Barrel = i; } else if (!stricmp(model->tags[0][i].Name,"tag_barrel2")) { giTagMenuSubtractValue_Barrel2 = i; } else if (!stricmp(model->tags[0][i].Name,"tag_barrel3")) { giTagMenuSubtractValue_Barrel3 = i; } else if (!stricmp(model->tags[0][i].Name,"tag_barrel4")) { giTagMenuSubtractValue_Barrel4 = i; } } // arrrghhh!!!!... // giTagMenuSubtractValue_Torso = model->iNumTags - giTagMenuSubtractValue_Torso; giTagMenuSubtractValue_Head = model->iNumTags - giTagMenuSubtractValue_Head; giTagMenuSubtractValue_Weapon = (giTagMenuSubtractValue_Weapon ==-1)?-1:model->iNumTags - giTagMenuSubtractValue_Weapon; giTagMenuSubtractValue_Barrel = (giTagMenuSubtractValue_Barrel ==-1)?-1:model->iNumTags - giTagMenuSubtractValue_Barrel; giTagMenuSubtractValue_Barrel2 = (giTagMenuSubtractValue_Barrel2==-1)?-1:model->iNumTags - giTagMenuSubtractValue_Barrel2; giTagMenuSubtractValue_Barrel3 = (giTagMenuSubtractValue_Barrel3==-1)?-1:model->iNumTags - giTagMenuSubtractValue_Barrel3; giTagMenuSubtractValue_Barrel4 = (giTagMenuSubtractValue_Barrel4==-1)?-1:model->iNumTags - giTagMenuSubtractValue_Barrel4; // // this value is now the value (if NZ) to sub from the menu count (then add ID_TAG_START) to reach "tag_torso"ID of the menu item // SetFaceSkin(0); // safety to always do this return true; }