Song Attacks modifier (course-style scripted mods in regular single play)

This commit is contained in:
Mike Hawkins
2008-05-30 01:09:00 +00:00
parent 316f9b511f
commit 25b13dfcdf
8 changed files with 143 additions and 65 deletions
@@ -623,6 +623,7 @@ Silent=Silent
Skip=Skip Skip=Skip
Skippy=Skippy Skippy=Skippy
Slow=Slow Slow=Slow
SongAttacks=Song Attacks
Song BGAnimation=Song BGAnimation Song BGAnimation=Song BGAnimation
Song Bitmap=Song Bitmap Song Bitmap=Song Bitmap
Song Movie=Song Movie Song Movie=Song Movie
+3 -2
View File
@@ -3669,10 +3669,11 @@ Mines,1="mod,nomines;name,Off"
Mines,2="name,On" Mines,2="name,On"
Mines,3="mod,mines;name,Add" Mines,3="mod,mines;name,Add"
Mines,4="mod,attackmines;name,AttackMines" Mines,4="mod,attackmines;name,AttackMines"
Attacks="2" Attacks="3"
AttacksDefault="mod,no randomattacks" AttacksDefault="mod,no randomattacks,no songattacks"
Attacks,1="name,Off" Attacks,1="name,Off"
Attacks,2="mod,randomattacks;name,RandomAttacks" Attacks,2="mod,randomattacks;name,RandomAttacks"
Attacks,3="mod,songattacks;name,SongAttacks"
Hide="3" Hide="3"
HideDefault="mod,no dark,no blind" HideDefault="mod,no dark,no blind"
Hide,1="name,Off" Hide,1="name,Off"
+98 -52
View File
@@ -14,14 +14,14 @@
const int MAX_EDIT_STEPS_SIZE_BYTES = 30*1024; // 30KB const int MAX_EDIT_STEPS_SIZE_BYTES = 30*1024; // 30KB
static void LoadFromSMTokens( static void LoadFromSMTokens(
RString sStepsType, RString sStepsType,
RString sDescription, RString sDescription,
RString sDifficulty, RString sDifficulty,
RString sMeter, RString sMeter,
RString sRadarValues, RString sRadarValues,
RString sNoteData, RString sNoteData,
Steps &out Steps &out
) )
{ {
out.SetSavedToDisk( true ); // we're loading from disk, so this is by definintion already saved out.SetSavedToDisk( true ); // we're loading from disk, so this is by definintion already saved
@@ -30,7 +30,7 @@ static void LoadFromSMTokens(
Trim( sDifficulty ); Trim( sDifficulty );
Trim( sNoteData ); Trim( sNoteData );
// LOG->Trace( "Steps::LoadFromSMTokens()" ); // LOG->Trace( "Steps::LoadFromSMTokens()" );
out.m_StepsType = GameManager::StringToStepsType( sStepsType ); out.m_StepsType = GameManager::StringToStepsType( sStepsType );
out.SetDescription( sDescription ); out.SetDescription( sDescription );
@@ -53,7 +53,7 @@ static void LoadFromSMTokens(
RadarValues v[NUM_PLAYERS]; RadarValues v[NUM_PLAYERS];
FOREACH_PlayerNumber( pn ) FOREACH_PlayerNumber( pn )
FOREACH_ENUM( RadarCategory, rc ) FOREACH_ENUM( RadarCategory, rc )
v[pn][rc] = StringToFloat( saValues[pn*NUM_RadarCategory + rc] ); v[pn][rc] = StringToFloat( saValues[pn*NUM_RadarCategory + rc] );
out.SetCachedRadarValues( v ); out.SetCachedRadarValues( v );
} }
@@ -110,7 +110,7 @@ void SMLoader::LoadTimingFromSMFile( const MsdFile &msd, TimingData &out )
{ {
// XXX: Hard to tell which file caused this. // XXX: Hard to tell which file caused this.
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.", LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.",
sValueName.c_str(), arrayFreezeExpressions[f].c_str() ); sValueName.c_str(), arrayFreezeExpressions[f].c_str() );
continue; continue;
} }
@@ -119,7 +119,7 @@ void SMLoader::LoadTimingFromSMFile( const MsdFile &msd, TimingData &out )
StopSegment new_seg( BeatToNoteRow(fFreezeBeat), fFreezeSeconds ); StopSegment new_seg( BeatToNoteRow(fFreezeBeat), fFreezeSeconds );
// LOG->Trace( "Adding a freeze segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fStopSeconds ); // LOG->Trace( "Adding a freeze segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fStopSeconds );
out.AddStopSegment( new_seg ); out.AddStopSegment( new_seg );
} }
@@ -138,7 +138,7 @@ void SMLoader::LoadTimingFromSMFile( const MsdFile &msd, TimingData &out )
if( arrayBPMChangeValues.size() != 2 ) if( arrayBPMChangeValues.size() != 2 )
{ {
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.", LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.",
sValueName.c_str(), arrayBPMChangeExpressions[b].c_str() ); sValueName.c_str(), arrayBPMChangeExpressions[b].c_str() );
continue; continue;
} }
@@ -291,7 +291,7 @@ bool SMLoader::LoadFromSMFile( const RString &sPath, Song &out, bool bFromCache
// handle the data // handle the data
/* Don't use GetMainAndSubTitlesFromFullTitle; that's only for heuristically /* Don't use GetMainAndSubTitlesFromFullTitle; that's only for heuristically
* splitting other formats that *don't* natively support #SUBTITLE. */ * splitting other formats that *don't* natively support #SUBTITLE. */
if( sValueName=="TITLE" ) if( sValueName=="TITLE" )
out.m_sMainTitle = sParams[1]; out.m_sMainTitle = sParams[1];
@@ -363,7 +363,7 @@ bool SMLoader::LoadFromSMFile( const RString &sPath, Song &out, bool bFromCache
; /* ignore */ ; /* ignore */
/* We calculate these. Some SMs in circulation have bogus values for /* We calculate these. Some SMs in circulation have bogus values for
* these, so make sure we always calculate it ourself. */ * these, so make sure we always calculate it ourself. */
else if( sValueName=="FIRSTBEAT" ) else if( sValueName=="FIRSTBEAT" )
{ {
if( bFromCache ) if( bFromCache )
@@ -465,6 +465,52 @@ bool SMLoader::LoadFromSMFile( const RString &sPath, Song &out, bool bFromCache
split( sParams[1], ",", out.m_vsKeysoundFile ); split( sParams[1], ",", out.m_vsKeysoundFile );
} }
// Attacks loaded from file
else if( sValueName=="ATTACKS" )
{
// Build the RString vector here so we can write it to file again later
for( unsigned s=1; s < sParams.params.size(); ++s )
out.m_sAttackString.push_back( sParams[s] );
Attack attack;
float end = -9999;
for( unsigned j=1; j < sParams.params.size(); ++j )
{
vector<RString> sBits;
split( sParams[j], "=", sBits, false );
// Need an identifer and a value for this to work
if( sBits.size() < 2 )
continue;
TrimLeft( sBits[0] );
TrimRight( sBits[0] );
if( !sBits[0].CompareNoCase("TIME") )
attack.fStartSecond = strtof( sBits[1], NULL );
else if( !sBits[0].CompareNoCase("LEN") )
attack.fSecsRemaining = strtof( sBits[1], NULL );
else if( !sBits[0].CompareNoCase("END") )
end = strtof( sBits[1], NULL );
else if( !sBits[0].CompareNoCase("MODS") )
{
attack.sModifiers = sBits[1];
if( end != -9999 )
{
attack.fSecsRemaining = end - attack.fStartSecond;
end = -9999;
}
if( attack.fSecsRemaining < 0.0f )
attack.fSecsRemaining = 0.0f;
out.m_Attacks.push_back( attack );
}
}
}
else if( sValueName=="NOTES" || sValueName=="NOTES2" ) else if( sValueName=="NOTES" || sValueName=="NOTES2" )
{ {
if( iNumParams < 7 ) if( iNumParams < 7 )
@@ -486,7 +532,7 @@ bool SMLoader::LoadFromSMFile( const RString &sPath, Song &out, bool bFromCache
out.AddSteps( pNewNotes ); out.AddSteps( pNewNotes );
} }
else if( sValueName=="OFFSET" || sValueName=="BPMS" || sValueName=="STOPS" || sValueName=="FREEZES" || sValueName=="TIMESIGNATURES" ) else if( sValueName=="OFFSET" || sValueName=="BPMS" || sValueName=="STOPS" || sValueName=="FREEZES" || sValueName=="TIMESIGNATURES" )
; ;
else else
LOG->UserLog( "Song file", sPath, "has an unexpected value named \"%s\".", sValueName.c_str() ); LOG->UserLog( "Song file", sPath, "has an unexpected value named \"%s\".", sValueName.c_str() );
} }
@@ -507,7 +553,7 @@ bool SMLoader::LoadFromDir( const RString &sPath, Song &out )
} }
/* We should have exactly one; if we had none, we shouldn't have been /* We should have exactly one; if we had none, we shouldn't have been
* called to begin with. */ * called to begin with. */
ASSERT( aFileNames.size() == 1 ); ASSERT( aFileNames.size() == 1 );
return LoadFromSMFile( sPath + aFileNames[0], out ); return LoadFromSMFile( sPath + aFileNames[0], out );
@@ -627,20 +673,20 @@ bool SMLoader::LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath
void SMLoader::TidyUpData( Song &song, bool bFromCache ) void SMLoader::TidyUpData( Song &song, bool bFromCache )
{ {
/* /*
* Hack: if the song has any changes at all (so it won't use a random BGA) * Hack: if the song has any changes at all (so it won't use a random BGA)
* and doesn't end with "-nosongbg-", add a song background BGC. Remove * and doesn't end with "-nosongbg-", add a song background BGC. Remove
* "-nosongbg-" if it exists. * "-nosongbg-" if it exists.
* *
* This way, songs that were created earlier, when we added the song BG * This way, songs that were created earlier, when we added the song BG
* at the end by default, will still behave as expected; all new songs will * at the end by default, will still behave as expected; all new songs will
* have to add an explicit song BG tag if they want it. This is really a * have to add an explicit song BG tag if they want it. This is really a
* formatting hack only; nothing outside of SMLoader ever sees "-nosongbg-". * formatting hack only; nothing outside of SMLoader ever sees "-nosongbg-".
*/ */
vector<BackgroundChange> &bg = song.GetBackgroundChanges(BACKGROUND_LAYER_1); vector<BackgroundChange> &bg = song.GetBackgroundChanges(BACKGROUND_LAYER_1);
if( !bg.empty() ) if( !bg.empty() )
{ {
/* BGChanges have been sorted. On the odd chance that a BGChange exists /* BGChanges have been sorted. On the odd chance that a BGChange exists
* with a very high beat, search the whole list. */ * with a very high beat, search the whole list. */
bool bHasNoSongBgTag = false; bool bHasNoSongBgTag = false;
for( unsigned i = 0; !bHasNoSongBgTag && i < bg.size(); ++i ) for( unsigned i = 0; !bHasNoSongBgTag && i < bg.size(); ++i )
@@ -656,12 +702,12 @@ void SMLoader::TidyUpData( Song &song, bool bFromCache )
if( !bHasNoSongBgTag ) do if( !bHasNoSongBgTag ) do
{ {
/* If we're loading cache, -nosongbg- should always be in there. We must /* If we're loading cache, -nosongbg- should always be in there. We must
* not call IsAFile(song.GetBackgroundPath()) when loading cache. */ * not call IsAFile(song.GetBackgroundPath()) when loading cache. */
if( bFromCache ) if( bFromCache )
break; break;
/* If BGChanges already exist after the last beat, don't add the background /* If BGChanges already exist after the last beat, don't add the background
* in the middle. */ * in the middle. */
if( !bg.empty() && bg.back().m_fStartBeat-0.0001f >= song.m_fLastBeat ) if( !bg.empty() && bg.back().m_fStartBeat-0.0001f >= song.m_fLastBeat )
break; break;
@@ -678,26 +724,26 @@ void SMLoader::TidyUpData( Song &song, bool bFromCache )
} }
/* /*
* (c) 2001-2004 Chris Danford, Glenn Maynard * (c) 2001-2004 Chris Danford, Glenn Maynard
* All rights reserved. * All rights reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the * copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including * "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish, * without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to * distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above * whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of * copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this * the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation. * permission notice appear in supporting documentation.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE. * PERFORMANCE OF THIS SOFTWARE.
*/ */
+11
View File
@@ -168,6 +168,17 @@ static void WriteGlobalTags( RageFile &f, const Song &out )
f.Write( "," ); f.Write( "," );
} }
f.PutLine( ";" ); f.PutLine( ";" );
f.Write( "#ATTACKS:" );
for( unsigned a=0; a < out.m_sAttackString.size(); a++ )
{
RString sData = out.m_sAttackString[a];
f.Write( ssprintf( "%s", sData.c_str() ) );
if( a != (out.m_sAttackString.size() - 1) )
f.Write( ":" ); // Not the end, so write a divider ':'
}
f.PutLine( ";" );
} }
static RString JoinLineList( vector<RString> &lines ) static RString JoinLineList( vector<RString> &lines )
+6 -1
View File
@@ -28,6 +28,7 @@ void PlayerOptions::Init()
m_fBlind = 0; m_SpeedfBlind = 1.0f; m_fBlind = 0; m_SpeedfBlind = 1.0f;
m_fCover = 0; m_SpeedfCover = 1.0f; m_fCover = 0; m_SpeedfCover = 1.0f;
m_fRandAttack = 0; m_SpeedfRandAttack = 1.0f; m_fRandAttack = 0; m_SpeedfRandAttack = 1.0f;
m_fSongAttack = 0; m_SpeedfSongAttack = 1.0f;
m_bSetTiltOrSkew = false; m_bSetTiltOrSkew = false;
m_fPerspectiveTilt = 0; m_SpeedfPerspectiveTilt = 1.0f; m_fPerspectiveTilt = 0; m_SpeedfPerspectiveTilt = 1.0f;
m_fSkew = 0; m_SpeedfSkew = 1.0f; m_fSkew = 0; m_SpeedfSkew = 1.0f;
@@ -63,6 +64,7 @@ void PlayerOptions::Approach( const PlayerOptions& other, float fDeltaSeconds )
APPROACH( fBlind ); APPROACH( fBlind );
APPROACH( fCover ); APPROACH( fCover );
APPROACH( fRandAttack ); APPROACH( fRandAttack );
APPROACH( fSongAttack );
APPROACH( fPerspectiveTilt ); APPROACH( fPerspectiveTilt );
APPROACH( fSkew ); APPROACH( fSkew );
APPROACH( fPassmark ); APPROACH( fPassmark );
@@ -136,7 +138,7 @@ void PlayerOptions::GetMods( vector<RString> &AddTo, bool bForceNoteSkin ) const
AddPart( AddTo, m_fEffects[EFFECT_DRUNK], "Drunk" ); AddPart( AddTo, m_fEffects[EFFECT_DRUNK], "Drunk" );
AddPart( AddTo, m_fEffects[EFFECT_DIZZY], "Dizzy" ); AddPart( AddTo, m_fEffects[EFFECT_DIZZY], "Dizzy" );
AddPart( AddTo, m_fEffects[EFFECT_CONFUSION], "Confusion" ); AddPart( AddTo, m_fEffects[EFFECT_CONFUSION], "Confusion" );
AddPart( AddTo, m_fEffects[EFFECT_MINI], "Mini" ); AddPart( AddTo, m_fEffects[EFFECT_MINI], "Mini" );
AddPart( AddTo, m_fEffects[EFFECT_TINY], "Tiny" ); AddPart( AddTo, m_fEffects[EFFECT_TINY], "Tiny" );
AddPart( AddTo, m_fEffects[EFFECT_FLIP], "Flip" ); AddPart( AddTo, m_fEffects[EFFECT_FLIP], "Flip" );
@@ -166,6 +168,7 @@ void PlayerOptions::GetMods( vector<RString> &AddTo, bool bForceNoteSkin ) const
AddPart( AddTo, m_fCover, "Cover" ); AddPart( AddTo, m_fCover, "Cover" );
AddPart( AddTo, m_fRandAttack, "RandomAttacks" ); AddPart( AddTo, m_fRandAttack, "RandomAttacks" );
AddPart( AddTo, m_fSongAttack, "SongAttacks" );
AddPart( AddTo, m_fPassmark, "Passmark" ); AddPart( AddTo, m_fPassmark, "Passmark" );
@@ -380,6 +383,7 @@ bool PlayerOptions::FromOneModString( const RString &sOneMod, RString &sErrorOut
else if( sBit == "blind" ) SET_FLOAT( fBlind ) else if( sBit == "blind" ) SET_FLOAT( fBlind )
else if( sBit == "cover" ) SET_FLOAT( fCover ) else if( sBit == "cover" ) SET_FLOAT( fCover )
else if( sBit == "randomattacks" ) SET_FLOAT( fRandAttack ) else if( sBit == "randomattacks" ) SET_FLOAT( fRandAttack )
else if( sBit == "songattacks" ) SET_FLOAT( fSongAttack )
else if( sBit == "passmark" ) SET_FLOAT( fPassmark ) else if( sBit == "passmark" ) SET_FLOAT( fPassmark )
else if( sBit == "overhead" ) { m_bSetTiltOrSkew = true; m_fSkew = 0; m_fPerspectiveTilt = 0; m_SpeedfSkew = m_SpeedfPerspectiveTilt = speed; } else if( sBit == "overhead" ) { m_bSetTiltOrSkew = true; m_fSkew = 0; m_fPerspectiveTilt = 0; m_SpeedfSkew = m_SpeedfPerspectiveTilt = speed; }
else if( sBit == "incoming" ) { m_bSetTiltOrSkew = true; m_fSkew = level; m_fPerspectiveTilt = -level; m_SpeedfSkew = m_SpeedfPerspectiveTilt = speed; } else if( sBit == "incoming" ) { m_bSetTiltOrSkew = true; m_fSkew = level; m_fPerspectiveTilt = -level; m_SpeedfSkew = m_SpeedfPerspectiveTilt = speed; }
@@ -619,6 +623,7 @@ bool PlayerOptions::operator==( const PlayerOptions &other ) const
COMPARE(m_fBlind); COMPARE(m_fBlind);
COMPARE(m_fCover); COMPARE(m_fCover);
COMPARE(m_fRandAttack); COMPARE(m_fRandAttack);
COMPARE(m_fSongAttack);
COMPARE(m_fPerspectiveTilt); COMPARE(m_fPerspectiveTilt);
COMPARE(m_fSkew); COMPARE(m_fSkew);
COMPARE(m_sNoteSkin); COMPARE(m_sNoteSkin);
+1
View File
@@ -134,6 +134,7 @@ public:
float m_fBlind, m_SpeedfBlind; float m_fBlind, m_SpeedfBlind;
float m_fCover, m_SpeedfCover; // hide the background per-player--can't think of a good name float m_fCover, m_SpeedfCover; // hide the background per-player--can't think of a good name
float m_fRandAttack, m_SpeedfRandAttack; float m_fRandAttack, m_SpeedfRandAttack;
float m_fSongAttack, m_SpeedfSongAttack;
bool m_bSetTiltOrSkew; // true if the tilt or skew was set by FromString bool m_bSetTiltOrSkew; // true if the tilt or skew was set by FromString
float m_fPerspectiveTilt, m_SpeedfPerspectiveTilt; // -1 = near, 0 = overhead, +1 = space float m_fPerspectiveTilt, m_SpeedfPerspectiveTilt; // -1 = near, 0 = overhead, +1 = space
float m_fSkew, m_SpeedfSkew; // 0 = vanish point is in center of player, 1 = vanish point is in center of screen float m_fSkew, m_SpeedfSkew; // 0 = vanish point is in center of player, 1 = vanish point is in center of screen
+10 -2
View File
@@ -830,8 +830,16 @@ void ScreenGameplay::InitSongQueues()
Steps *pSteps = GAMESTATE->m_pCurSteps[ pi->GetStepsAndTrailIndex() ]; Steps *pSteps = GAMESTATE->m_pCurSteps[ pi->GetStepsAndTrailIndex() ];
pi->m_vpStepsQueue.push_back( pSteps ); pi->m_vpStepsQueue.push_back( pSteps );
AttackArray aa; if( pi->GetPlayerState()->m_PlayerOptions.GetCurrent().m_fSongAttack != 0 &&
pi->m_asModifiersQueue.push_back( aa ); GAMESTATE->m_pCurSong->m_Attacks.size() > 0 )
{
pi->m_asModifiersQueue.push_back( GAMESTATE->m_pCurSong->m_Attacks );
}
else
{
AttackArray aa;
pi->m_asModifiersQueue.push_back( aa );
}
} }
} }
+5
View File
@@ -3,6 +3,7 @@
#ifndef SONG_H #ifndef SONG_H
#define SONG_H #define SONG_H
#include "Attack.h"
#include "TimingData.h" #include "TimingData.h"
#include "Difficulty.h" #include "Difficulty.h"
#include "EnumHelper.h" #include "EnumHelper.h"
@@ -144,6 +145,9 @@ public:
RString m_sBackgroundFile; RString m_sBackgroundFile;
RString m_sCDTitleFile; RString m_sCDTitleFile;
AttackArray m_Attacks;
vector<RString> m_sAttackString;
RString GetMusicPath() const; RString GetMusicPath() const;
RString GetInstrumentTrackPath( InstrumentTrack it ) const; RString GetInstrumentTrackPath( InstrumentTrack it ) const;
RString GetBannerPath() const; RString GetBannerPath() const;
@@ -151,6 +155,7 @@ public:
RString GetBackgroundPath() const; RString GetBackgroundPath() const;
RString GetCDTitlePath() const; RString GetCDTitlePath() const;
/* For loading only: */ /* For loading only: */
bool m_bHasMusic, m_bHasBanner; bool m_bHasMusic, m_bHasBanner;