diff --git a/stepmania/src/NoteData.cpp b/stepmania/src/NoteData.cpp index d6f5fc9ea4..5fea632726 100644 --- a/stepmania/src/NoteData.cpp +++ b/stepmania/src/NoteData.cpp @@ -92,7 +92,18 @@ void NoteData::CopyRange( const NoteData* pFrom, int iFromIndexBegin, int iFromI while( f<=iFromIndexEnd ) { for( int c=0; cm_TapNotes[c]; m_HoldNotes = pFrom->m_HoldNotes; + m_AttackMap = pFrom->m_AttackMap; } void NoteData::AddHoldNote( HoldNote add ) @@ -174,7 +186,7 @@ void NoteData::RemoveHoldNote( int iHoldIndex ) m_HoldNotes.erase(m_HoldNotes.begin()+iHoldIndex, m_HoldNotes.begin()+iHoldIndex+1); } -void NoteData::AddAttackNote( int track, int row, Attack attack ) +void NoteData::SetTapAttackNote( int track, int row, Attack attack ) { PruneUnusedAttacksFromMap(); diff --git a/stepmania/src/NoteData.h b/stepmania/src/NoteData.h index b1f389bd19..7237934ed6 100644 --- a/stepmania/src/NoteData.h +++ b/stepmania/src/NoteData.h @@ -35,6 +35,7 @@ class NoteData void LoadOverlapped( const NoteData* pOriginal, int iNewNumTracks ); public: + /* Set up to hold the data in From; same number of tracks, same * divisor. Doesn't allocate or copy anything. */ void Config( const NoteData &From ); @@ -46,6 +47,10 @@ public: int GetNumTracks() const; void SetNumTracks( int iNewNumTracks ); + // TODO: Think of better accessors + const map& GetAttackMap() const { return m_AttackMap; } + map& GetAttackMap() { return m_AttackMap; } + /* Return the note at the given track and row. Row may be out of * range; pretend the song goes on with TAP_EMPTYs indefinitely. */ inline TapNote GetTapNote(unsigned track, int row) const @@ -144,7 +149,7 @@ public: HoldNote &GetHoldNote( int index ) { return m_HoldNotes[index]; } const HoldNote &GetHoldNote( int index ) const { return m_HoldNotes[index]; } - void AddAttackNote( int track, int row, Attack attack ); + void SetTapAttackNote( int track, int row, Attack attack ); void PruneUnusedAttacksFromMap(); // slow const Attack& GetAttackAt( int track, int row ); // remove Attacks with SetTapNote(TAP_EMPTY) diff --git a/stepmania/src/NoteDataUtil.cpp b/stepmania/src/NoteDataUtil.cpp index 31abe85f0a..cd8cd7673a 100644 --- a/stepmania/src/NoteDataUtil.cpp +++ b/stepmania/src/NoteDataUtil.cpp @@ -52,132 +52,218 @@ NoteType NoteDataUtil::GetSmallestNoteTypeForMeasure( const NoteData &n, int iMe return nt; } -void NoteDataUtil::LoadFromSMNoteDataString( NoteData &out, CString sSMNoteData ) +void NoteDataUtil::LoadFromSMNoteDataString( NoteData &out, CString sSMNoteData, CString sSMAttackData ) { - /* Clear notes, but keep the same number of tracks. */ - int iNumTracks = out.GetNumTracks(); - out.Init(); - out.SetNumTracks( iNumTracks ); - - // strip comments out of sSMNoteData - while( sSMNoteData.Find("//") != -1 ) { - int iIndexCommentStart = sSMNoteData.Find("//"); - int iIndexCommentEnd = sSMNoteData.Find("\n", iIndexCommentStart); - if( iIndexCommentEnd == -1 ) // comment doesn't have an end? - sSMNoteData.erase( iIndexCommentStart, 2 ); - else - sSMNoteData.erase( iIndexCommentStart, iIndexCommentEnd-iIndexCommentStart ); - } + // + // Load note data + // - CStringArray asMeasures; - split( sSMNoteData, ",", asMeasures, true ); // ignore empty is important - for( unsigned m=0; m= 'a' && sMeasureLine[c] <= 'z' ) + { + t = sMeasureLine[c]; + } + else + { + /* Invalid data. We don't want to assert, since there might + * simply be invalid data in an .SM, and we don't want to die + * due to invalid data. We should probably check for this when + * we load SM data for the first time ... */ + // ASSERT(0); + t = TAP_EMPTY; + } + break; + } + out.SetTapNote(c, iIndex, t); } - out.SetTapNote(c, iIndex, t); } } + out.Convert2sAnd3sToHoldNotes(); + } + + { + // + // Load attack data + // + CStringArray asLines; + split( sSMAttackData, ",", asLines, true ); + + for( int i=0; i::const_iterator iter = in_.GetAttackMap().begin(); + iter != in_.GetAttackMap().end(); + iter++ ) + { + TapNote tn = iter->first; + Attack attack = iter->second; + attack.sModifier.Replace( ',', '.' ); // comma is the map item separator + + asLines.push_back( ssprintf("%c=%s=%f,\n", tn, attack.sModifier.c_str(), attack.fSecsRemaining) ); } - sRet.append(1, ','); + attacks_out = join( ",", asLines ); } } diff --git a/stepmania/src/NoteDataUtil.h b/stepmania/src/NoteDataUtil.h index c465a572dd..83e2dba2cd 100644 --- a/stepmania/src/NoteDataUtil.h +++ b/stepmania/src/NoteDataUtil.h @@ -27,8 +27,8 @@ struct PlayerOptions; namespace NoteDataUtil { NoteType GetSmallestNoteTypeForMeasure( const NoteData &n, int iMeasureIndex ); - void LoadFromSMNoteDataString( NoteData &out, CString sSMNoteData ); - void GetSMNoteDataString( const NoteData &in, CString &out ); + void LoadFromSMNoteDataString( NoteData &out, CString sSMNoteData, CString sSMAttackData ); + void GetSMNoteDataString( const NoteData &in, CString ¬es_out, CString &attacks_out ); float GetStreamRadarValue( const NoteData &in, float fSongSeconds ); float GetVoltageRadarValue( const NoteData &in, float fSongSeconds ); diff --git a/stepmania/src/NotesLoaderSM.cpp b/stepmania/src/NotesLoaderSM.cpp index 2f6eb91c50..0742e3c3c7 100644 --- a/stepmania/src/NotesLoaderSM.cpp +++ b/stepmania/src/NotesLoaderSM.cpp @@ -14,6 +14,7 @@ void SMLoader::LoadFromSMTokens( CString sMeter, CString sRadarValues, CString sNoteData, + CString sAttackData, Steps &out ) { @@ -47,7 +48,7 @@ void SMLoader::LoadFromSMTokens( for( int r=0; rTrace( "The song file '%s' is has %d fields in a #NOTES tag, but should have %d.", sPath.c_str(), iNumParams, 7 ); + LOG->Trace( "The song file '%s' is has %d fields in a #NOTES tag, but should have at least %d.", sPath.c_str(), iNumParams, 7 ); continue; } LoadFromSMTokens( - sParams[1], sParams[2], sParams[3], sParams[4], sParams[5], sParams[6], + sParams[1], sParams[2], sParams[3], sParams[4], sParams[5], sParams[6], (iNumParams>=8)?sParams[7]:"", *pNewNotes); } else diff --git a/stepmania/src/NotesLoaderSM.h b/stepmania/src/NotesLoaderSM.h index a46b9b342c..c1776c1138 100644 --- a/stepmania/src/NotesLoaderSM.h +++ b/stepmania/src/NotesLoaderSM.h @@ -13,6 +13,7 @@ class SMLoader: public NotesLoader { CString sMeter, CString sRadarValues, CString sNoteData, + CString sAttackData, Steps &out); bool FromCache; diff --git a/stepmania/src/NotesWriterSM.cpp b/stepmania/src/NotesWriterSM.cpp index bf73c033e2..9cd0ff64fb 100644 --- a/stepmania/src/NotesWriterSM.cpp +++ b/stepmania/src/NotesWriterSM.cpp @@ -109,7 +109,16 @@ void NotesWriterSM::WriteSMNotesTag( const Steps &in, FILE* fp ) * newline and they'll accumulate. */ fprintf( fp, " %s:", join(",",asRadarValues).c_str() ); - fprintf( fp, "%s;\n", in.GetSMNoteData().c_str() ); + CString sNoteData; + CString sAttackData; + in.GetSMNoteData( sNoteData, sAttackData ); + + fprintf( fp, "%s", sNoteData.c_str() ); + + if( sAttackData.empty() ) + fprintf( fp, ";\n" ); + else + fprintf( fp, ":\n%s;\n", sAttackData.c_str() ); } bool NotesWriterSM::Write(CString sPath, const Song &out, bool bSavingCache) diff --git a/stepmania/src/ScreenEdit.cpp b/stepmania/src/ScreenEdit.cpp index 361b20aaa1..376f4b0dc5 100644 --- a/stepmania/src/ScreenEdit.cpp +++ b/stepmania/src/ScreenEdit.cpp @@ -1282,7 +1282,7 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM ) attack.fSecsRemaining = g_fLastInsertAttackDurationSeconds; attack.sModifier = sMods; - m_NoteFieldEdit.AddAttackNote( g_iLastInsertAttackTrack, iSongIndex, attack ); + m_NoteFieldEdit.SetTapAttackNote( g_iLastInsertAttackTrack, iSongIndex, attack ); GAMESTATE->RestoreSelectedOptions(); // restore the edit and playback options } break; diff --git a/stepmania/src/Song.cpp b/stepmania/src/Song.cpp index a57126d446..5d08e0e42e 100644 --- a/stepmania/src/Song.cpp +++ b/stepmania/src/Song.cpp @@ -550,7 +550,11 @@ static void DeleteDuplicateSteps( Song *song, vector &vSteps ) if( s1->GetMeter() != s2->GetMeter() ) continue; /* Compare, ignoring whitespace. */ - if( RemoveInitialWhitespace(s1->GetSMNoteData()) != RemoveInitialWhitespace(s2->GetSMNoteData()) ) + CString sSMNoteData1, sSMAttackData1; + s1->GetSMNoteData( sSMNoteData1, sSMAttackData1 ); + CString sSMNoteData2, sSMAttackData2; + s2->GetSMNoteData( sSMNoteData2, sSMAttackData2 ); + if( RemoveInitialWhitespace(sSMNoteData1) != RemoveInitialWhitespace(sSMNoteData2) ) continue; LOG->Trace("Removed %p duplicate steps in song \"%s\" with description \"%s\" and meter \"%i\"", diff --git a/stepmania/src/Steps.cpp b/stepmania/src/Steps.cpp index 0011951685..69df75c5ca 100644 --- a/stepmania/src/Steps.cpp +++ b/stepmania/src/Steps.cpp @@ -79,27 +79,35 @@ void Steps::GetNoteData( NoteData* pNoteDataOut ) const } } -void Steps::SetSMNoteData( const CString &out ) +void Steps::SetSMNoteData( const CString ¬es_comp_, const CString &attacks_comp_ ) { delete notes; notes = NULL; if(!notes_comp) - notes_comp = new CString; + notes_comp = new CompressedNoteData; - *notes_comp = out; + notes_comp->notes = notes_comp_; + notes_comp->attacks = attacks_comp_; } -CString Steps::GetSMNoteData() const +void Steps::GetSMNoteData( CString ¬es_comp_out, CString &attacks_comp_out ) const { if(!notes_comp) { - if(!notes) return ""; /* no data is no data */ - notes_comp = new CString; - NoteDataUtil::GetSMNoteDataString( *notes, *notes_comp ); + if(!notes) + { + /* no data is no data */ + notes_comp_out = attacks_comp_out = ""; + return; + } + + notes_comp = new CompressedNoteData; + NoteDataUtil::GetSMNoteDataString( *notes, notes_comp->notes, notes_comp->attacks ); } - return *notes_comp; + notes_comp_out = notes_comp->notes; + attacks_comp_out = notes_comp->attacks; } void Steps::TidyUpData() @@ -177,7 +185,7 @@ void Steps::Decompress() const notes = new NoteData; notes->SetNumTracks( GameManager::NotesTypeToNumTracks(m_StepsType) ); - NoteDataUtil::LoadFromSMNoteDataString(*notes, *notes_comp); + NoteDataUtil::LoadFromSMNoteDataString(*notes, notes_comp->notes, notes_comp->attacks ); } } @@ -186,8 +194,8 @@ void Steps::Compress() const if(!notes_comp) { if(!notes) return; /* no data is no data */ - notes_comp = new CString; - NoteDataUtil::GetSMNoteDataString( *notes, *notes_comp ); + notes_comp = new CompressedNoteData; + NoteDataUtil::GetSMNoteDataString( *notes, notes_comp->notes, notes_comp->attacks ); } delete notes; diff --git a/stepmania/src/Steps.h b/stepmania/src/Steps.h index 539a718a61..c065668a26 100644 --- a/stepmania/src/Steps.h +++ b/stepmania/src/Steps.h @@ -45,12 +45,12 @@ public: bool IsAutogen() const; // Was created by autogen? - StepsType m_StepsType; + StepsType m_StepsType; - void GetNoteData( NoteData* pNoteDataOut ) const; - void SetNoteData( const NoteData* pNewNoteData ); - void SetSMNoteData( const CString &out ); - CString GetSMNoteData() const; + void GetNoteData( NoteData* pNoteDataOut ) const; + void SetNoteData( const NoteData* pNewNoteData ); + void SetSMNoteData( const CString ¬es_comp, const CString &attacks_comp ); + void GetSMNoteData( CString ¬es_comp_out, CString &attacks_comp_out ) const; struct MemCardData @@ -115,7 +115,11 @@ protected: * Call Compress() to force us to only have notes_comp; otherwise, creation of * these is transparent. */ mutable NoteData *notes; - mutable CString *notes_comp; + struct CompressedNoteData + { + CString notes, attacks; + }; + mutable CompressedNoteData *notes_comp; const Steps *Real() const;