/************************************************************************************************ * CRMInstanceFile::Open * Opens the given instance file and prepares it for use in instance creation * * inputs: * instance: Name of instance to open. Note that the root path will be automatically * added and shouldnt be included in the given name * * return: * true: instance file successfully loaded * false: instance file could not be loaded for some reason * ************************************************************************************************/ bool CRMInstanceFile::Open ( const char* instance ) { char instanceDef[MAX_QPATH]; CGPGroup *basegroup; // Build the filename Com_sprintf(instanceDef, MAX_QPATH, "ext_data/rmg/%s.instance", instance ); #ifndef FINAL_BUILD // Debug message Com_Printf("CM_Terrain: Loading and parsing instanceDef %s.....\n", instance); #endif // Parse the text file using the generic parser if(!Com_ParseTextFile(instanceDef, mParser )) { Com_sprintf(instanceDef, MAX_QPATH, "ext_data/arioche/%s.instance", instance ); if(!Com_ParseTextFile(instanceDef, mParser )) { Com_Printf(va("CM_Terrain: Could not open instance file '%s'\n", instanceDef)); return false; } } // The whole file.... basegroup = mParser.GetBaseParseGroup(); // The root { } struct mInstances = basegroup->GetSubGroups(); // The "instances" { } structure mInstances = mInstances->GetSubGroups ( ); return true; }
bool CGPGroup::Parse(char **dataPtr, CTextPool **textPool) { char *token; char lastToken[MAX_TOKEN_SIZE]; CGPGroup *newSubGroup; CGPValue *newPair; while(1) { token = GetToken(dataPtr, true); if (!token[0]) { // end of data - error! if (mParent) { return false; } else { break; } } else if (strcmpi(token, "}") == 0) { // ending brace for this group break; } strcpy(lastToken, token); // read ahead to see what we are doing token = GetToken(dataPtr, true, true); if (strcmpi(token, "{") == 0) { // new sub group newSubGroup = AddGroup(lastToken, textPool); newSubGroup->SetWriteable(mWriteable); if (!newSubGroup->Parse(dataPtr, textPool)) { return false; } } else if (strcmpi(token, "[") == 0) { // new pair list newPair = AddPair(lastToken, 0, textPool); if (!newPair->Parse(dataPtr, textPool)) { return false; } } else { // new pair AddPair(lastToken, token, textPool); } } return true; }
/************************************************************************************************ * CRMRandomInstance::CRMRandomInstance * constructs a random instance by choosing one of the sub instances and creating it * * inputs: * instGroup: parser group containing infromation about this instance * instFile: reference to an open instance file for creating sub instances * * return: * none * ************************************************************************************************/ CRMRandomInstance::CRMRandomInstance ( CGPGroup *instGroup, CRMInstanceFile& instFile ) : CRMInstance ( instGroup, instFile ) { CGPGroup* group; CGPGroup* groups[MAX_RANDOM_INSTANCES]; int numGroups; // Build a list of the groups one can be chosen for ( numGroups = 0, group = instGroup->GetSubGroups ( ); group; group = group->GetNext ( ) ) { // If this isnt an instance group then skip it if ( stricmp ( group->GetName ( ), "instance" ) ) { continue; } int multiplier = atoi(group->FindPairValue ( "multiplier", "1" )); for ( ; multiplier > 0 && numGroups < MAX_RANDOM_INSTANCES; multiplier -- ) { groups[numGroups++] = group; } } // No groups, no instance if ( !numGroups ) { // Initialize this now mInstance = NULL; Com_Printf ( "WARNING: No sub instances specified for random instance '%s'\n", group->FindPairValue ( "name", "unknown" ) ); return; } // Now choose a group to parse instGroup = groups[TheRandomMissionManager->GetLandScape()->irand(0,numGroups-1)]; // Create the child instance now. If the instance create fails then the // IsValid routine will return false and this instance wont be added mInstance = instFile.CreateInstance ( instGroup->FindPairValue ( "name", "" ) ); mInstance->SetFilter(mFilter); mInstance->SetTeamFilter(mTeamFilter); mAutomapSymbol = mInstance->GetAutomapSymbol(); SetMessage(mInstance->GetMessage()); SetDescription(mInstance->GetDescription()); SetInfo(mInstance->GetInfo()); }
CGPGroup *CGPGroup::FindSubGroup(const char *name) { CGPGroup *group; group = mSubGroups; while(group) { if(!Q_stricmp(name, group->GetName())) { return(group); } group = (CGPGroup *)group->GetNext(); } return(NULL); }
int CGPGroup::GetNumSubGroups(void) { int count; CGPGroup *group; count = 0; group = mSubGroups; while(group) { count++; group = (CGPGroup *)group->GetNext(); } return(count); }
void CGPGroup::Parse(char **dataPtr, CTextPool **textPool) { char *token; char lastToken[MAX_TOKEN_SIZE]; CGPGroup *newSubGroup; CGPValue *newPair; char *name, *value; while(1) { token = GetToken(dataPtr, true); if (!token[0]) { // end of data - error! break; } else if (Q_strcmpi(token, "}") == 0) { // ending brace for this group break; } strcpy(lastToken, token); // read ahead to see what we are doing token = GetToken(dataPtr, true, true); if (Q_strcmpi(token, "{") == 0) { // new sub group name = (*textPool)->AllocText(lastToken, true, textPool); newSubGroup = AddGroup(name); newSubGroup->SetWriteable(mWriteable); newSubGroup->Parse(dataPtr, textPool); } else if (Q_strcmpi(token, "[") == 0) { // new pair list name = (*textPool)->AllocText(lastToken, true, textPool); newPair = AddPair(name, 0); newPair->Parse(dataPtr, textPool); } else { // new pair name = (*textPool)->AllocText(lastToken, true, textPool); value = (*textPool)->AllocText(token, true, textPool); AddPair(name, value); } } }
bool CGPGroup::Write(CTextPool **textPool, int depth) { int i; CGPValue *mPair = mPairs; CGPGroup *mSubGroup = mSubGroups; if (depth >= 0) { for(i=0;i<depth;i++) { (*textPool)->AllocText("\t", false, textPool); } WriteText(textPool, mName); (*textPool)->AllocText("\r\n", false, textPool); for(i=0;i<depth;i++) { (*textPool)->AllocText("\t", false, textPool); } (*textPool)->AllocText("{\r\n", false, textPool); } while(mPair) { mPair->Write(textPool, depth+1); mPair = (CGPValue *)mPair->GetNext(); } while(mSubGroup) { mSubGroup->Write(textPool, depth+1); mSubGroup = (CGPGroup *)mSubGroup->GetNext(); } if (depth >= 0) { for(i=0;i<depth;i++) { (*textPool)->AllocText("\t", false, textPool); } (*textPool)->AllocText("}\r\n", false, textPool); } return true; }
bool CPrimitiveTemplate::ParseGroup( const CGPGroup& grp, const StringViewIMap< ParseMethod >& parseMethods, gsl::czstring name ) { for( auto& cur : grp.GetProperties() ) { auto pos = parseMethods.find( cur.GetName() ); if( pos == parseMethods.end() ) { theFxHelper.Print( "Unknown key parsing %s group!", name ); } else { ParseMethod method = pos->second; ( this->*method )( cur.GetTopValue() ); } } return true; }
/************************************************************************************************ * CRMInstanceFile::CreateInstance * Creates an instance (to be freed by caller) using the given instance name. * * inputs: * name: Name of the instance to read from the instance file * * return: * NULL: instance could not be read from the instance file * NON-NULL: instance created and returned for further use * ************************************************************************************************/ CRMInstance* CRMInstanceFile::CreateInstance ( const char* name ) { static int instanceID = 0; CGPGroup* group; CRMInstance* instance; // Make sure we were loaded assert ( mInstances ); // Search through the instances for the one with the given name for ( group = mInstances; group; group = group->GetNext ( ) ) { // Skip it if the name doesnt match if ( stricmp ( name, group->FindPairValue ( "name", "" ) ) ) { continue; } // Handle the various forms of instance types if ( !stricmp ( group->GetName ( ), "bsp" ) ) { instance = new CRMBSPInstance ( group, *this ); } else if ( !stricmp ( group->GetName ( ), "npc" ) ) { // instance = new CRMNPCInstance ( group, *this ); continue; } else if ( !stricmp ( group->GetName ( ), "group" ) ) { instance = new CRMGroupInstance ( group, *this ); } else if ( !stricmp ( group->GetName ( ), "random" ) ) { instance = new CRMRandomInstance ( group, *this ); } else if ( !stricmp ( group->GetName ( ), "void" ) ) { instance = new CRMVoidInstance ( group, *this ); } else { continue; } // If the instance isnt valid after being created then delete it if ( !instance->IsValid ( ) ) { delete instance; return NULL; } // The instance was successfully created so return it return instance; } #ifndef FINAL_BUILD // The instance wasnt found in the file so report it Com_Printf(va("WARNING: Instance '%s' was not found in the active instance file\n", name )); #endif return NULL; }
// Parse a primitive, apply defaults first, grab any base level // key pairs, then process any sub groups we may contain. //------------------------------------------------------ bool CPrimitiveTemplate::ParsePrimitive( CGPGroup *grp ) { CGPGroup *subGrp; CGPValue *pairs; const char *key; const char *val; // Lets work with the pairs first pairs = grp->GetPairs(); while( pairs ) { // the fields key = pairs->GetName(); val = pairs->GetTopValue(); // Huge stricmp lists suxor if ( !stricmp( key, "count" )) { ParseCount( val ); } else if ( !stricmp( key, "shaders" ) || !stricmp( key, "shader" )) { ParseShaders( pairs ); } else if ( !stricmp( key, "models" ) || !stricmp( key, "model" )) { ParseModels( pairs ); } else if ( !stricmp( key, "sounds" ) || !stricmp( key, "sound" )) { ParseSounds( pairs ); } else if ( !stricmp( key, "impactfx" )) { ParseImpactFxStrings( pairs ); } else if ( !stricmp( key, "deathfx" )) { ParseDeathFxStrings( pairs ); } else if ( !stricmp( key, "emitfx" )) { ParseEmitterFxStrings( pairs ); } else if ( !stricmp( key, "playfx" )) { ParsePlayFxStrings( pairs ); } else if ( !stricmp( key, "life" )) { ParseLife( val ); } else if ( !stricmp( key, "cullrange" )) { mCullRange = atoi( val ); mCullRange *= mCullRange; // Square } else if ( !stricmp( key, "delay" )) { ParseDelay( val ); } else if ( !stricmp( key, "bounce" ) || !stricmp( key, "intensity" )) // me==bad for reusing this...but it shouldn't hurt anything) { ParseElasticity( val ); } else if ( !stricmp( key, "min" )) { ParseMin( val ); } else if ( !stricmp( key, "max" )) { ParseMax( val ); } else if ( !stricmp( key, "angle" ) || !stricmp( key, "angles" )) { ParseAngle( val ); } else if ( !stricmp( key, "angleDelta" )) { ParseAngleDelta( val ); } else if ( !stricmp( key, "velocity" ) || !stricmp( key, "vel" )) { ParseVelocity( val ); } else if ( !stricmp( key, "acceleration" ) || !stricmp( key, "accel" )) { ParseAcceleration( val ); } else if ( !stricmp( key, "gravity" )) { ParseGravity( val ); } else if ( !stricmp( key, "density" )) { ParseDensity( val ); } else if ( !stricmp( key, "variance" )) { ParseVariance( val ); } else if ( !stricmp( key, "origin" )) { ParseOrigin1( val ); } else if ( !stricmp( key, "origin2" )) { ParseOrigin2( val ); } else if ( !stricmp( key, "radius" )) // part of ellipse/cylinder calcs. { ParseRadius( val ); } else if ( !stricmp( key, "height" )) // part of ellipse/cylinder calcs. { ParseHeight( val ); } else if ( !stricmp( key, "rotation" )) { ParseRotation( val ); } else if ( !Q_stricmp( key, "rotationDelta" )) { ParseRotationDelta( val ); } else if ( !stricmp( key, "flags" ) || !stricmp( key, "flag" )) { // these need to get passed on to the primitive ParseFlags( val ); } else if ( !stricmp( key, "spawnFlags" ) || !stricmp( key, "spawnFlag" )) { // these are used to spawn things in cool ways, but don't ever get passed on to prims. ParseSpawnFlags( val ); } else if ( !stricmp( key, "name" )) { if ( val ) { // just stash the descriptive name of the primitive strcpy( mName, val ); } } else { theFxHelper.Print( "Unknown key parsing an effect primitive: %s\n", key ); } pairs = (CGPValue *)pairs->GetNext(); } subGrp = grp->GetSubGroups(); // Lets chomp on the groups now while ( subGrp ) { key = subGrp->GetName(); if ( !stricmp( key, "rgb" )) { ParseRGB( subGrp ); } else if ( !stricmp( key, "alpha" )) { ParseAlpha( subGrp ); } else if ( !stricmp( key, "size" ) || !stricmp( key, "width" )) { ParseSize( subGrp ); } else if ( !stricmp( key, "size2" ) || !stricmp( key, "width2" )) { ParseSize2( subGrp ); } else if ( !stricmp( key, "length" ) || !stricmp( key, "height" )) { ParseLength( subGrp ); } else { theFxHelper.Print( "Unknown group key parsing a particle: %s\n", key ); } subGrp = (CGPGroup *)subGrp->GetNext(); } return true; }
static sboolean Music_ParseLeveldata(const char *psLevelName) { sboolean bReturn = qfalse; if (MusicData == NULL) { MusicData = new MusicData_t; } // already got this data? // if (MusicData->size() && !Q_stricmp(psLevelName,gsLevelNameForCompare.c_str())) { return qtrue; } MusicData->clear(); char sLevelName[MAX_QPATH]; Q_strncpyz(sLevelName,psLevelName,sizeof(sLevelName)); gsLevelNameForLoad = sLevelName; // harmless to init here even if we fail to parse dms.dat file gsLevelNameForCompare = sLevelName; // harmless to init here even if we fail to parse dms.dat file gsLevelNameForBossLoad = sLevelName; // harmless to init here even if we fail to parse dms.dat file char *pText = NULL; /*int iTotalBytesLoaded = */FS_ReadFile(sFILENAME_DMS, (void **)&pText ); if (pText) { char *psStrippedText = StripTrailingWhiteSpaceOnEveryLine(pText); CGenericParser2 Parser; char *psDataPtr = psStrippedText; // because ptr gets advanced, so we supply a clone that GP can alter if (Parser.Parse(&psDataPtr, true)) { CGPGroup *pFileGroup = Parser.GetBaseParseGroup(); if (pFileGroup) { CGPGroup *pgMusicFiles = pFileGroup->FindSubGroup(sKEY_MUSICFILES); if (pgMusicFiles) { CGPGroup *pgLevelMusic = pFileGroup->FindSubGroup(sKEY_LEVELMUSIC); if (pgLevelMusic) { CGPGroup *pgThisLevelMusic = NULL; // // check for new USE keyword... // int iSanityLimit = 0; sstring_t sSearchName(sLevelName); while (sSearchName.c_str()[0] && iSanityLimit < 10) { gsLevelNameForLoad = sSearchName; gsLevelNameForBossLoad = sSearchName; pgThisLevelMusic = pgLevelMusic->FindSubGroup(sSearchName.c_str()); if (pgThisLevelMusic) { CGPValue *pValue = pgThisLevelMusic->FindPair(sKEY_USES); if (pValue) { // re-search using the USE param... // sSearchName = pValue->GetTopValue(); iSanityLimit++; // Com_DPrintf("Using \"%s\"\n",sSearchName.c_str()); } else { // no new USE keyword found... // sSearchName = ""; } } else { // level entry not found... // break; } } // now go ahead and use the final music set we've decided on... // if (pgThisLevelMusic && iSanityLimit < 10) { // these are optional fields, so see which ones we find... // LPCSTR psName_Explore = NULL; LPCSTR psName_Action = NULL; LPCSTR psName_Boss = NULL; LPCSTR psName_Death = NULL; // LPCSTR psName_UseBoss = NULL; for (CGPValue *pValue = pgThisLevelMusic->GetPairs(); pValue; pValue = pValue->GetNext()) { LPCSTR psKey = pValue->GetName(); LPCSTR psValue = pValue->GetTopValue(); if (Q_stricmp(psValue,sKEY_PLACEHOLDER)) // ignore "placeholder" items { if (!Q_stricmp(psKey,sKEY_EXPLORE)) { psName_Explore = psValue; } else if (!Q_stricmp(psKey,sKEY_ACTION)) { psName_Action = psValue; } else if (!Q_stricmp(psKey,sKEY_USEBOSS)) { psName_UseBoss = psValue; } else if (!Q_stricmp(psKey,sKEY_BOSS)) { psName_Boss = psValue; } else if (!Q_stricmp(psKey,sKEY_DEATH)) { psName_Death = psValue; } } } bReturn = qtrue; // defualt to ON now, so I can turn it off if "useboss" fails if (psName_UseBoss) { CGPGroup *pgLevelMusicOfBoss = pgLevelMusic->FindSubGroup(psName_UseBoss); if (pgLevelMusicOfBoss) { CGPValue *pValueBoss = pgLevelMusicOfBoss->FindPair(sKEY_BOSS); if (pValueBoss) { psName_Boss = pValueBoss->GetTopValue(); gsLevelNameForBossLoad = psName_UseBoss; } else { MUSIC_PARSE_ERROR(va("'useboss' \"%s\" has no \"boss\" entry!\n",psName_UseBoss)); bReturn = qfalse; } } else { MUSIC_PARSE_ERROR(va("Unable to find 'useboss' entry \"%s\"\n",psName_UseBoss)); bReturn = qfalse; } } // done this way in case I want to conditionally pass any bools depending on music type... // if (bReturn && psName_Explore) { bReturn = Music_ParseMusic(Parser, MusicData, pgMusicFiles, psName_Explore, sKEY_EXPLORE, eBGRNDTRACK_EXPLORE); } if (bReturn && psName_Action) { bReturn = Music_ParseMusic(Parser, MusicData, pgMusicFiles, psName_Action, sKEY_ACTION, eBGRNDTRACK_ACTION); } if (bReturn && psName_Boss) { bReturn = Music_ParseMusic(Parser, MusicData, pgMusicFiles, psName_Boss, sKEY_BOSS, eBGRNDTRACK_BOSS); } if (bReturn /*&& psName_Death*/) // LAST MINUTE HACK!!, always force in some death music!!!! { //bReturn = Music_ParseMusic(Parser, MusicData, pgMusicFiles, psName_Death, sKEY_DEATH, eBGRNDTRACK_DEATH); MusicFile_t m; m.sFileNameBase = "death_music"; (*MusicData)[ sKEY_DEATH ] = m; } } else { MUSIC_PARSE_WARNING(va("Unable to find entry for \"%s\" in \"%s\"\n",sLevelName,sFILENAME_DMS)); } } else { MUSIC_PARSE_ERROR(va("Unable to find subgroup \"%s\"\n",sKEY_LEVELMUSIC)); } } else { MUSIC_PARSE_ERROR(va("Unable to find subgroup \"%s\"\n",sKEY_MUSICFILES)); } } else { MUSIC_PARSE_ERROR( "Error calling GP2.GetBaseParseGroup()\n" ); } } else { MUSIC_PARSE_ERROR( "Error using GP to parse file\n" ); } Z_Free(psStrippedText); FS_FreeFile( pText ); } else { MUSIC_PARSE_ERROR( "Unable to even read main file\n" ); // file name specified in error message } if (bReturn) { // sort exit points, and do some error checking... // for (MusicData_t::iterator itMusicData = MusicData->begin(); itMusicData != MusicData->end(); ++itMusicData) { LPCSTR psMusicStateType = (*itMusicData).first.c_str(); MusicFile_t &MusicFile = (*itMusicData).second; // kludge up an enum, only interested in boss or not at the moment, so... // MusicState_e eMusicState = !stricmp(psMusicStateType,"boss") ? eBGRNDTRACK_BOSS : !stricmp(psMusicStateType,"death") ? eBGRNDTRACK_DEATH : eBGRNDTRACK_EXPLORE; if (!MusicFile.MusicExitTimes.empty()) { sort(MusicFile.MusicExitTimes.begin(),MusicFile.MusicExitTimes.end()); } // check music exists... // LPCSTR psMusicFileName = Music_BuildFileName( MusicFile.sFileNameBase.c_str(), eMusicState ); if (!S_FileExists( psMusicFileName )) { MUSIC_PARSE_ERROR(va("Music file \"%s\" not found!\n",psMusicFileName)); return qfalse; // have to return, because music data destroyed now } // check all transition music pieces exist, and that entry points into new pieces after transitions also exist... // for (int iExitPoint=0; iExitPoint < MusicFile.MusicExitPoints.size(); iExitPoint++) { MusicExitPoint_t &MusicExitPoint = MusicFile.MusicExitPoints[ iExitPoint ]; LPCSTR psTransitionFileName = Music_BuildFileName( MusicExitPoint.sNextFile.c_str(), eMusicState ); if (!S_FileExists( psTransitionFileName )) { MUSIC_PARSE_ERROR(va("Transition file \"%s\" (entry \"%s\" ) not found!\n",psTransitionFileName, MusicExitPoint.sNextFile.c_str())); return qfalse; // have to return, because music data destroyed now } LPCSTR psNextMark = MusicExitPoint.sNextMark.c_str(); if (strlen(psNextMark)) // always NZ ptr { // then this must be "action" music under current rules... // assert( !strcmp(psMusicStateType, Music_BaseStateToString(eBGRNDTRACK_ACTION) ? Music_BaseStateToString(eBGRNDTRACK_ACTION):"") ); // // does this marker exist in the explore piece? // MusicData_t::iterator itExploreMusicData = MusicData->find( Music_BaseStateToString(eBGRNDTRACK_EXPLORE) ); if (itExploreMusicData != MusicData->end()) { MusicFile_t &MusicFile_Explore = (*itExploreMusicData).second; if (!MusicFile_Explore.MusicEntryTimes.count(psNextMark)) { MUSIC_PARSE_ERROR( va("Unable to find entry point \"%s\" in description for \"%s\"\n",psNextMark,MusicFile_Explore.sFileNameBase.c_str()) ); return qfalse; // have to return, because music data destroyed now } } else { MUSIC_PARSE_ERROR( va("Unable to find %s piece to match \"%s\"\n", Music_BaseStateToString(eBGRNDTRACK_EXPLORE), MusicFile.sFileNameBase.c_str() ) ); return qfalse; // have to return, because music data destroyed now } } } } } #ifdef _DEBUG /* // dump the whole thing out to prove it was read in ok... // if (bReturn) { for (MusicData_t::iterator itMusicData = MusicData->begin(); itMusicData != MusicData->end(); ++itMusicData) { LPCSTR psMusicState = (*itMusicData).first.c_str(); MusicFile_t &MusicFile = (*itMusicData).second; OutputDebugString(va("Music State: \"%s\", File: \"%s\"\n",psMusicState, MusicFile.sFileNameBase.c_str())); // entry times... // for (MusicEntryTimes_t::iterator itEntryTimes = MusicFile.MusicEntryTimes.begin(); itEntryTimes != MusicFile.MusicEntryTimes.end(); ++itEntryTimes) { LPCSTR psMarkerName = (*itEntryTimes).first.c_str(); float fEntryTime = (*itEntryTimes).second; OutputDebugString(va("Entry time for \"%s\": %f\n", psMarkerName, fEntryTime)); } // exit points... // for (int i=0; i<MusicFile.MusicExitPoints.size(); i++) { MusicExitPoint_t &MusicExitPoint = MusicFile.MusicExitPoints[i]; OutputDebugString(va("Exit point %d: sNextFile: \"%s\", sNextMark: \"%s\"\n",i,MusicExitPoint.sNextFile.c_str(),MusicExitPoint.sNextMark.c_str())); } // exit times... // for (i=0; i<MusicFile.MusicExitTimes.size(); i++) { MusicExitTime_t &MusicExitTime = MusicFile.MusicExitTimes[i]; OutputDebugString(va("Exit time %d: fTime: %f, iExitPoint: %d\n",i,MusicExitTime.fTime,MusicExitTime.iExitPoint)); } } } */ #endif return bReturn; }
static bool Music_ParseMusic( gsl::czstring filename, const CGenericParser2& Parser, MusicData_t* MusicData, const CGPGroup& pgMusicFiles, const gsl::cstring_view& psMusicName, const gsl::cstring_view& psMusicNameKey, MusicState_e eMusicState ) { bool bReturn = false; MusicFile_t MusicFile; const CGPGroup* pgMusicFile = pgMusicFiles.FindSubGroup( psMusicName ); if( pgMusicFile ) { // read subgroups... // bool bEntryFound = false; bool bExitFound = false; // // (read entry points first, so I can check exit points aren't too close in time) // const CGPGroup* pEntryGroup = pgMusicFile->FindSubGroup( sKEY_ENTRY ); if( pEntryGroup ) { // read entry points... // for( auto& prop : pEntryGroup->GetProperties() ) { //if (!strncmp(psKey,sKEY_MARKER,strlen(sKEY_MARKER))) // for now, assume anything is a marker MusicFile.MusicEntryTimes[ StringViewToSString( prop.GetName() ) ] = Q::svtoi( prop.GetTopValue() ); bEntryFound = true; } } for( auto& group : pgMusicFile->GetSubGroups() ) { auto& groupName = group.GetName(); if( groupName == sKEY_ENTRY ) { // skip entry points, I've already read them in above // } else if( groupName == sKEY_EXIT ) { int iThisExitPointIndex = MusicFile.MusicExitPoints.size(); // must eval this first, so unaffected by push_back etc // // read this set of exit points... // MusicExitPoint_t MusicExitPoint; for( auto& prop : group.GetProperties() ) { auto& key = prop.GetName(); auto& value = prop.GetTopValue(); if( key == sKEY_NEXTFILE ) { MusicExitPoint.sNextFile = StringViewToSString( value ); bExitFound = true; // harmless to keep setting } else if( key == sKEY_NEXTMARK ) { MusicExitPoint.sNextMark = StringViewToSString( value ); } else if( key == sKEY_TIME ) { MusicExitTime_t MusicExitTime; MusicExitTime.fTime = Q::svtof( value ); MusicExitTime.iExitPoint = iThisExitPointIndex; // new check, don't keep this this exit point if it's within 1.5 seconds either way of an entry point... // bool bTooCloseToEntryPoint = false; for( auto& item : MusicFile.MusicEntryTimes ) { float fThisEntryTime = item.second; if( Q_fabs( fThisEntryTime - MusicExitTime.fTime ) < 1.5f ) { // bTooCloseToEntryPoint = true; // not sure about this, ignore for now break; } } if( !bTooCloseToEntryPoint ) { MusicFile.MusicExitTimes.push_back( MusicExitTime ); } } } MusicFile.MusicExitPoints.push_back( MusicExitPoint ); int iNumExitPoints = MusicFile.MusicExitPoints.size(); // error checking... // switch( eMusicState ) { case eBGRNDTRACK_EXPLORE: if( iNumExitPoints > iMAX_EXPLORE_TRANSITIONS ) { Music_Parse_Error( filename, build_string( "\"", psMusicName, "\" has > ", iMAX_EXPLORE_TRANSITIONS, " ", psMusicNameKey, " transitions defined!\n" ) ); return false; } break; case eBGRNDTRACK_ACTION: if( iNumExitPoints > iMAX_ACTION_TRANSITIONS ) { Music_Parse_Error( filename, build_string( "\"", psMusicName, "\" has > ", iMAX_ACTION_TRANSITIONS, " ", psMusicNameKey, " transitions defined!\n" ) ); return false; } break; case eBGRNDTRACK_BOSS: case eBGRNDTRACK_DEATH: Music_Parse_Error( filename, build_string( "\"", psMusicName, "\" has ", psMusicNameKey, " transitions defined, this is not allowed!\n" ) ); return false; default: break; } } } // for now, assume everything was ok unless some obvious things are missing... // bReturn = true; // boss & death pieces can omit entry/exit stuff if( eMusicState != eBGRNDTRACK_BOSS && eMusicState != eBGRNDTRACK_DEATH ) { if( !bEntryFound ) { Music_Parse_Error( filename, build_string( "Unable to find subgroup \"", sKEY_ENTRY, "\" in group \"", psMusicName, "\"\n" ) ); bReturn = false; } if( !bExitFound ) { Music_Parse_Error( filename, build_string( "Unable to find subgroup \"", sKEY_EXIT, "\" in group \"", psMusicName, "\"\n" ) ); bReturn = false; } } } else { Music_Parse_Error( filename, build_string( "Unable to find musicfiles entry \"", psMusicName, "\"\n" ) ); } if( bReturn ) { MusicFile.sFileNameBase = StringViewToSString( psMusicName ); ( *MusicData )[ StringViewToSString( psMusicNameKey ) ] = MusicFile; } return bReturn; }
// 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()); }
static LPCSTR Skins_Parse(string strThisSkinFileName, CGPGroup *pFileGroup, CGPGroup *pParseGroup_Prefs) { LPCSTR psError = NULL; // read any optional surface on/off blocks... // for (int iSurfaceOnOffType = 0; iSurfaceOnOffType<3; iSurfaceOnOffType++) { CGPGroup *pSurfaceParseGroup = NULL; switch (iSurfaceOnOffType) { case 0: pSurfaceParseGroup = pParseGroup_Prefs->FindSubGroup(sSKINKEYWORD_SURFACES_ON); break; case 1: pSurfaceParseGroup = pParseGroup_Prefs->FindSubGroup(sSKINKEYWORD_SURFACES_OFF); break; case 2: pSurfaceParseGroup = pParseGroup_Prefs->FindSubGroup(sSKINKEYWORD_SURFACES_OFFNOCHILDREN); break; default: assert(0); break; } if (pSurfaceParseGroup) { CGPValue *pValue = pSurfaceParseGroup->GetPairs(); while (pValue) { // string str1 = (*it).first; // junk, eg "name1" string str2 = pValue->GetTopValue(); switch (iSurfaceOnOffType) { case 0: CurrentSkinsSurfacePrefs[strThisSkinFileName].vSurfacesOn.push_back(str2); break; case 1: CurrentSkinsSurfacePrefs[strThisSkinFileName].vSurfacesOff.push_back(str2); break; case 2: CurrentSkinsSurfacePrefs[strThisSkinFileName].vSurfacesOffNoChildren.push_back(str2); break; default: assert(0); break; } pValue = pValue->GetNext(); } } } // find all the materials and add them to the skin set... // int iMaterialDeclarationIndex = 0; for (CGPGroup *pMaterialGroup = pFileGroup->GetSubGroups(); pMaterialGroup; pMaterialGroup = pMaterialGroup->GetNext(), iMaterialDeclarationIndex++) { string strKeyWord = pMaterialGroup->GetName(); if (strKeyWord == sSKINKEYWORD_MATERIAL) { string strMaterialName(pMaterialGroup->FindPairValue(sSKINKEYWORD_NAME,"")); if (strMaterialName == "") { psError = va("%s[%d] had no \"%s\" field!\n",sSKINKEYWORD_MATERIAL, iMaterialDeclarationIndex, sSKINKEYWORD_NAME); return psError; } // now iterate through the ethnic group variants of this material... // int iEthnicGroupIndex = 0; for (CGPGroup *pEthnicGroup = pMaterialGroup->GetSubGroups(); pEthnicGroup; pEthnicGroup = pEthnicGroup->GetNext(), iEthnicGroupIndex++) { strKeyWord = pEthnicGroup->GetName(); if (strKeyWord == sSKINKEYWORD_GROUP) { string strEthnicGroupName(pEthnicGroup->FindPairValue(sSKINKEYWORD_NAME,"")); if (strEthnicGroupName == "") { psError = va("%s[%d] %s[%d] had no \"%s\" field!\n",sSKINKEYWORD_MATERIAL, iMaterialDeclarationIndex, sSKINKEYWORD_GROUP, iEthnicGroupIndex, sSKINKEYWORD_NAME); return psError; } // now iterate through the shader variants for this ethnic version of this material... (is anyone reading this...?) // int iAlternateShaderIndex = 0; for (CGPValue *pValue = pEthnicGroup->GetPairs(); pValue; pValue = pValue->GetNext()) { string strField(pValue->GetName()); if (strField != sSKINKEYWORD_NAME) { // ... then it should be a shader... // string strShader(pValue->GetTopValue()); CurrentSkins[strThisSkinFileName][strEthnicGroupName][strMaterialName].push_back(strShader); } } } } } } return psError; }
// Parse a primitive, apply defaults first, grab any base level // key pairs, then process any sub groups we may contain. //------------------------------------------------------ bool CPrimitiveTemplate::ParsePrimitive( const CGPGroup& grp ) { // Property for( auto& prop : grp.GetProperties() ) { // Single Value Parsing { static StringViewIMap< ParseMethod > parseMethods{ { CSTRING_VIEW( "count" ), &CPrimitiveTemplate::ParseCount }, { CSTRING_VIEW( "life" ), &CPrimitiveTemplate::ParseLife }, { CSTRING_VIEW( "delay" ), &CPrimitiveTemplate::ParseDelay }, { CSTRING_VIEW( "bounce" ), &CPrimitiveTemplate::ParseElasticity }, { CSTRING_VIEW( "intensity" ), &CPrimitiveTemplate::ParseElasticity }, { CSTRING_VIEW( "min" ), &CPrimitiveTemplate::ParseMin }, { CSTRING_VIEW( "max" ), &CPrimitiveTemplate::ParseMax }, { CSTRING_VIEW( "angle" ), &CPrimitiveTemplate::ParseAngle }, { CSTRING_VIEW( "angles" ), &CPrimitiveTemplate::ParseAngle }, { CSTRING_VIEW( "angleDelta" ), &CPrimitiveTemplate::ParseAngleDelta }, { CSTRING_VIEW( "velocity" ), &CPrimitiveTemplate::ParseVelocity }, { CSTRING_VIEW( "vel" ), &CPrimitiveTemplate::ParseVelocity }, { CSTRING_VIEW( "acceleration" ), &CPrimitiveTemplate::ParseAcceleration }, { CSTRING_VIEW( "accel" ), &CPrimitiveTemplate::ParseAcceleration }, { CSTRING_VIEW( "gravity" ), &CPrimitiveTemplate::ParseGravity }, { CSTRING_VIEW( "density" ), &CPrimitiveTemplate::ParseDensity }, { CSTRING_VIEW( "variance" ), &CPrimitiveTemplate::ParseVariance }, { CSTRING_VIEW( "origin" ), &CPrimitiveTemplate::ParseOrigin1 }, { CSTRING_VIEW( "origin2" ), &CPrimitiveTemplate::ParseOrigin2 }, { CSTRING_VIEW( "radius" ), &CPrimitiveTemplate::ParseRadius }, { CSTRING_VIEW( "height" ), &CPrimitiveTemplate::ParseHeight }, { CSTRING_VIEW( "wind" ), &CPrimitiveTemplate::ParseWindModifier }, { CSTRING_VIEW( "rotation" ), &CPrimitiveTemplate::ParseRotation }, { CSTRING_VIEW( "rotationDelta" ), &CPrimitiveTemplate::ParseRotationDelta }, { CSTRING_VIEW( "flags" ), &CPrimitiveTemplate::ParseFlags }, { CSTRING_VIEW( "flag" ), &CPrimitiveTemplate::ParseFlags }, { CSTRING_VIEW( "spawnFlags" ), &CPrimitiveTemplate::ParseSpawnFlags }, { CSTRING_VIEW( "spawnFlag" ), &CPrimitiveTemplate::ParseSpawnFlags }, }; auto pos = parseMethods.find( prop.GetName() ); if( pos != parseMethods.end() ) { ParseMethod method = pos->second; ( this->*method )( prop.GetTopValue() ); continue; } } // Property Parsing { using PropertyParseMethod = bool( CPrimitiveTemplate::* )( const CGPProperty& ); static StringViewIMap< PropertyParseMethod > parseMethods{ { CSTRING_VIEW( "shaders" ), &CPrimitiveTemplate::ParseShaders }, { CSTRING_VIEW( "shader" ), &CPrimitiveTemplate::ParseShaders }, { CSTRING_VIEW( "models" ), &CPrimitiveTemplate::ParseModels }, { CSTRING_VIEW( "model" ), &CPrimitiveTemplate::ParseModels }, { CSTRING_VIEW( "sounds" ), &CPrimitiveTemplate::ParseSounds }, { CSTRING_VIEW( "sound" ), &CPrimitiveTemplate::ParseSounds }, { CSTRING_VIEW( "impactfx" ), &CPrimitiveTemplate::ParseImpactFxStrings }, { CSTRING_VIEW( "deathfx" ), &CPrimitiveTemplate::ParseDeathFxStrings }, { CSTRING_VIEW( "emitfx" ), &CPrimitiveTemplate::ParseEmitterFxStrings }, { CSTRING_VIEW( "playfx" ), &CPrimitiveTemplate::ParsePlayFxStrings }, }; auto pos = parseMethods.find( prop.GetName() ); if( pos != parseMethods.end() ) { PropertyParseMethod method = pos->second; ( this->*method )( prop ); continue; } } // Special Cases if( Q::stricmp( prop.GetName(), CSTRING_VIEW( "cullrange" ) ) == Q::Ordering::EQ ) { mCullRange = Q::svtoi( prop.GetTopValue() ); mCullRange *= mCullRange; // Square } else if( Q::stricmp( prop.GetName(), CSTRING_VIEW( "name" ) ) == Q::Ordering::EQ ) { if( !prop.GetTopValue().empty() ) { // just stash the descriptive name of the primitive std::size_t len = std::min< std::size_t >( prop.GetTopValue().size(), FX_MAX_PRIM_NAME - 1 ); auto begin = prop.GetTopValue().begin(); std::copy( begin, begin + len, &mName[ 0 ] ); mName[ len ] = '\0'; } } // Error else { theFxHelper.Print( "Unknown key parsing an effect primitive!\n" ); } } for( auto& subGrp : grp.GetSubGroups() ) { using GroupParseMethod = bool ( CPrimitiveTemplate::* )( const CGPGroup& ); static StringViewIMap< GroupParseMethod > parseMethods{ { CSTRING_VIEW( "rgb" ), &CPrimitiveTemplate::ParseRGB }, { CSTRING_VIEW( "alpha" ), &CPrimitiveTemplate::ParseAlpha }, { CSTRING_VIEW( "size" ), &CPrimitiveTemplate::ParseSize }, { CSTRING_VIEW( "width" ), &CPrimitiveTemplate::ParseSize }, { CSTRING_VIEW( "size2" ), &CPrimitiveTemplate::ParseSize2 }, { CSTRING_VIEW( "width2" ), &CPrimitiveTemplate::ParseSize2 }, { CSTRING_VIEW( "length" ), &CPrimitiveTemplate::ParseLength }, { CSTRING_VIEW( "height" ), &CPrimitiveTemplate::ParseLength }, }; auto pos = parseMethods.find( subGrp.GetName() ); if( pos == parseMethods.end() ) { theFxHelper.Print( "Unknown group key parsing a particle!\n" ); } else { GroupParseMethod method = pos->second; ( this->*method )( subGrp ); } } return true; }
static sboolean Music_ParseMusic(CGenericParser2 &Parser, MusicData_t *MusicData, CGPGroup *pgMusicFiles, LPCSTR psMusicName, LPCSTR psMusicNameKey, MusicState_e eMusicState) { sboolean bReturn = qfalse; #ifdef _XBOX Z_SetNewDeleteTemporary(true); #endif MusicFile_t MusicFile; #ifdef _XBOX Z_SetNewDeleteTemporary(false); #endif CGPGroup *pgMusicFile = pgMusicFiles->FindSubGroup(psMusicName); if (pgMusicFile) { // read subgroups... // sboolean bEntryFound = qfalse; sboolean bExitFound = qfalse; // // (read entry points first, so I can check exit points aren't too close in time) // CGPGroup *pEntryGroup = pgMusicFile->FindSubGroup(sKEY_ENTRY); if (pEntryGroup) { // read entry points... // for (CGPValue *pValue = pEntryGroup->GetPairs(); pValue; pValue = pValue->GetNext()) { LPCSTR psKey = pValue->GetName(); LPCSTR psValue = pValue->GetTopValue(); //if (!strncmp(psKey,sKEY_MARKER,strlen(sKEY_MARKER))) // for now, assume anything is a marker { MusicFile.MusicEntryTimes[psKey] = atof(psValue); bEntryFound = qtrue; // harmless to keep setting } } } for (CGPGroup *pGroup = pgMusicFile->GetSubGroups(); pGroup; pGroup = pGroup->GetNext()) { LPCSTR psGroupName = pGroup->GetName(); if (!strcmp(psGroupName,sKEY_ENTRY)) { // skip entry points, I've already read them in above // } else if (!strcmp(psGroupName,sKEY_EXIT)) { int iThisExitPointIndex = MusicFile.MusicExitPoints.size(); // must eval this first, so unaffected by push_back etc // // read this set of exit points... // MusicExitPoint_t MusicExitPoint; for (CGPValue *pValue = pGroup->GetPairs(); pValue; pValue = pValue->GetNext()) { LPCSTR psKey = pValue->GetName(); LPCSTR psValue = pValue->GetTopValue(); if (!strcmp(psKey,sKEY_NEXTFILE)) { MusicExitPoint.sNextFile = psValue; bExitFound = qtrue; // harmless to keep setting } else if (!strcmp(psKey,sKEY_NEXTMARK)) { MusicExitPoint.sNextMark = psValue; } else if (!strncmp(psKey,sKEY_TIME,strlen(sKEY_TIME))) { MusicExitTime_t MusicExitTime; MusicExitTime.fTime = atof(psValue); MusicExitTime.iExitPoint= iThisExitPointIndex; // new check, don't keep this this exit point if it's within 1.5 seconds either way of an entry point... // sboolean bTooCloseToEntryPoint = qfalse; for (MusicEntryTimes_t::iterator itEntryTimes = MusicFile.MusicEntryTimes.begin(); itEntryTimes != MusicFile.MusicEntryTimes.end(); ++itEntryTimes) { float fThisEntryTime = (*itEntryTimes).second; if (Q_fabs(fThisEntryTime - MusicExitTime.fTime) < 1.5f) { // bTooCloseToEntryPoint = qtrue; // not sure about this, ignore for now break; } } if (!bTooCloseToEntryPoint) { #ifdef _XBOX Z_SetNewDeleteTemporary(true); #endif MusicFile.MusicExitTimes.push_back(MusicExitTime); #ifdef _XBOX Z_SetNewDeleteTemporary(false); #endif } } } #ifdef _XBOX Z_SetNewDeleteTemporary(true); #endif MusicFile.MusicExitPoints.push_back(MusicExitPoint); #ifdef _XBOX Z_SetNewDeleteTemporary(false); #endif int iNumExitPoints = MusicFile.MusicExitPoints.size(); // error checking... // switch (eMusicState) { case eBGRNDTRACK_EXPLORE: if (iNumExitPoints > iMAX_EXPLORE_TRANSITIONS) { MUSIC_PARSE_ERROR( va("\"%s\" has > %d %s transitions defined!\n",psMusicName,iMAX_EXPLORE_TRANSITIONS,psMusicNameKey) ); return qfalse; } break; case eBGRNDTRACK_ACTION: if (iNumExitPoints > iMAX_ACTION_TRANSITIONS) { MUSIC_PARSE_ERROR( va("\"%s\" has > %d %s transitions defined!\n",psMusicName,iMAX_ACTION_TRANSITIONS,psMusicNameKey) ); return qfalse; } break; case eBGRNDTRACK_BOSS: case eBGRNDTRACK_DEATH: MUSIC_PARSE_ERROR( va("\"%s\" has %s transitions defined, this is not allowed!\n",psMusicName,psMusicNameKey) ); break; } } } // for now, assume everything was ok unless some obvious things are missing... // bReturn = qtrue; if (eMusicState != eBGRNDTRACK_BOSS && eMusicState != eBGRNDTRACK_DEATH) // boss & death pieces can omit entry/exit stuff { if (!bEntryFound) { MUSIC_PARSE_ERROR(va("Unable to find subgroup \"%s\" in group \"%s\"\n",sKEY_ENTRY,psMusicName)); bReturn = qfalse; } if (!bExitFound) { MUSIC_PARSE_ERROR(va("Unable to find subgroup \"%s\" in group \"%s\"\n",sKEY_EXIT,psMusicName)); bReturn = qfalse; } } } else { MUSIC_PARSE_ERROR(va("Unable to find musicfiles entry \"%s\"\n",psMusicName)); } if (bReturn) { MusicFile.sFileNameBase = psMusicName; (*MusicData)[ psMusicNameKey ] = MusicFile; } return bReturn; }
/************************************************************************************************ * CRMManager::LoadMission * Loads the mission using the mission name stored in the ar_mission cvar * * inputs: * none * * return: * none * ************************************************************************************************/ bool CRMManager::LoadMission ( qboolean IsServer ) { char instances[MAX_QPATH]; char mission[MAX_QPATH]; char course[MAX_QPATH]; char map[MAX_QPATH]; char temp[MAX_QPATH]; #ifndef FINAL_BUILD Com_Printf ("--------- Random Mission Manager ---------\n\n"); Com_Printf ("RMG version : 1.01\n\n"); #endif if (!mTerrain) { return false; } // Grab the arioche variables Cvar_VariableStringBuffer("rmg_usetimelimit", temp, MAX_QPATH); if (Q_stricmp(temp, "yes") == 0) { mUseTimeLimit = true; } Cvar_VariableStringBuffer("rmg_instances", instances, MAX_QPATH); Cvar_VariableStringBuffer("RMG_mission", temp, MAX_QPATH); Cvar_VariableStringBuffer("rmg_map", map, MAX_QPATH); Com_sprintf(mission, sizeof(mission), "%s_%s", temp, map); Cvar_VariableStringBuffer("rmg_course", course, MAX_QPATH); // dump existing mission, if any if (mMission) { delete mMission; mMission = NULL; } // Create a new mission file mMission = new CRMMission ( mTerrain ); if ( IsServer ) { // Load the mission using the arioche variables if ( !mMission->Load ( mission, instances, course ) ) { return false; } // set the names of the teams CGenericParser2 parser; CGPGroup* root; Cvar_VariableStringBuffer("RMG_terrain", temp, MAX_QPATH); // Create the parser for the mission file if(Com_ParseTextFile(va("ext_data/rmg/%s.teams", temp), parser)) { root = parser.GetBaseParseGroup()->GetSubGroups(); if (0 == stricmp(root->GetName(), "teams")) { /* SV_SetConfigstring( CS_GAMETYPE_REDTEAM, root->FindPairValue ( "red", "marine" )); SV_SetConfigstring( CS_GAMETYPE_BLUETEAM, root->FindPairValue ( "blue", "thug" )); */ //rwwFIXMEFIXME: Do we care about this? } parser.Clean(); } } // Must have a valid landscape before we can spawn the mission assert ( mLandScape ); #ifndef FINAL_BUILD Com_Printf ("------------------------------------------\n"); #endif return true; }