no message

This commit is contained in:
Chris Danford
2002-06-30 23:19:33 +00:00
parent a44b557d1b
commit f8118fea49
17 changed files with 370 additions and 551 deletions
+1 -1
View File
@@ -125,7 +125,7 @@ void Background::Update( float fDeltaTime )
switch( PREFSMAN->m_visMode )
{
case VIS_MODE_ANIMATION:
if( m_pCurBackgroundAnimation )
if( m_pCurBackgroundAnimation && !m_bFreeze )
m_pCurBackgroundAnimation->Update( fDeltaTime, m_fSongBeat );
else
m_sprSongBackground.Update( fDeltaTime );
+2 -1
View File
@@ -29,7 +29,7 @@ public:
virtual void Update( float fDeltaTime );
virtual void DrawPrimitives();
void SetSongBeat( const float fSongBeat ) { m_fSongBeat = fSongBeat; };
void SetSongBeat( const float fSongBeat, const bool bFreeze ) { m_fSongBeat = fSongBeat; m_bFreeze = bFreeze; };
virtual void SetDiffuseColor( D3DXCOLOR c )
{
@@ -60,5 +60,6 @@ protected:
bool m_bShowDanger;
float m_fSongBeat;
bool m_bFreeze;
};
+14 -1
View File
@@ -154,6 +154,18 @@ inline CString DifficultyClassToString( DifficultyClass dc )
}
}
inline DifficultyClass StringToDifficultyClass( CString sDC )
{
for( int i=0; i<NUM_DIFFICULTY_CLASSES; i++ )
{
DifficultyClass dc = (DifficultyClass)i;
if( sDC == DifficultyClassToString(dc) )
return dc;
}
return CLASS_INVALID;
}
enum NotesType
{
NOTES_TYPE_DANCE_SINGLE = 0,
@@ -169,7 +181,7 @@ enum NotesType
NOTES_TYPE_INVALID,
};
inline int NotesTypeToNumColumns( NotesType nt )
inline int NotesTypeToNumTracks( NotesType nt )
{
switch( nt )
{
@@ -188,6 +200,7 @@ inline int NotesTypeToNumColumns( NotesType nt )
inline NotesType StringToNotesType( CString sNotesType )
{
sNotesType.MakeLower();
if ( sNotesType == "dance-single" ) return NOTES_TYPE_DANCE_SINGLE;
else if( sNotesType == "dance-double" ) return NOTES_TYPE_DANCE_DOUBLE;
else if( sNotesType == "dance-couple" ) return NOTES_TYPE_DANCE_COUPLE;
+2 -2
View File
@@ -38,8 +38,8 @@ void LifeMeterBar::ChangeLife( TapNoteScore score )
float fDeltaLife;
switch( score )
{
case TNS_PERFECT: fDeltaLife = +0.015f; break;
case TNS_GREAT: fDeltaLife = +0.008f; break;
case TNS_PERFECT: fDeltaLife = +0.008f; break;
case TNS_GREAT: fDeltaLife = +0.004f; break;
case TNS_GOOD: fDeltaLife = +0.000f; break;
case TNS_BOO: fDeltaLife = -0.040f; break;
case TNS_MISS: fDeltaLife = -0.080f; break;
+34 -5
View File
@@ -82,6 +82,8 @@ void WheelItemData::Load( WheelItemType wit, Song* pSong, const CString &sSectio
WheelItemDisplay::WheelItemDisplay()
{
m_fPercentGray = 0;
m_MusicStatusDisplay.SetXY( -136, 0 );
m_TextBanner.SetHorizAlign( align_left );
@@ -271,6 +273,15 @@ void WheelItemDisplay::DrawPrimitives()
m_TextBanner.Draw();
for( int p=0; p<NUM_PLAYERS; p++ )
m_GradeDisplay[p].Draw();
if( m_fPercentGray > 0 )
{
m_sprSongBar.SetDiffuseColor( D3DXCOLOR(1,1,1,0) );
m_sprSongBar.SetAddColor( D3DXCOLOR(0,0,0,m_fPercentGray) );
m_sprSongBar.Draw();
m_sprSongBar.SetDiffuseColor( D3DXCOLOR(1,1,1,1) );
m_sprSongBar.SetAddColor( D3DXCOLOR(0,0,0,0) );
}
}
break;
case TYPE_COURSE:
@@ -403,7 +414,7 @@ MusicWheel::~MusicWheel()
PREFSMAN->m_SongSortOrder = m_SortOrder;
}
void MusicWheel::BuildWheelItemDatas( CArray<WheelItemData, WheelItemData&> &arrayWheelItemDatas, SongSortOrder so )
void MusicWheel::BuildWheelItemDatas( CArray<WheelItemData, WheelItemData&> &arrayWheelItemDatas, SongSortOrder so, bool bRoulette )
{
int i;
@@ -469,6 +480,9 @@ void MusicWheel::BuildWheelItemDatas( CArray<WheelItemData, WheelItemData&> &arr
case SORT_TITLE: bUseSections = true; break;
default: ASSERT( false );
}
if( bRoulette )
bUseSections = false;
if( bUseSections )
{
@@ -556,7 +570,7 @@ void MusicWheel::BuildWheelItemDatas( CArray<WheelItemData, WheelItemData&> &arr
arrayWheelItemDatas.SetSize( 1 );
arrayWheelItemDatas[0].Load( TYPE_SECTION, NULL, "NO SONGS", NULL, D3DXCOLOR(1,0,0,1) );
}
else if( PREFSMAN->m_PlayMode == PLAY_MODE_ARCADE )
else if( PREFSMAN->m_PlayMode == PLAY_MODE_ARCADE && !bRoulette )
{
arrayWheelItemDatas.SetSize( arrayWheelItemDatas.GetSize()+1 );
arrayWheelItemDatas[arrayWheelItemDatas.GetSize()-1].Load( TYPE_ROULETTE, NULL, "", NULL, D3DXCOLOR(1,0,0,1) );
@@ -696,6 +710,11 @@ void MusicWheel::DrawPrimitives()
break;
};
if( m_WheelState == STATE_LOCKED && i != NUM_WHEEL_ITEMS_TO_DRAW/2 )
display.m_fPercentGray = 0.5f;
else
display.m_fPercentGray = 0;
display.Draw();
}
@@ -720,7 +739,7 @@ void MusicWheel::Update( float fDeltaTime )
if( m_WheelState == STATE_ROULETTE_SPINNING )
{
NextMusic(); // spin as fast as possible
NextMusic( false ); // spin as fast as possible
}
if( m_fTimeLeftBeforePlayMusicSample > 0 )
@@ -895,7 +914,7 @@ void MusicWheel::Update( float fDeltaTime )
}
void MusicWheel::PrevMusic()
void MusicWheel::PrevMusic( bool bSendSongChangedMessage )
{
if( m_WheelState == STATE_LOCKED )
{
@@ -935,9 +954,12 @@ void MusicWheel::PrevMusic()
m_fPositionOffsetFromSelection -= 1;
m_soundChangeMusic.Play();
if( bSendSongChangedMessage )
SCREENMAN->SendMessageToTopScreen( SM_SongChanged, 0 );
}
void MusicWheel::NextMusic()
void MusicWheel::NextMusic( bool bSendSongChangedMessage )
{
if( m_WheelState == STATE_LOCKED )
{
@@ -978,6 +1000,9 @@ void MusicWheel::NextMusic()
m_fPositionOffsetFromSelection += 1;
m_soundChangeMusic.Play();
if( bSendSongChangedMessage )
SCREENMAN->SendMessageToTopScreen( SM_SongChanged, 0 );
}
void MusicWheel::PrevSort()
@@ -1054,6 +1079,10 @@ bool MusicWheel::Select() // return true of a playable item was chosen
case TYPE_ROULETTE:
m_soundExpand.Play();
m_WheelState = STATE_ROULETTE_SPINNING;
m_SortOrder = SORT_GROUP;
m_MusicSortDisplay.SetDiffuseColor( D3DXCOLOR(1,1,1,0) );
m_MusicSortDisplay.SetEffectNone();
BuildWheelItemDatas( m_WheelItemDatas[SORT_GROUP], SORT_GROUP, true );
return false;
case TYPE_SONG:
+5 -3
View File
@@ -68,6 +68,8 @@ public:
void LoadFromWheelItemData( WheelItemData* pWID );
void RefreshGrades();
float m_fPercentGray;
// for TYPE_SECTION and TYPE_ROULETTE
Sprite m_sprSectionBar;
// for TYPE_SECTION
@@ -100,8 +102,8 @@ public:
virtual void TweenOnScreen();
virtual void TweenOffScreen();
void PrevMusic();
void NextMusic();
void PrevMusic( bool bSendSongChangedMessage = true );
void NextMusic( bool bSendSongChangedMessage = true );
void PrevSort();
void NextSort();
void NotesChanged( PlayerNumber pn ); // update grade graphics and top score
@@ -119,7 +121,7 @@ public:
protected:
void BuildWheelItemDatas( CArray<WheelItemData, WheelItemData&> &arrayWheelItems, SongSortOrder so );
void BuildWheelItemDatas( CArray<WheelItemData, WheelItemData&> &arrayWheelItems, SongSortOrder so, bool bRoulette = false );
void RebuildWheelItemDisplays();
void SwitchSortOrder();
-128
View File
@@ -36,43 +36,6 @@ NoteData::~NoteData()
{
}
void NoteData::WriteToCacheFile( FILE* file )
{
LOG->WriteLine( "NoteData::WriteToCacheFile()" );
ConvertHoldNotesTo2sAnd3s();
int iNumRows = GetLastRow();
fprintf( file, "%d\n", iNumRows );
fwrite( m_TapNotes, sizeof(TapNote), MAX_NOTE_TRACKS*iNumRows, file );
fprintf( file, "\n" );
Convert2sAnd3sToHoldNotes();
}
void NoteData::ReadFromCacheFile( FILE* file )
{
LOG->WriteLine( "NoteData::ReadFromCacheFile()" );
int iNumRows;
fscanf( file, "%d\n", &iNumRows );
fread( m_TapNotes, sizeof(TapNote), MAX_NOTE_TRACKS*iNumRows, file );
fscanf( file, "\n", &iNumRows );
Convert2sAnd3sToHoldNotes();
}
void NoteData::SkipOverDataInCacheFile( FILE* file )
{
LOG->WriteLine( "NoteData::SkipOverDataInCacheFile()" );
int iNumRows;
fscanf( file, "%d\n", &iNumRows );
int retval = fseek( file, sizeof(TapNote)*MAX_NOTE_TRACKS*iNumRows, SEEK_CUR );
ASSERT( retval == 0 );
fscanf( file, "\n", &iNumRows );
}
void NoteData::ClearRange( int iNoteIndexBegin, int iNoteIndexEnd )
{
@@ -633,97 +596,6 @@ void NoteData::SnapToNearestNoteType( NoteType nt1, NoteType nt2, float fBeginBe
}
void NoteData::GetMeasureStrings( CStringArray &arrayMeasureStrings )
{
ConvertHoldNotesTo2sAnd3s();
float fLastBeat = this->GetLastBeat();
int iLastMeasure = int( fLastBeat/BEATS_PER_MEASURE );
for( int m=0; m<=iLastMeasure; m++ ) // foreach measure
{
CString sMeasureString;
int iMeasureStartIndex = m * ELEMENTS_PER_MEASURE;
int iMeasureLastIndex = (m+1) * ELEMENTS_PER_MEASURE - 1;
// probe to find the smallest note type
NoteType nt;
int iNoteIndexSpacing;
for( nt=(NoteType)0; nt<NUM_NOTE_TYPES; nt=NoteType(nt+1) )
{
float fBeatSpacing = NoteTypeToBeat( nt );
iNoteIndexSpacing = roundf( fBeatSpacing * ELEMENTS_PER_BEAT );
bool bFoundSmallerNote = false;
for( int i=iMeasureStartIndex; i<=iMeasureLastIndex; i++ ) // for each index in this measure
{
if( i % iNoteIndexSpacing == 0 )
continue; // skip
if( !IsRowEmpty(i) )
{
bFoundSmallerNote = true;
break;
}
}
if( bFoundSmallerNote )
continue; // keep searching
else
break; // stop searching
}
if( nt == NUM_NOTE_TYPES ) // we didn't find one
iNoteIndexSpacing = 1;
for( int i=iMeasureStartIndex; i<=iMeasureLastIndex; i+=iNoteIndexSpacing )
{
for( int c=0; c<m_iNumTracks; c++ )
sMeasureString += m_TapNotes[c][i];
sMeasureString += '\n';
}
arrayMeasureStrings.Add( sMeasureString );
}
}
void NoteData::SetFromMeasureStrings( CStringArray &arrayMeasureStrings )
{
for( int m=0; m<arrayMeasureStrings.GetSize(); m++ )
{
CString sMeasureString = arrayMeasureStrings[m];
sMeasureString.TrimLeft();
sMeasureString.TrimRight();
CStringArray arrayNoteLines;
split( sMeasureString, "\n", arrayNoteLines );
int iNumNoteLines = arrayNoteLines.GetSize();
for( int l=0; l<arrayNoteLines.GetSize(); l++ )
{
const float fPercentIntoMeasure = l/(float)arrayNoteLines.GetSize();
const float fBeat = (m + fPercentIntoMeasure) * BEATS_PER_MEASURE;
const int iIndex = BeatToNoteRow( fBeat );
CString sNoteLine = arrayNoteLines[l];
sNoteLine.TrimRight();
m_iNumTracks = max( m_iNumTracks, sNoteLine.GetLength() );
for( int c=0; c<sNoteLine.GetLength(); c++ )
{
m_TapNotes[c][iIndex] = sNoteLine[c];
}
}
}
ASSERT( m_iNumTracks != 0 );
}
float NoteData::GetStreamRadarValue( float fSongSeconds )
{
// density of steps
-11
View File
@@ -47,17 +47,6 @@ public:
void Init();
~NoteData();
// used for loading
void SetFromMeasureStrings( CStringArray &arrayMeasureStrings ); // for loading from a .notes file
void SetFromDWIInfo(); // for loading from a .dwi file
void SetFromBMSInfo(); // for loading from a .bms file
void ReadFromCacheFile( FILE* file );
static void SkipOverDataInCacheFile( FILE* file );
// used for saving
void GetMeasureStrings( CStringArray &arrayMeasureStrings ); // for saving to a .notes file
void WriteToCacheFile( FILE* file );
int m_iNumTracks;
TapNote m_TapNotes[MAX_NOTE_TRACKS][MAX_TAP_NOTE_ROWS];
HoldNote m_HoldNotes[MAX_HOLD_NOTE_ELEMENTS];
+141 -138
View File
@@ -42,8 +42,12 @@ enum {
Notes::Notes()
{
m_NotesType = NOTES_TYPE_DANCE_SINGLE;
m_DifficultyClass = CLASS_EASY;
m_iMeter = 0;
for( int r=0; r<NUM_RADAR_VALUES; r++ )
m_fRadarValues[r] = 0;
m_iNumTimesPlayed = 0;
m_iMaxCombo = 0;
m_iTopScore = 0;
@@ -57,54 +61,6 @@ Notes::~Notes()
DeleteNoteData();
}
void Notes::WriteToCacheFile( FILE* file )
{
LOG->WriteLine( "Notes::WriteToCacheFile()" );
fprintf( file, "%d\n", m_NotesType );
WriteStringToFile( file, m_sDescription );
WriteStringToFile( file, m_sCredit );
fprintf( file, "%d\n", m_DifficultyClass );
fprintf( file, "%d\n", m_iMeter );
for( int i=0; i<NUM_RADAR_VALUES; i++ )
fprintf( file, "%f\n", m_fRadarValues[i] );
fprintf( file, "%d\n", m_TopGrade );
fprintf( file, "%d\n", m_iTopScore );
fprintf( file, "%d\n", m_iMaxCombo );
fprintf( file, "%d\n", m_iNumTimesPlayed );
ASSERT( m_pNoteData != NULL );
m_pNoteData->WriteToCacheFile( file );
}
void Notes::ReadFromCacheFile( FILE* file, bool bLoadNoteData )
{
LOG->WriteLine( "Notes::ReadFromCacheFile( %d )", bLoadNoteData );
fscanf( file, "%d\n", &m_NotesType );
ReadStringFromFile( file, m_sDescription );
ReadStringFromFile( file, m_sCredit );
fscanf( file, "%d\n", &m_DifficultyClass );
fscanf( file, "%d\n", &m_iMeter );
for( int i=0; i<NUM_RADAR_VALUES; i++ )
fscanf( file, "%f\n", &m_fRadarValues[i] );
fscanf( file, "%d\n", &m_TopGrade );
fscanf( file, "%d\n", &m_iTopScore );
fscanf( file, "%d\n", &m_iMaxCombo );
fscanf( file, "%d\n", &m_iNumTimesPlayed );
if( bLoadNoteData )
{
GetNoteData()->ReadFromCacheFile( file );
}
else
{
DeleteNoteData();
NoteData::SkipOverDataInCacheFile( file );
}
}
// BMS encoding: tap-hold
@@ -655,116 +611,163 @@ bool Notes::LoadFromDWITokens(
return true;
}
bool Notes::LoadFromNotesFile( const CString &sPath )
void Notes::LoadFromSMTokens(
const CString &sNotesType,
const CString &sDescription,
const CString &sCredit,
const CString &sDifficultyClass,
const CString &sMeter,
const CString &sRadarValues,
const CString &sNoteDataOut,
const bool bLoadNoteData
)
{
LOG->WriteLine( "Notes::LoadFromNotesFile( '%s' )", sPath );
LOG->WriteLine( "Notes::LoadFromSMTokens( %d )", bLoadNoteData );
CStdioFile file;
if( !file.Open( sPath, CFile::modeRead|CFile::shareDenyNone ) )
throw RageException( "Error opening DWI file '%s'.", sPath );
m_NotesType = StringToNotesType(sNotesType);
m_sDescription = sDescription;
m_sCredit = sCredit;
m_DifficultyClass = StringToDifficultyClass( sDifficultyClass );
m_iMeter = atoi(sMeter);
CStringArray saValues;
split( sRadarValues, ",", saValues, true );
if( saValues.GetSize() == NUM_RADAR_VALUES )
for( int r=0; r<NUM_RADAR_VALUES; r++ )
m_fRadarValues[r] = (float)atof(saValues[r]);
// read the whole file into a sFileText
CString sFileText;
CString buffer;
while( file.ReadString(buffer) )
sFileText += buffer + "\n";
file.Close();
if( m_iMeter < 1 || m_iMeter > 10 )
m_iMeter = 4;
if( m_DifficultyClass == CLASS_INVALID )
m_DifficultyClass = DifficultyClassFromDescriptionAndMeter( sDescription, m_iMeter );
// strip comments out of sFileText
while( sFileText.Find("//") != -1 )
//
// Load NoteData
//
NoteData *pND = GetNoteData();
pND->m_iNumTracks = NotesTypeToNumTracks( m_NotesType );
CStringArray asNoteData;
split( sNoteDataOut, ",", asNoteData, true );
for( int i=0; i<asNoteData.GetSize(); i+=2 )
{
int iIndexCommentStart = sFileText.Find("//");
int iIndexCommentEnd = sFileText.Find("\n", iIndexCommentStart);
if( iIndexCommentEnd == -1 ) // comment doesn't have an end?
sFileText.Delete( iIndexCommentStart, 2 );
else
sFileText.Delete( iIndexCommentStart, iIndexCommentEnd-iIndexCommentStart );
int iNumRowsInMeasure = atoi( asNoteData[i] );
CString sMeasureString = asNoteData[i+1];
sMeasureString.TrimLeft();
sMeasureString.TrimRight();
CStringArray arrayNoteLines;
split( sMeasureString, "\n", arrayNoteLines );
if( arrayNoteLines.GetSize() != iNumRowsInMeasure )
throw RageException( "Actual number of note rows (%d) doesn't match what tag says (%d).", arrayNoteLines.GetSize(), iNumRowsInMeasure );
for( int l=0; l<iNumRowsInMeasure; l++ )
{
const float fPercentIntoMeasure = l/(float)arrayNoteLines.GetSize();
const float fBeat = (i + fPercentIntoMeasure) * BEATS_PER_MEASURE;
const int iIndex = BeatToNoteRow( fBeat );
CString sNoteLine = arrayNoteLines[l];
sNoteLine.TrimRight();
if( pND->m_iNumTracks != sNoteLine.GetLength() )
throw RageException( "Actual number of note columns (%d) is different from the NotesType (%d).", pND->m_iNumTracks, sNoteLine.GetLength() );
for( int c=0; c<sNoteLine.GetLength(); c++ )
pND->m_TapNotes[c][iIndex] = sNoteLine[c];
}
}
// split sFileText into strings containing each value expression
CStringArray arrayValueStrings;
split( sFileText, ";", arrayValueStrings );
}
void Notes::WriteSMNotesTag( FILE* fp )
{
fprintf( fp, "#NOTES:\n" );
fprintf( fp, " %s:\n", NotesTypeToString(m_NotesType) );
fprintf( fp, " %s:\n", m_sDescription );
fprintf( fp, " %s:\n", m_sCredit );
fprintf( fp, " %s:\n", DifficultyClassToString(m_DifficultyClass) );
fprintf( fp, " %d:\n", m_iMeter );
CStringArray asRadarValues;
for( int r=0; r<NUM_RADAR_VALUES; r++ )
asRadarValues.Add( ssprintf("%.1f", m_fRadarValues[r]) );
fprintf( fp, " %s:\n", join(",",asRadarValues) );
// for each value expression string, parse it into a value name and data
for( int i=0; i < arrayValueStrings.GetSize(); i++ )
//
// fill in sNoteDataOut
//
NoteData* pND = GetNoteData();
pND->ConvertHoldNotesTo2sAnd3s();
float fLastBeat = pND->GetLastBeat();
int iLastMeasure = int( fLastBeat/BEATS_PER_MEASURE );
for( int m=0; m<=iLastMeasure; m++ ) // foreach measure
{
CString sValueString = arrayValueStrings[i];
int iMeasureStartIndex = m * ELEMENTS_PER_MEASURE;
int iMeasureLastIndex = (m+1) * ELEMENTS_PER_MEASURE - 1;
// split the value string into tokens
CStringArray arrayValueTokens;
split( sValueString, ":", arrayValueTokens, false );
if( arrayValueTokens.GetSize() == 0 )
continue;
CString sValueName = arrayValueTokens.GetAt( 0 );
sValueName.TrimLeft();
sValueName.TrimRight();
// handle the data
if( sValueName == "#TYPE" )
m_NotesType = StringToNotesType( arrayValueTokens[1] );
else if( sValueName == "#DESCRIPTION" )
m_sDescription = arrayValueTokens[1];
else if( sValueName == "#CREDIT" )
m_sCredit = arrayValueTokens[1];
else if( sValueName == "#METER" )
m_iMeter = atoi( arrayValueTokens[1] );
else if( sValueName == "#NOTES" )
// probe to find the smallest note type
NoteType nt;
int iNoteIndexSpacing;
for( nt=(NoteType)0; nt<NUM_NOTE_TYPES; nt=NoteType(nt+1) )
{
arrayValueTokens.RemoveAt( 0 );
float fBeatSpacing = NoteTypeToBeat( nt );
iNoteIndexSpacing = roundf( fBeatSpacing * ELEMENTS_PER_BEAT );
ASSERT( m_pNoteData == NULL ); // if not, then we're loading this NoteData twice
m_pNoteData = new NoteData;
m_pNoteData->SetFromMeasureStrings( arrayValueTokens );
bool bFoundSmallerNote = false;
for( int i=iMeasureStartIndex; i<=iMeasureLastIndex; i++ ) // for each index in this measure
{
if( i % iNoteIndexSpacing == 0 )
continue; // skip
if( !pND->IsRowEmpty(i) )
{
bFoundSmallerNote = true;
break;
}
}
if( bFoundSmallerNote )
continue; // keep searching
else
break; // stop searching
}
else
LOG->WriteLine( "Unexpected value named '%s'", sValueName );
if( nt == NUM_NOTE_TYPES ) // we didn't find one
iNoteIndexSpacing = 1;
fprintf( fp, "%d, // measure %d\n", ELEMENTS_PER_MEASURE/iNoteIndexSpacing, m+1 );
for( int i=iMeasureStartIndex; i<=iMeasureLastIndex; i+=iNoteIndexSpacing )
{
CString sLineString;
for( int c=0; c<pND->m_iNumTracks; c++ )
sLineString += pND->m_TapNotes[c][i];
fprintf( fp, "%s", sLineString );
if( i == iMeasureLastIndex )
fprintf( fp, ",\n" );
else
fprintf( fp, "\n" );
}
}
m_DifficultyClass = DifficultyClassFromDescriptionAndMeter( m_sDescription, m_iMeter );
return true;
fprintf( fp, ";\n" );
pND->Convert2sAnd3sToHoldNotes();
}
void Notes::SaveToSMDir( CString sSongDir )
DifficultyClass Notes::DifficultyClassFromDescriptionAndMeter( CString sDescription, int iMeter )
{
LOG->WriteLine( "Notes::Save( '%s' )", sSongDir );
CString sNewNotesFilePath = sSongDir + ssprintf("%s-%s.notes", NotesTypeToString(m_NotesType), m_sDescription);
CStdioFile file;
if( !file.Open( sNewNotesFilePath, CFile::modeWrite | CFile::modeCreate ) )
throw RageException( "Error opening Notes file '%s' for writing.", sNewNotesFilePath );
file.WriteString( ssprintf("#TYPE:%s;\n", NotesTypeToString(m_NotesType)) );
file.WriteString( ssprintf("#DESCRIPTION:%s;\n", m_sDescription) );
file.WriteString( ssprintf("#METER:%d;\n", m_iMeter) );
file.WriteString( ssprintf("#CREDIT:%s;\n", m_sCredit) );
file.WriteString( "#NOTES:\n" );
CStringArray sMeasureStrings;
GetNoteData()->GetMeasureStrings( sMeasureStrings );
file.WriteString( join(":\n", sMeasureStrings) );
file.WriteString( ";" );
file.Close();
}
DifficultyClass Notes::DifficultyClassFromDescriptionAndMeter( CString sDifficulty, int iMeter )
{
sDifficulty.MakeLower();
sDescription.MakeLower();
const CString sDescriptionParts[NUM_DIFFICULTY_CLASSES][3] = {
{
@@ -786,7 +789,7 @@ DifficultyClass Notes::DifficultyClassFromDescriptionAndMeter( CString sDifficul
for( int i=0; i<NUM_DIFFICULTY_CLASSES; i++ )
for( int j=0; j<3; j++ )
if( sDifficulty.Find(sDescriptionParts[i][j]) != -1 )
if( sDescription.Find(sDescriptionParts[i][j]) != -1 )
return DifficultyClass(i);
// guess difficulty class from meter
+20 -14
View File
@@ -26,22 +26,31 @@ public:
// Loading
bool LoadFromNotesFile( const CString &sPath );
bool LoadFromBMSFile( const CString &sPath );
bool LoadFromDWITokens( const CString &sMode, const CString &sDescription,
const int &iNumFeet,
const CString &sStepData1, const CString &sStepData2 );
void ReadFromCacheFile( FILE* file, bool bReadNoteData );
// for saving
void SaveToSMDir( CString sSongDir );
void WriteToCacheFile( FILE* file );
//
bool LoadFromDWITokens(
const CString &sMode,
const CString &sDescription,
const int &iNumFeet,
const CString &sStepData1, const CString &sStepData2
);
void LoadFromSMTokens(
const CString &sNotesType,
const CString &sDescription,
const CString &sCredit,
const CString &sDifficultyClass,
const CString &sMeter,
const CString &sRadarValues,
const CString &sNoteDataOut,
const bool bLoadNoteData
);
void WriteSMNotesTag( FILE* fp );
public:
NotesType m_NotesType;
CString m_sDescription; // This text is displayed next to thte number of feet when a song is selected
CString m_sCredit; // name of the person who created these Notes
DifficultyClass m_DifficultyClass; // this is inferred from m_sDescription
int m_iMeter; // difficulty from 1-10
float m_fRadarValues[NUM_RADAR_VALUES]; // between 0.0-1.2 starting from 12-o'clock rotating clockwise
// Color is a function of DifficultyClass and Intended Style
D3DXCOLOR GetColor()
@@ -57,8 +66,6 @@ public:
return DifficultyClassToColor( m_DifficultyClass );
}
int m_iMeter; // difficulty from 1-10
float m_fRadarValues[NUM_RADAR_VALUES]; // between 0.0-1.2 starting from 12-o'clock rotating clockwise
// Statistics
Grade m_TopGrade;
@@ -72,8 +79,7 @@ public:
void DeleteNoteData();
protected:
static DifficultyClass DifficultyClassFromDescriptionAndMeter( CString sDifficulty, int iMeter );
static DifficultyClass DifficultyClassFromDescriptionAndMeter( CString sDescription, int iMeter );
NoteData* m_pNoteData;
};
+9 -9
View File
@@ -285,20 +285,20 @@ void GetDirListing( CString sPath, CStringArray &AddTo, bool bOnlyDirs, bool bRe
::FindClose( hFind );
}
ULONG GetHashForString( CString s )
int GetHashForString( CString s )
{
ULONG hash = 0;
int hash = 0;
for( int i=0; i<s.GetLength(); i++ )
{
hash *= 10;
hash += (DWORD)s[i];
}
return hash;
return abs(hash);
}
ULONG GetHashForFile( CString sPath )
int GetHashForFile( CString sPath )
{
ULONG hash = 0;
int hash = 0;
hash += GetHashForString( sPath );
@@ -308,12 +308,12 @@ ULONG GetHashForFile( CString sPath )
if( CFile::GetStatus(sPath, status) )
hash += status.m_mtime.GetHour() * 3600 + status.m_mtime.GetMinute() * 60 + status.m_mtime.GetSecond();
return hash;
return abs(hash);
}
ULONG GetHashForDirectory( CString sDir )
int GetHashForDirectory( CString sDir )
{
ULONG hash = 0;
int hash = 0;
hash += GetHashForFile( sDir );
@@ -325,7 +325,7 @@ ULONG GetHashForDirectory( CString sDir )
hash += GetHashForFile( sFilePath );
}
return hash;
return abs(hash);
}
DWORD GetFileSizeInBytes( const CString &sFilePath )
+3 -3
View File
@@ -97,9 +97,9 @@ CString join(
);
void GetDirListing( CString sPath, CStringArray &AddTo, bool bOnlyDirs=false, bool bReturnPathToo=false );
ULONG GetHashForString( CString s );
ULONG GetHashForFile( CString sPath );
ULONG GetHashForDirectory( CString sDir ); // a hash value that remains the same as long as nothing in the directory has changed
int GetHashForString( CString s );
int GetHashForFile( CString sPath );
int GetHashForDirectory( CString sDir ); // a hash value that remains the same as long as nothing in the directory has changed
bool DoesFileExist( const CString &sPath );
DWORD GetFileSizeInBytes( const CString &sFilePath );
+7 -5
View File
@@ -172,9 +172,10 @@ ScreenEdit::~ScreenEdit()
void ScreenEdit::Update( float fDeltaTime )
{
float fSongBeat, fBPS;
float fPositionSeconds = m_soundMusic.GetPositionSeconds();
m_pSong->GetBeatAndBPSFromElapsedTime( fPositionSeconds, fSongBeat, fBPS );
float fSongBeat, fBPS;
bool bFreeze;
m_pSong->GetBeatAndBPSFromElapsedTime( fPositionSeconds, fSongBeat, fBPS, bFreeze );
if( m_Mode == MODE_RECORD || m_Mode == MODE_PLAY )
{
@@ -409,7 +410,7 @@ void ScreenEdit::InputEdit( const DeviceInput& DeviceI, const InputEventType typ
}
pNotes->SetNoteData( (NoteData*)&m_NoteFieldEdit );
SONGMAN->GetCurrentSong()->Save();
SONGMAN->GetCurrentSong()->SaveToSMFile();
}
break;
case DIK_UP:
@@ -762,8 +763,9 @@ void ScreenEdit::InputRecord( const DeviceInput& DeviceI, const InputEventType t
const float fHoldStartSeconds = m_soundMusic.GetPositionSeconds() - TIME_BEFORE_SLOW_REPEATS * m_soundMusic.GetPlaybackRate();
float fStartBeat, fEndBeat, fThrowAway;
m_pSong->GetBeatAndBPSFromElapsedTime( fHoldStartSeconds, fStartBeat, fThrowAway );
m_pSong->GetBeatAndBPSFromElapsedTime( fHoldEndSeconds, fEndBeat, fThrowAway );
bool bFreeze;
m_pSong->GetBeatAndBPSFromElapsedTime( fHoldStartSeconds, fStartBeat, fThrowAway, bFreeze );
m_pSong->GetBeatAndBPSFromElapsedTime( fHoldEndSeconds, fEndBeat, fThrowAway, bFreeze );
const int iStartIndex = BeatToNoteRow(fStartBeat) - 1;
const int iEndIndex = BeatToNoteRow(fEndBeat);
+7 -6
View File
@@ -348,13 +348,13 @@ void ScreenGameplay::Update( float fDeltaTime )
return;
float fSongBeat, fBPS;
float fPositionSeconds = m_soundMusic.GetPositionSeconds();
m_pCurSong->GetBeatAndBPSFromElapsedTime( fPositionSeconds, fSongBeat, fBPS );
float fSongBeat, fBPS;
bool bFreeze;
m_pCurSong->GetBeatAndBPSFromElapsedTime( fPositionSeconds, fSongBeat, fBPS, bFreeze );
m_Background.SetSongBeat( fSongBeat );
m_Background.SetSongBeat( fSongBeat, bFreeze );
//LOG->WriteLine( "m_fOffsetInBeats = %f, m_fBeatsPerSecond = %f, m_Music.GetPositionSeconds = %f", m_fOffsetInBeats, m_fBeatsPerSecond, m_Music.GetPositionSeconds() );
@@ -477,7 +477,7 @@ void ScreenGameplay::Update( float fDeltaTime )
if( PREFSMAN->m_SongOptions.m_AssistType == SongOptions::ASSIST_TICK )
{
fPositionSeconds += (SOUND->GetPlayLatency()+0.06f) * m_soundMusic.GetPlaybackRate(); // HACK: Add 0.06 seconds to make them play a tiny bit earlier
m_pCurSong->GetBeatAndBPSFromElapsedTime( fPositionSeconds, fSongBeat, fBPS );
m_pCurSong->GetBeatAndBPSFromElapsedTime( fPositionSeconds, fSongBeat, fBPS, bFreeze );
int iRowNow = BeatToNoteRowNotRounded( fSongBeat );
static int iRowLastCrossed = 0;
@@ -539,7 +539,8 @@ void ScreenGameplay::Input( const DeviceInput& DeviceI, const InputEventType typ
//LOG->WriteLine( "ScreenGameplay::Input()" );
float fSongBeat, fBPS;
m_pCurSong->GetBeatAndBPSFromElapsedTime( m_soundMusic.GetPositionSeconds(), fSongBeat, fBPS );
bool bFreeze;
m_pCurSong->GetBeatAndBPSFromElapsedTime( m_soundMusic.GetPositionSeconds(), fSongBeat, fBPS, bFreeze );
// Handle special keys to adjust the offset
+7 -4
View File
@@ -329,22 +329,21 @@ void ScreenSelectMusic::HandleScreenMessage( const ScreenMessage SM )
case SM_PlaySongSample:
PlayMusicSample();
break;
case SM_SongChanged:
AfterMusicChange();
break;
}
}
void ScreenSelectMusic::MenuLeft( const PlayerNumber p, const InputEventType type )
{
m_MusicWheel.PrevMusic();
AfterMusicChange();
}
void ScreenSelectMusic::MenuRight( const PlayerNumber p, const InputEventType type )
{
m_MusicWheel.NextMusic();
AfterMusicChange();
}
void ScreenSelectMusic::MenuStart( const PlayerNumber p )
@@ -471,6 +470,10 @@ void ScreenSelectMusic::AfterMusicChange()
{
if( !GAMEMAN->IsPlayerEnabled( PlayerNumber(p) ) )
continue;
for( int i=0; i<m_arrayNotes.GetSize(); i++ )
if( m_arrayNotes[i]->m_DifficultyClass == PREFSMAN->m_PreferredDifficultyClass[p] )
m_iSelection[p] = i;
m_iSelection[p] = clamp( m_iSelection[p], 0, m_arrayNotes.GetSize() ) ;
}
}
+111 -205
View File
@@ -12,12 +12,13 @@
#include "Notes.h"
#include "RageUtil.h"
#include "Song.h"
#include <math.h> // for fmod
#include "RageLog.h"
#include "IniFile.h"
#include "Song.h"
const int FILE_CACHE_VERSION = 11; // increment this when the cache file format changes
int CompareBPMSegments(const void *arg1, const void *arg2)
@@ -101,7 +102,7 @@ void Song::AddFreezeSegment( FreezeSegment seg )
}
void Song::GetBeatAndBPSFromElapsedTime( float fElapsedTime, float &fBeatOut, float &fBPSOut )
void Song::GetBeatAndBPSFromElapsedTime( float fElapsedTime, float &fBeatOut, float &fBPSOut, bool &bFreezeOut )
{
// LOG->WriteLine( "GetBeatAndBPSFromElapsedTime( fElapsedTime = %f )", fElapsedTime );
// This function is a nightmare. Don't even try to understand it. :-)
@@ -134,7 +135,7 @@ void Song::GetBeatAndBPSFromElapsedTime( float fElapsedTime, float &fBeatOut, fl
if( fElapsedTime > fSecondsInThisSegment )
{
// this BPMSegement is not the current segment
// this BPMSegement is NOT the current segment
fElapsedTime -= fSecondsInThisSegment;
}
else
@@ -158,6 +159,7 @@ void Song::GetBeatAndBPSFromElapsedTime( float fElapsedTime, float &fBeatOut, fl
{
fBeatOut = m_FreezeSegments[j].m_fStartBeat;
fBPSOut = fBPS;
bFreezeOut = true;
return;
}
}
@@ -168,6 +170,7 @@ void Song::GetBeatAndBPSFromElapsedTime( float fElapsedTime, float &fBeatOut, fl
fBeatOut = fBeatEstimate;
fBPSOut = fBPS;
bFreezeOut = false;
return;
}
@@ -183,10 +186,11 @@ float Song::GetElapsedTimeFromBeat( float fBeat )
float fElapsedTimeBestGuess = 100; // seconds
float fSecondsToMove = fElapsedTimeBestGuess/2; // seconds
float fBeatOut, fBPSOut;
bool bFreezeOut;
while( fSecondsToMove > 0.1f )
{
GetBeatAndBPSFromElapsedTime( fElapsedTimeBestGuess, fBeatOut, fBPSOut );
GetBeatAndBPSFromElapsedTime( fElapsedTimeBestGuess, fBeatOut, fBPSOut, bFreezeOut );
if( fBeatOut > fBeat )
fElapsedTimeBestGuess -= fSecondsToMove;
else
@@ -221,8 +225,7 @@ void Song::GetMainAndSubTitlesFromFullTitle( CString sFullTitle, CString &sMainT
CString Song::GetCacheFilePath()
{
ULONG hash = GetHashForString( m_sSongDir );
return ssprintf( "Cache\\%u.song", hash );
return ssprintf( "Cache\\%d", GetHashForString(m_sSongDir) );
}
bool Song::LoadFromSongDir( CString sDir )
@@ -240,10 +243,35 @@ bool Song::LoadFromSongDir( CString sDir )
//
// First look in the cache for this song (without loading NoteData)
//
//if( LoadFromCacheFile(false) )
// return true;
IniFile ini;
ini.SetPath( "Cache\\index.cache" );
if( !ini.ReadFile() )
goto load_without_cache;
int iCacheVersion;
ini.GetValueI( "Cache", "CacheVersion", iCacheVersion );
if( iCacheVersion != FILE_CACHE_VERSION )
{
LOG->WriteLine( "Cache format is out of date. Deleting all cache files" );
CStringArray asCacheFileNames;
GetDirListing( "Cache\\*.*", asCacheFileNames );
for( int i=0; i<asCacheFileNames.GetSize(); i++ )
DeleteFile( "Cache\\" + asCacheFileNames[i] );
goto load_without_cache;
}
int iDirHash;
ini.GetValueI( "Cache", m_sSongDir, iDirHash );
if( GetHashForDirectory(m_sSongDir) == iDirHash ) // this cache is up to date
{
if( !DoesFileExist(GetCacheFilePath()) )
goto load_without_cache;
LoadFromSMFile( GetCacheFilePath(), false ); // don't load NoteData
LOG->WriteLine( "Loading '%s' from cache file '%s'.", m_sSongDir, GetCacheFilePath() );
return true;
}
load_without_cache:
//
// There was no entry in the cache for this song.
// Let's load it from a file, then write a cache entry.
@@ -256,23 +284,23 @@ bool Song::LoadFromSongDir( CString sDir )
GetDirListing( sDir + CString("*.dwi"), arrayDWIFileNames );
int iNumDWIFiles = arrayDWIFileNames.GetSize();
CStringArray arraySongFileNames;
GetDirListing( sDir + CString("*.song"), arraySongFileNames );
int iNumSongFiles = arraySongFileNames.GetSize();
CStringArray arraySMFileNames;
GetDirListing( sDir + CString("*.sm"), arraySMFileNames );
int iNumSMFiles = arraySMFileNames.GetSize();
if( iNumSongFiles > 1 )
throw RageException( "There is more than one .song file in '%s'. There should be only one!", sDir );
if( iNumSMFiles > 1 )
throw RageException( "There is more than one SM file in '%s'. There should be only one!", sDir );
else if( iNumDWIFiles > 1 )
throw RageException( "There is more than one DWI file in '%s'. There should be only one!", sDir );
else if( iNumSongFiles == 1 )
LoadFromSMDir( sDir );
else if( iNumSMFiles == 1 )
LoadFromSMFile( sDir + arraySMFileNames[0], true ); // do load note data
else if( iNumDWIFiles == 1 )
LoadFromDWIFile( sDir + arrayDWIFileNames[0] );
else if( iNumBMSFiles > 0 )
LoadFromBMSDir( sDir );
else
throw RageException( "Couldn't find any .song, BMS, or DWI files in '%s'. This is not a valid song directory.", sDir );
throw RageException( "Couldn't find any SM, BMS, or DWI files in '%s'. This is not a valid song directory.", sDir );
TidyUpData();
@@ -280,8 +308,8 @@ bool Song::LoadFromSongDir( CString sDir )
// In order to save memory, we're going to save the file back to the cache,
// then unload all the large NoteData.
//
//SaveToCacheFile();
//LoadFromCacheFile( false );
SaveToCacheFile();
LoadFromSMFile( GetCacheFilePath(), false ); // don't load NoteData
return true;
}
@@ -756,47 +784,19 @@ bool Song::LoadFromDWIFile( CString sPath )
}
bool Song::LoadFromSMDir( CString sDir )
bool Song::LoadFromSMFile( CString sPath, bool bLoadNoteData )
{
LOG->WriteLine( "Song::LoadFromSMDir(%s)", sDir );
LOG->WriteLine( "Song::LoadFromSMDir(%s, %d)", sPath, bLoadNoteData );
int i;
// make sure there is a trailing '\\' at the end of sDir
if( sDir.Right(1) != "\\" )
sDir += "\\";
// save song dir
m_sSongDir = sDir;
// get group name
CStringArray sDirectoryParts;
split( m_sSongDir, "\\", sDirectoryParts, true );
m_sGroupName = sDirectoryParts[1];
CStringArray arraySongFileNames;
GetDirListing( sDir + "*.song", arraySongFileNames );
if( arraySongFileNames.GetSize() == 0 )
throw RageException( "Couldn't find any SM Song files in '%s'", sDir );
// Load the Song info from the first BMS file. Silly BMS duplicates the song info in every
// file. So, we read the song data from only the first BMS file and assume that the info
// is identical for every BMS file in the directory.
m_sSongFile = arraySongFileNames[0];
CStringArray arrayNotesFileNames;
GetDirListing( sDir + CString("*.notes"), arrayNotesFileNames );
// load the Notes from the rest of the BMS files
for( i=0; i<arrayNotesFileNames.GetSize(); i++ )
{
Notes* pNewNotes = new Notes;
pNewNotes->LoadFromNotesFile( m_sSongDir + arrayNotesFileNames[i] );
m_arrayNotes.Add( pNewNotes );
}
m_sSongFile = sPath;
CStdioFile file;
@@ -846,7 +846,7 @@ bool Song::LoadFromSMDir( CString sDir )
if( sValueName == "#TITLE" )
GetMainAndSubTitlesFromFullTitle( arrayValueTokens[1], m_sMainTitle, m_sSubTitle );
if( sValueName == "#MAINTITLE" )
if( sValueName == "#TITLE" )
m_sMainTitle = arrayValueTokens[1];
if( sValueName == "#SUBTITLE" )
@@ -930,6 +930,24 @@ bool Song::LoadFromSMDir( CString sDir )
}
}
else if( sValueName == "#NOTES" )
{
Notes* pNewNotes = new Notes;
if( arrayValueTokens.GetSize() != 7 )
throw RageException( "The song file '%s' is has an incorrect number of parameters in a #NOTES tag.", GetSongFilePath() );
pNewNotes->LoadFromSMTokens(
arrayValueTokens[0],
arrayValueTokens[1],
arrayValueTokens[2],
arrayValueTokens[3],
arrayValueTokens[4],
arrayValueTokens[5],
arrayValueTokens[6],
bLoadNoteData );
m_arrayNotes.Add( pNewNotes );
}
else
LOG->WriteLine( "Unexpected value named '%s'", sValueName );
}
@@ -1068,139 +1086,30 @@ void Song::GetNotesThatMatch( NotesType nt, CArray<Notes*, Notes*>& arrayAddTo )
arrayAddTo.Add( m_arrayNotes[i] );
}
const int FILE_CACHE_VERSION = 10; // increment this when the cache file format changes
void Song::SaveToCacheFile()
{
LOG->WriteLine( "Song::SaveToCacheFile()" );
int i;
CString sCacheFilePath = GetCacheFilePath();
//
// First look in the cache for this song (without loading NoteData)
//
IniFile ini;
ini.SetPath( "Cache\\index.cache" );
ini.ReadFile(); // don't care if this fails
FILE* file = fopen( sCacheFilePath, "w" );
ASSERT( file != NULL );
if( file == NULL )
return;
fprintf( file, "%d\n", FILE_CACHE_VERSION );
fprintf( file, "%u\n", GetHashForDirectory(m_sSongDir) );
WriteStringToFile( file, m_sSongDir );
WriteStringToFile( file, m_sSongFile );
WriteStringToFile( file, m_sGroupName );
WriteStringToFile( file, m_sMainTitle );
WriteStringToFile( file, m_sSubTitle );
WriteStringToFile( file, m_sArtist );
WriteStringToFile( file, m_sCredit );
fprintf( file, "%f\n", m_fOffsetInSeconds );
WriteStringToFile( file, m_sMusicFile );
fprintf( file, "%d\n", m_iMusicBytes );
fprintf( file, "%f\n", m_fMusicLengthSeconds );
fprintf( file, "%f\n", m_fMusicSampleStartSeconds );
WriteStringToFile( file, m_sBannerFile );
WriteStringToFile( file, m_sBackgroundFile );
WriteStringToFile( file, m_sBackgroundMovieFile );
WriteStringToFile( file, m_sCDTitleFile );
fprintf( file, "%d\n", m_BPMSegments.GetSize() );
for( i=0; i<m_BPMSegments.GetSize(); i++ )
fprintf( file, "%f,%f\n", m_BPMSegments[i].m_fStartBeat, m_BPMSegments[i].m_fBPM );
fprintf( file, "%d\n", m_FreezeSegments.GetSize() );
for( i=0; i<m_FreezeSegments.GetSize(); i++ )
fprintf( file, "%f,%f\n", m_FreezeSegments[i].m_fStartBeat, m_FreezeSegments[i].m_fFreezeSeconds );
fprintf( file, "%d\n", m_arrayNotes.GetSize() );
for( i=0; i<m_arrayNotes.GetSize(); i++ )
m_arrayNotes[i]->WriteToCacheFile( file );
fclose( file );
}
bool Song::LoadFromCacheFile( bool bLoadNoteData )
{
LOG->WriteLine( "Song::LoadFromCacheFile( %i )", bLoadNoteData );
int i;
CString sCacheFilePath = GetCacheFilePath();
LOG->WriteLine( "cache file is '%s'.", sCacheFilePath );
FILE* file = fopen( sCacheFilePath, "r" );
if( file == NULL )
return false;
int iCacheVersion;
fscanf( file, "%d\n", &iCacheVersion );
if( iCacheVersion != FILE_CACHE_VERSION )
{
LOG->WriteLine( "Cache file versions don't match '%s'.", sCacheFilePath );
fclose( file );
DeleteCacheFile();
return false;
}
ULONG hash;
fscanf( file, "%u\n", &hash );
if( hash != GetHashForDirectory(m_sSongDir) )
{
LOG->WriteLine( "Cache file is out of date.", sCacheFilePath );
fclose( file );
return false;
}
ReadStringFromFile( file, m_sSongDir );
ReadStringFromFile( file, m_sSongFile );
ReadStringFromFile( file, m_sGroupName );
ReadStringFromFile( file, m_sMainTitle );
ReadStringFromFile( file, m_sSubTitle );
ReadStringFromFile( file, m_sArtist );
ReadStringFromFile( file, m_sCredit );
fscanf( file, "%f\n", &m_fOffsetInSeconds );
ReadStringFromFile( file, m_sMusicFile );
fscanf( file, "%d\n", &m_iMusicBytes );
fscanf( file, "%f\n", &m_fMusicLengthSeconds );
fscanf( file, "%f\n", &m_fMusicSampleStartSeconds );
ReadStringFromFile( file, m_sBannerFile );
ReadStringFromFile( file, m_sBackgroundFile );
ReadStringFromFile( file, m_sBackgroundMovieFile );
ReadStringFromFile( file, m_sCDTitleFile );
int iNumBPMSegments;
fscanf( file, "%d\n", &iNumBPMSegments );
m_BPMSegments.SetSize( iNumBPMSegments );
for( i=0; i<iNumBPMSegments; i++ )
fscanf( file, "%f,%f\n", &m_BPMSegments[i].m_fStartBeat, &m_BPMSegments[i].m_fBPM );
int iNumFreezeSegments;
fscanf( file, "%d\n", &iNumFreezeSegments );
m_FreezeSegments.SetSize( iNumFreezeSegments );
for( i=0; i<iNumFreezeSegments; i++ )
fscanf( file, "%f,%f\n", &m_FreezeSegments[i].m_fStartBeat, &m_FreezeSegments[i].m_fFreezeSeconds );
int iNumNotes;
fscanf( file, "%d\n", &iNumNotes );
m_arrayNotes.SetSize( iNumNotes );
for( i=0; i<iNumNotes; i++ )
m_arrayNotes[i]->ReadFromCacheFile( file, bLoadNoteData );
fclose( file );
return true;
}
void Song::DeleteCacheFile()
{
DeleteFile( GetCacheFilePath() );
ini.SetValueI( "Cache", "CacheVersion", FILE_CACHE_VERSION );
ini.SetValueI( "Cache", m_sSongDir, GetHashForDirectory(m_sSongDir) );
ini.WriteFile();
SaveToSMFile( GetCacheFilePath() );
}
void Song::SaveToSMDir()
void Song::SaveToSMFile( CString sPath )
{
LOG->WriteLine( "Song::SaveToSMDir()" );
if( sPath == "" )
sPath = GetSongFilePath();
LOG->WriteLine( "Song::SaveToSMDir('%s')", sPath );
int i;
//
@@ -1217,56 +1126,53 @@ void Song::SaveToSMDir()
MoveFile( sOldPath, sNewPath );
}
CStdioFile file;
if( !file.Open( GetSongFilePath(), CFile::modeWrite | CFile::modeCreate ) )
throw RageException( "Error opening song file '%s' for writing.", GetSongFilePath() );
FILE* fp = fopen( sPath, "w" );
if( fp == NULL )
throw RageException( "Error opening song file '%s' for writing.", sPath );
file.WriteString( ssprintf("#MAINTITLE:%s;\n", m_sMainTitle) );
file.WriteString( ssprintf("#SUBTITLE:%s;\n", m_sSubTitle) );
file.WriteString( ssprintf("#ARTIST:%s;\n", m_sArtist) );
file.WriteString( ssprintf("#CREDIT:%s;\n", m_sCredit) );
file.WriteString( ssprintf("#BANNER:%s;\n", m_sBannerFile) );
file.WriteString( ssprintf("#BACKGROUND:%s;\n", m_sBackgroundFile) );
file.WriteString( ssprintf("#BACKGROUNDMOVIE:%s;\n", m_sBackgroundMovieFile) );
file.WriteString( ssprintf("#CDTITLE:%s;\n", m_sCDTitleFile) );
file.WriteString( ssprintf("#MUSIC:%s;\n", m_sMusicFile) );
file.WriteString( ssprintf("#MUSICBYTES:%u;\n", m_iMusicBytes) );
file.WriteString( ssprintf("#OFFSET:%f;\n", m_fOffsetInSeconds) );
file.WriteString( ssprintf("#SAMPLESTART:%f;\n", m_fMusicSampleStartSeconds) );
file.WriteString( ssprintf("#SAMPLELENGTH:%f;\n", m_fMusicSampleLengthSeconds) );
fprintf( fp, "#TITLE:%s;\n", m_sMainTitle );
fprintf( fp, "#SUBTITLE:%s;\n", m_sSubTitle );
fprintf( fp, "#ARTIST:%s;\n", m_sArtist );
fprintf( fp, "#CREDIT:%s;\n", m_sCredit );
fprintf( fp, "#BANNER:%s;\n", m_sBannerFile );
fprintf( fp, "#BACKGROUND:%s;\n", m_sBackgroundFile );
fprintf( fp, "#BACKGROUNDMOVIE:%s;\n", m_sBackgroundMovieFile );
fprintf( fp, "#CDTITLE:%s;\n", m_sCDTitleFile );
fprintf( fp, "#MUSIC:%s;\n", m_sMusicFile );
fprintf( fp, "#MUSICBYTES:%u;\n", m_iMusicBytes );
fprintf( fp, "#OFFSET:%.2f;\n", m_fOffsetInSeconds );
fprintf( fp, "#SAMPLESTART:%.2f;\n", m_fMusicSampleStartSeconds );
fprintf( fp, "#SAMPLELENGTH:%.2f;\n", m_fMusicSampleLengthSeconds );
file.WriteString( "#FREEZES:" );
fprintf( fp, "#FREEZES:" );
for( i=0; i<m_FreezeSegments.GetSize(); i++ )
{
FreezeSegment &fs = m_FreezeSegments[i];
file.WriteString( ssprintf("%f=%f", fs.m_fStartBeat, fs.m_fFreezeSeconds) );
fprintf( fp, "%.2f=%.2f", fs.m_fStartBeat, fs.m_fFreezeSeconds );
if( i != m_FreezeSegments.GetSize()-1 )
file.WriteString( "," );
fprintf( fp, "," );
}
file.WriteString( ";\n" );
fprintf( fp, ";\n" );
file.WriteString( "#BPMS:" );
fprintf( fp, "#BPMS:" );
for( i=0; i<m_BPMSegments.GetSize(); i++ )
{
BPMSegment &bs = m_BPMSegments[i];
file.WriteString( ssprintf("%f=%f", bs.m_fStartBeat, bs.m_fBPM) );
fprintf( fp, "%.2f=%.2f", bs.m_fStartBeat, bs.m_fBPM );
if( i != m_BPMSegments.GetSize()-1 )
file.WriteString( "," );
fprintf( fp, "," );
}
file.WriteString( ";\n" );
fprintf( fp, ";\n" );
file.Close();
//
// Save all Notes for this file
//
for( i=0; i<m_arrayNotes.GetSize(); i++ )
{
m_arrayNotes[i]->SaveToSMDir( m_sSongDir );
}
m_arrayNotes[i]->WriteSMNotesTag( fp );
fclose( fp );
}
Grade Song::GetGradeForDifficultyClass( NotesType nt, DifficultyClass dc )
+7 -15
View File
@@ -3,20 +3,17 @@
-----------------------------------------------------------------------------
Class: Song
Desc: Holds data about a piece of music that can be played by one or more
Games.
Desc: Holds data about a song that is common to several Notes.
Copyright (c) 2001-2002 by the person(s) listed below. All rights reserved.
Chris Danford
-----------------------------------------------------------------------------
*/
#include "Notes.h"
#include "GameConstantsAndTypes.h"
#include "RageUtil.h"
//enum DanceStyle; // why is this needed?
struct BPMSegment
@@ -43,21 +40,17 @@ public:
~Song();
bool LoadFromSongDir( CString sDir ); // calls one of the loads below
void Save() { SaveToSMDir(); SaveToCacheFile(); };
void SetChangedSinceLastSave() { m_bChangedSinceSave = true; }
bool LoadFromCacheFile( bool bLoadNoteData );
protected:
bool LoadFromDWIFile( CString sPath );
bool LoadFromBMSDir( CString sDir );
bool LoadFromSMDir( CString sDir );
bool LoadFromSMFile( CString sPath, bool bLoadNoteData );
void TidyUpData(); // call after loading to clean up invalid data
void SaveToSMDir(); // saves to StepMania song and notes files
void SaveToCacheFile(); // saves to cache file
void SaveToSMFile( CString sPath = "" ); // no path means save in Song dir
void DeleteCacheFile();
CString GetCacheFilePath();
void SaveToCacheFile();
public:
@@ -66,7 +59,6 @@ public:
CString m_sGroupName;
CString GetSongFilePath() {return m_sSongDir+m_sSongFile; };
CString GetCacheFilePath();
bool m_bChangedSinceSave;
@@ -127,7 +119,7 @@ public:
break;
return m_BPMSegments[i].m_fBPM;
};
void GetBeatAndBPSFromElapsedTime( float fElapsedTime, float &fBeatOut, float &fBPSOut );
void GetBeatAndBPSFromElapsedTime( float fElapsedTime, float &fBeatOut, float &fBPSOut, bool &bFreezeOut );
float GetElapsedTimeFromBeat( float fBeat );