Esempio n. 1
0
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;
}