From f8118fea49bd87db457d9e86d7bc6afabe75e9bf Mon Sep 17 00:00:00 2001 From: Chris Danford Date: Sun, 30 Jun 2002 23:19:33 +0000 Subject: [PATCH] no message --- stepmania/src/Background.cpp | 2 +- stepmania/src/Background.h | 3 +- stepmania/src/GameConstantsAndTypes.h | 15 +- stepmania/src/LifeMeterBar.cpp | 4 +- stepmania/src/MusicWheel.cpp | 39 +++- stepmania/src/MusicWheel.h | 8 +- stepmania/src/NoteData.cpp | 128 ----------- stepmania/src/NoteData.h | 11 - stepmania/src/Notes.cpp | 279 ++++++++++++----------- stepmania/src/Notes.h | 34 +-- stepmania/src/RageUtil.cpp | 18 +- stepmania/src/RageUtil.h | 6 +- stepmania/src/ScreenEdit.cpp | 12 +- stepmania/src/ScreenGameplay.cpp | 13 +- stepmania/src/ScreenSelectMusic.cpp | 11 +- stepmania/src/Song.cpp | 316 +++++++++----------------- stepmania/src/song.h | 22 +- 17 files changed, 370 insertions(+), 551 deletions(-) diff --git a/stepmania/src/Background.cpp b/stepmania/src/Background.cpp index 9866d0d9cd..bf629c9b20 100644 --- a/stepmania/src/Background.cpp +++ b/stepmania/src/Background.cpp @@ -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 ); diff --git a/stepmania/src/Background.h b/stepmania/src/Background.h index ea2fc58b4c..9d2ea46ac7 100644 --- a/stepmania/src/Background.h +++ b/stepmania/src/Background.h @@ -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; }; diff --git a/stepmania/src/GameConstantsAndTypes.h b/stepmania/src/GameConstantsAndTypes.h index e45dc3c626..8eb0c1f884 100644 --- a/stepmania/src/GameConstantsAndTypes.h +++ b/stepmania/src/GameConstantsAndTypes.h @@ -154,6 +154,18 @@ inline CString DifficultyClassToString( DifficultyClass dc ) } } +inline DifficultyClass StringToDifficultyClass( CString sDC ) +{ + for( int i=0; i 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 &arrayWheelItemDatas, SongSortOrder so ) +void MusicWheel::BuildWheelItemDatas( CArray &arrayWheelItemDatas, SongSortOrder so, bool bRoulette ) { int i; @@ -469,6 +480,9 @@ void MusicWheel::BuildWheelItemDatas( CArray &arr case SORT_TITLE: bUseSections = true; break; default: ASSERT( false ); } + if( bRoulette ) + bUseSections = false; + if( bUseSections ) { @@ -556,7 +570,7 @@ void MusicWheel::BuildWheelItemDatas( CArray &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: diff --git a/stepmania/src/MusicWheel.h b/stepmania/src/MusicWheel.h index 7560c81670..9e526bcb2c 100644 --- a/stepmania/src/MusicWheel.h +++ b/stepmania/src/MusicWheel.h @@ -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 &arrayWheelItems, SongSortOrder so ); + void BuildWheelItemDatas( CArray &arrayWheelItems, SongSortOrder so, bool bRoulette = false ); void RebuildWheelItemDisplays(); void SwitchSortOrder(); diff --git a/stepmania/src/NoteData.cpp b/stepmania/src/NoteData.cpp index bb309199cf..9057c253f9 100644 --- a/stepmania/src/NoteData.cpp +++ b/stepmania/src/NoteData.cpp @@ -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; ntWriteLine( "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; iWriteToCacheFile( 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; iReadFromCacheFile( 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 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; im_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; cm_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; rConvertHoldNotesTo2sAnd3s(); + + 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; ntSetFromMeasureStrings( 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; cm_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; iGetBeatAndBPSFromElapsedTime( 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); diff --git a/stepmania/src/ScreenGameplay.cpp b/stepmania/src/ScreenGameplay.cpp index eeb395b058..ed12a77518 100644 --- a/stepmania/src/ScreenGameplay.cpp +++ b/stepmania/src/ScreenGameplay.cpp @@ -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 diff --git a/stepmania/src/ScreenSelectMusic.cpp b/stepmania/src/ScreenSelectMusic.cpp index 7730cd3891..85898c857f 100644 --- a/stepmania/src/ScreenSelectMusic.cpp +++ b/stepmania/src/ScreenSelectMusic.cpp @@ -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; im_DifficultyClass == PREFSMAN->m_PreferredDifficultyClass[p] ) + m_iSelection[p] = i; + m_iSelection[p] = clamp( m_iSelection[p], 0, m_arrayNotes.GetSize() ) ; } } diff --git a/stepmania/src/Song.cpp b/stepmania/src/Song.cpp index b3bab04437..7f16a329db 100644 --- a/stepmania/src/Song.cpp +++ b/stepmania/src/Song.cpp @@ -12,12 +12,13 @@ #include "Notes.h" #include "RageUtil.h" - -#include "Song.h" #include // 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; iWriteLine( "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; iLoadFromNotesFile( 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& 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; iWriteToCacheFile( 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; iReadFromCacheFile( 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; iSaveToSMDir( m_sSongDir ); - } + m_arrayNotes[i]->WriteSMNotesTag( fp ); + fclose( fp ); } Grade Song::GetGradeForDifficultyClass( NotesType nt, DifficultyClass dc ) diff --git a/stepmania/src/song.h b/stepmania/src/song.h index 4198abf965..83aba0c0bb 100644 --- a/stepmania/src/song.h +++ b/stepmania/src/song.h @@ -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 );