diff --git a/Docs/Changelog_SSCformat.txt b/Docs/Changelog_SSCformat.txt index ad66ffe058..721673f31d 100644 --- a/Docs/Changelog_SSCformat.txt +++ b/Docs/Changelog_SSCformat.txt @@ -9,6 +9,11 @@ change to JSON, but it is unsure if this will be done. Implement .ssc at your own risk. ________________________________________________________________________________ +[v0.76] - Wolfman2000 +* Expand the #COMBOS tag to allow for Miss Combos. Anyone that is crazy enough + to put in a 51 miss combo in their tags should be...oh wait: it's already + been done. + [v0.75] - Wolfman2000 * Add Step based #DISPLAYBPM for those songs that have...very varied syncing. diff --git a/Docs/Changelog_sm5.txt b/Docs/Changelog_sm5.txt index a0b6007429..b46b9fa23a 100644 --- a/Docs/Changelog_sm5.txt +++ b/Docs/Changelog_sm5.txt @@ -8,6 +8,12 @@ ________________________________________________________________________________ StepMania 5.0 ????????? | 20110??? -------------------------------------------------------------------------------- +2011/07/09 +---------- +* [NotesTheUsual] Update the #COMBOS tag to allow for a Miss Combo attribute. + Any files that only use the Combo attribute will have that value copied to + miss combo on next launch. [Wolfman2000] + 2011/07/07 ---------- * [ScreenEdit] Fix the NoMines transformation bug, issue 363. [Wolfman2000] diff --git a/Themes/_fallback/Languages/en.ini b/Themes/_fallback/Languages/en.ini index 505e6582ca..2ef2b0104c 100644 --- a/Themes/_fallback/Languages/en.ini +++ b/Themes/_fallback/Languages/en.ini @@ -1248,7 +1248,7 @@ Enter a new Stop value.=Enter a new Stop value.\n\nType "0" to remove. Enter a new Delay value.=Enter a new Delay value.\n\nType "0" to remove. Enter a new Time Signature.=Enter a new time signature.\nUse the format "x/y".\nEnter the previous value to remove. Enter a new Tickcount value.=Enter a new Tickcount value.\n\nEnter the previous value to remove. -Enter a new Combo value.=Enter a new Combo value.\n\nEnter the previous value to remove. +Enter a new Combo value.=Enter a new Combo value.\nUse the format "x/y".\nEnter the previous value to remove. Enter a new Label value.=Enter a name for this section of the chart.\n\nEnter a previously used label to remove. Enter a new Warp value.=Enter the number of beats you will warp over.\n\nType "0" to remove this segment. Enter a new Speed percent value.=Enter the ratio for speed scrolling.\nEnter the previous value to remove.\n1 is the default scroll. diff --git a/src/NoteField.cpp b/src/NoteField.cpp index 3acfb3ea5e..952f6466c4 100644 --- a/src/NoteField.cpp +++ b/src/NoteField.cpp @@ -577,7 +577,7 @@ void NoteField::DrawTickcountText( const float fBeat, int iTicks ) m_textMeasureNumber.Draw(); } -void NoteField::DrawComboText( const float fBeat, int iCombo ) +void NoteField::DrawComboText( const float fBeat, int iCombo, int iMiss ) { const float fYOffset = ArrowEffects::GetYOffset( m_pPlayerState, 0, fBeat ); const float fYPos = ArrowEffects::GetYPos( m_pPlayerState, 0, fYOffset, m_fYReverseOffsetPixels ); @@ -589,7 +589,7 @@ void NoteField::DrawComboText( const float fBeat, int iCombo ) m_textMeasureNumber.SetHorizAlign( COMBO_IS_LEFT_SIDE ? align_right : align_left ); m_textMeasureNumber.SetDiffuse( COMBO_COLOR ); m_textMeasureNumber.SetGlow( RageColor(1,1,1,RageFastCos(RageTimer::GetTimeSinceStartFast()*2)/2+0.5f) ); - m_textMeasureNumber.SetText( ssprintf("%d", iCombo) ); + m_textMeasureNumber.SetText( ssprintf("%d/%d", iCombo, iMiss) ); m_textMeasureNumber.SetXY( (COMBO_IS_LEFT_SIDE ? -xBase - xOffset : xBase + xOffset), fYPos ); m_textMeasureNumber.Draw(); } @@ -981,7 +981,7 @@ void NoteField::DrawPrimitives() { float fBeat = seg->GetBeat(); if( IS_ON_SCREEN(fBeat) ) - DrawComboText( fBeat, seg->GetCombo() ); + DrawComboText( fBeat, seg->GetCombo(), seg->GetMissCombo() ); } } } diff --git a/src/NoteField.h b/src/NoteField.h index 3357eff284..2deb044350 100644 --- a/src/NoteField.h +++ b/src/NoteField.h @@ -62,7 +62,7 @@ protected: void DrawWarpText( const float fBeat, const float fNewBeat ); void DrawTimeSignatureText( const float fBeat, int iNumerator, int iDenominator ); void DrawTickcountText( const float fBeat, int iTicks ); - void DrawComboText( const float fBeat, int iCombo ); + void DrawComboText( const float fBeat, int iCombo, int iMiss ); void DrawLabelText( const float fBeat, RString sLabel ); void DrawSpeedText( const float fBeat, float fPercent, float fWait, unsigned short usMode ); void DrawScrollText( const float fBeat, float fPercent ); diff --git a/src/NotesLoaderKSF.cpp b/src/NotesLoaderKSF.cpp index 3ad22bfbc4..32971b9774 100644 --- a/src/NotesLoaderKSF.cpp +++ b/src/NotesLoaderKSF.cpp @@ -378,7 +378,7 @@ static bool LoadFromKSFFile( const RString &sPath, Steps &out, const Song &song, else if (BeginsWith(sRowString, "|M") || BeginsWith(sRowString, "|C")) { // multipliers/combo - stepsTiming.SetComboAtBeat( fCurBeat, static_cast(numTemp) ); + stepsTiming.SetHitComboAtBeat( fCurBeat, static_cast(numTemp) ); } else if (BeginsWith(sRowString, "|S")) { diff --git a/src/NotesLoaderSMA.cpp b/src/NotesLoaderSMA.cpp index 05db8d42b0..a47b639350 100644 --- a/src/NotesLoaderSMA.cpp +++ b/src/NotesLoaderSMA.cpp @@ -23,17 +23,22 @@ void SMALoader::ProcessMultipliers( TimingData &out, const int iRowsPerBeat, con { vector arrayMultiplierValues; split( arrayMultiplierExpressions[f], "=", arrayMultiplierValues ); - if( arrayMultiplierValues.size() != 2 ) + unsigned size = arrayMultiplierValues.size(); + if( size < 2 ) { LOG->UserLog("Song file", this->GetSongTitle(), - "has an invalid #MULTIPLIER value \"%s\" (must have exactly one '='), ignored.", + "has an invalid #MULTIPLIER value \"%s\" (must have at least one '='), ignored.", arrayMultiplierExpressions[f].c_str() ); continue; } const float fComboBeat = RowToBeat( arrayMultiplierValues[0], iRowsPerBeat ); - const int iCombos = StringToInt( arrayMultiplierValues[1] ); - ComboSegment new_seg( fComboBeat, iCombos ); + const int iCombos = StringToInt( arrayMultiplierValues[1] ); // always true. + // hoping I'm right here: SMA files can use 6 values after the row/beat. + const int iMisses = (size == 2 || size == 4 ? + iCombos : + StringToInt(arrayMultiplierValues[2])); + ComboSegment new_seg( fComboBeat, iCombos, iMisses ); out.AddComboSegment( new_seg ); } } diff --git a/src/NotesLoaderSSC.cpp b/src/NotesLoaderSSC.cpp index 0073198195..83c249d579 100644 --- a/src/NotesLoaderSSC.cpp +++ b/src/NotesLoaderSSC.cpp @@ -94,17 +94,19 @@ void SSCLoader::ProcessCombos( TimingData &out, const RString line, const int ro { vector arrayComboValues; split( arrayComboExpressions[f], "=", arrayComboValues ); - if( arrayComboValues.size() != 2 ) + unsigned size = arrayComboValues.size(); + if( size < 2 ) { LOG->UserLog("Song file", this->GetSongTitle(), - "has an invalid #COMBOS value \"%s\" (must have exactly one '='), ignored.", + "has an invalid #COMBOS value \"%s\" (must have at least one '='), ignored.", arrayComboExpressions[f].c_str() ); continue; } const float fComboBeat = StringToFloat( arrayComboValues[0] ); const int iCombos = StringToInt( arrayComboValues[1] ); - ComboSegment new_seg( fComboBeat, iCombos ); + const int iMisses = (size == 2 ? iCombos : StringToInt(arrayComboValues[2])); + ComboSegment new_seg( fComboBeat, iCombos, iMisses ); out.AddComboSegment( new_seg ); } } diff --git a/src/NotesWriterSSC.cpp b/src/NotesWriterSSC.cpp index 70578ee0dd..d9edfb1946 100644 --- a/src/NotesWriterSSC.cpp +++ b/src/NotesWriterSSC.cpp @@ -128,7 +128,12 @@ static void GetTimingTags( vector &lines, TimingData timing, bool bIsSo ASSERT( !timing.m_ComboSegments.empty() ); w.Init( "COMBOS" ); FOREACH_CONST( ComboSegment, timing.m_ComboSegments, cs ) - w.Write( cs->GetRow(), cs->GetCombo() ); + { + if (cs->GetCombo() == cs->GetMissCombo()) + w.Write( cs->GetRow(), cs->GetCombo() ); + else + w.Write( cs->GetRow(), cs->GetCombo(), cs->GetMissCombo() ); + } w.Finish(); // Song Timing should only have the initial value. diff --git a/src/ScoreKeeperNormal.cpp b/src/ScoreKeeperNormal.cpp index d5b3494a5f..4fc6e1ea92 100644 --- a/src/ScoreKeeperNormal.cpp +++ b/src/ScoreKeeperNormal.cpp @@ -447,17 +447,17 @@ void ScoreKeeperNormal::HandleComboInternal( int iNumHitContinueCombo, int iNumH { m_pPlayerStageStats->m_iCurMissCombo = 0; } - + TimingData td = GAMESTATE->m_pCurSteps[m_pPlayerState->m_PlayerNumber]->m_Timing; if( iNumBreakCombo == 0 ) { - TimingData td = GAMESTATE->m_pCurSteps[m_pPlayerState->m_PlayerNumber]->m_Timing; int multiplier = ( iRow == -1 ? 1 : td.GetComboSegmentAtRow( iRow ).GetCombo() ); m_pPlayerStageStats->m_iCurCombo += iNumHitContinueCombo * multiplier; } else { m_pPlayerStageStats->m_iCurCombo = 0; - m_pPlayerStageStats->m_iCurMissCombo += ( m_MissComboIsPerRow ? 1 : iNumBreakCombo ); + int multiplier = ( iRow == -1 ? 1 : td.GetComboSegmentAtRow(iRow).GetMissCombo()); + m_pPlayerStageStats->m_iCurMissCombo += ( m_MissComboIsPerRow ? 1 : iNumBreakCombo ) * multiplier; } } @@ -467,10 +467,10 @@ void ScoreKeeperNormal::HandleRowComboInternal( TapNoteScore tns, int iNumTapsIn { iNumTapsInRow = min( iNumTapsInRow, 1); } + TimingData td = GAMESTATE->m_pCurSteps[m_pPlayerState->m_PlayerNumber]->m_Timing; if ( tns >= m_MinScoreToContinueCombo ) { m_pPlayerStageStats->m_iCurMissCombo = 0; - TimingData td = GAMESTATE->m_pCurSteps[m_pPlayerState->m_PlayerNumber]->m_Timing; int multiplier = ( iRow == -1 ? 1 : td.GetComboSegmentAtRow( iRow ).GetCombo() ); m_pPlayerStageStats->m_iCurCombo += iNumTapsInRow * multiplier; } @@ -479,7 +479,10 @@ void ScoreKeeperNormal::HandleRowComboInternal( TapNoteScore tns, int iNumTapsIn m_pPlayerStageStats->m_iCurCombo = 0; if( tns <= m_MaxScoreToIncrementMissCombo ) - m_pPlayerStageStats->m_iCurMissCombo += ( m_MissComboIsPerRow ? 1 : iNumTapsInRow ); + { + int multiplier = ( iRow == -1 ? 1 : td.GetComboSegmentAtRow(iRow).GetMissCombo()); + m_pPlayerStageStats->m_iCurMissCombo += ( m_MissComboIsPerRow ? 1 : iNumTapsInRow ) * multiplier; + } } } diff --git a/src/ScreenEdit.cpp b/src/ScreenEdit.cpp index c9f872448a..6009c77d02 100644 --- a/src/ScreenEdit.cpp +++ b/src/ScreenEdit.cpp @@ -3006,10 +3006,10 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM ) } else if ( SM == SM_BackFromComboChange && !ScreenTextEntry::s_bCancelledLast ) { - int iCombo = StringToInt( ScreenTextEntry::s_sLastAnswer ); - if ( iCombo >= 0 ) + int iCombo, iMiss; + if (sscanf(ScreenTextEntry::s_sLastAnswer.c_str(), " %d / %d ", &iCombo, &iMiss) == 2) { - GetAppropriateTiming().SetComboAtBeat( GetBeat(), iCombo ); + GetAppropriateTiming().SetComboAtBeat( GetBeat(), iCombo, iMiss ); } SetDirty( true ); } @@ -3587,10 +3587,14 @@ void ScreenEdit::DisplayTimingMenu() g_TimingDataInformation.rows[bpm].SetOneUnthemedChoice( ssprintf("%.6f", pTime.GetBPMAtBeat( fBeat ) ) ); g_TimingDataInformation.rows[stop].SetOneUnthemedChoice( ssprintf("%.6f", pTime.GetStopAtBeat( fBeat ) ) ) ; g_TimingDataInformation.rows[delay].SetOneUnthemedChoice( ssprintf("%.6f", pTime.GetDelayAtBeat( fBeat ) ) ); - g_TimingDataInformation.rows[time_signature].SetOneUnthemedChoice( ssprintf("%d / %d", pTime.GetTimeSignatureNumeratorAtBeat( fBeat ), pTime.GetTimeSignatureDenominatorAtBeat( fBeat ) ) ); + g_TimingDataInformation.rows[time_signature].SetOneUnthemedChoice(ssprintf("%d / %d", + pTime.GetTimeSignatureNumeratorAtBeat( fBeat ), + pTime.GetTimeSignatureDenominatorAtBeat( fBeat ) ) ); g_TimingDataInformation.rows[label].SetOneUnthemedChoice( pTime.GetLabelAtBeat( fBeat ).c_str() ); g_TimingDataInformation.rows[tickcount].SetOneUnthemedChoice( ssprintf("%d", pTime.GetTickcountAtBeat( fBeat ) ) ); - g_TimingDataInformation.rows[combo].SetOneUnthemedChoice( ssprintf("%d", pTime.GetComboAtBeat( fBeat ) ) ); + g_TimingDataInformation.rows[combo].SetOneUnthemedChoice( ssprintf("%d / %d", + pTime.GetComboAtBeat( fBeat ), + pTime.GetMissComboAtBeat( fBeat ) ) ); g_TimingDataInformation.rows[warp].SetOneUnthemedChoice( ssprintf("%.6f", pTime.GetWarpAtBeat( fBeat ) ) ); g_TimingDataInformation.rows[speed_percent].SetOneUnthemedChoice( bHasSpeedOnThisRow ? ssprintf("%.6f", pTime.GetSpeedPercentAtBeat( fBeat ) ) : "---" ); g_TimingDataInformation.rows[speed_wait].SetOneUnthemedChoice( bHasSpeedOnThisRow ? ssprintf("%.6f", pTime.GetSpeedWaitAtBeat( fBeat ) ) : "---" ); @@ -4566,13 +4570,16 @@ void ScreenEdit::HandleTimingDataInformationChoice( TimingDataInformationChoice ); break; case combo: - ScreenTextEntry::TextEntry( - SM_BackFromComboChange, - ENTER_COMBO_VALUE, - ssprintf( "%d", GetAppropriateTiming().GetComboAtBeat( GetBeat() ) ), - 4 - ); - break; + { + ComboSegment &cs = GetAppropriateTiming().GetComboSegmentAtBeat(GetBeat()); + ScreenTextEntry::TextEntry(SM_BackFromComboChange, + ENTER_COMBO_VALUE, + ssprintf( "%d/%d", + cs.GetCombo(), + cs.GetMissCombo()), + 7); + break; + } case label: ScreenTextEntry::TextEntry( SM_BackFromLabelChange, diff --git a/src/Song.cpp b/src/Song.cpp index 04e7f1fdff..7ec55849c0 100644 --- a/src/Song.cpp +++ b/src/Song.cpp @@ -41,7 +41,7 @@ * @brief The internal version of the cache for StepMania. * * Increment this value to invalidate the current cache. */ -const int FILE_CACHE_VERSION = 189; +const int FILE_CACHE_VERSION = 190; /** @brief How long does a song sample last by default? */ const float DEFAULT_MUSIC_SAMPLE_LENGTH = 12.f; diff --git a/src/Song.h b/src/Song.h index 1a920b1968..a75b740dcd 100644 --- a/src/Song.h +++ b/src/Song.h @@ -20,7 +20,7 @@ void FixupPath( RString &path, const RString &sSongPath ); RString GetSongAssetPath( RString sPath, const RString &sSongPath ); /** @brief The version of the .ssc file format. */ -const static float STEPFILE_VERSION_NUMBER = 0.75f; +const static float STEPFILE_VERSION_NUMBER = 0.76f; /** @brief How many edits for this song can each profile have? */ const int MAX_EDITS_PER_SONG_PER_PROFILE = 15; diff --git a/src/TimingData.cpp b/src/TimingData.cpp index 2c75c60614..29d8d1ada0 100644 --- a/src/TimingData.cpp +++ b/src/TimingData.cpp @@ -166,12 +166,16 @@ void TimingData::SetTimeSignatureAtRow( int iRow, int iNumerator, int iDenominat void TimingData::SetTimeSignatureNumeratorAtRow( int iRow, int iNumerator ) { - SetTimeSignatureAtRow( iRow, iNumerator, GetTimeSignatureSegmentAtBeat( NoteRowToBeat( iRow ) ).GetDen() ); + this->SetTimeSignatureAtRow(iRow, + iNumerator, + GetTimeSignatureSegmentAtRow(iRow).GetDen()); } void TimingData::SetTimeSignatureDenominatorAtRow( int iRow, int iDenominator ) { - SetTimeSignatureAtRow( iRow, GetTimeSignatureSegmentAtBeat( NoteRowToBeat( iRow ) ).GetNum(), iDenominator ); + this->SetTimeSignatureAtRow(iRow, + GetTimeSignatureSegmentAtRow(iRow).GetNum(), + iDenominator); } void TimingData::SetWarpAtRow( int iRow, float fNew ) @@ -222,7 +226,7 @@ void TimingData::SetTickcountAtRow( int iRow, int iTicks ) } } -void TimingData::SetComboAtRow( int iRow, int iCombo ) +void TimingData::SetComboAtRow( int iRow, int iCombo, int iMiss ) { unsigned i; for( i=0; i 0 && m_ComboSegments[i-1].GetCombo() == iCombo ) + if(i > 0 && m_ComboSegments[i-1].GetCombo() == iCombo && + m_ComboSegments[i-1].GetMissCombo() == iMiss) m_ComboSegments.erase( m_ComboSegments.begin()+i, m_ComboSegments.begin()+i+1 ); else + { m_ComboSegments[i].SetCombo(iCombo); + m_ComboSegments[i].SetMissCombo(iMiss); + } } } +void TimingData::SetHitComboAtRow(int iRow, int iCombo) +{ + this->SetComboAtRow(iRow, + iCombo, + this->GetComboSegmentAtRow(iRow).GetMissCombo()); +} + +void TimingData::SetMissComboAtRow(int iRow, int iMiss) +{ + this->SetComboAtRow(iRow, + this->GetComboSegmentAtRow(iRow).GetCombo(), + iMiss); +} + void TimingData::SetLabelAtRow( int iRow, const RString sLabel ) { unsigned i; @@ -398,7 +421,12 @@ float TimingData::GetDelayAtRow( int iRow ) const int TimingData::GetComboAtRow( int iNoteRow ) const { - return m_ComboSegments[GetComboSegmentIndexAtRow( iNoteRow )].GetCombo(); + return m_ComboSegments[this->GetComboSegmentIndexAtRow(iNoteRow)].GetCombo(); +} + +int TimingData::GetMissComboAtRow(int iNoteRow) const +{ + return m_ComboSegments[this->GetComboSegmentIndexAtRow(iNoteRow)].GetMissCombo(); } RString TimingData::GetLabelAtRow( int iRow ) const @@ -1735,7 +1763,7 @@ void TimingData::TidyUpData() // Have a default combo segment of one just in case. if( m_ComboSegments.empty() ) { - ComboSegment seg(0, 1); + ComboSegment seg(0, 1, 1); m_ComboSegments.push_back( seg ); } @@ -1913,8 +1941,9 @@ public: FOREACH_CONST( ComboSegment, p->m_ComboSegments, seg ) { const int combo = seg->GetCombo(); + const int miss = seg->GetMissCombo(); const float beat = seg->GetBeat(); - vCombos.push_back( ssprintf("%f=%d", beat, combo) ); + vCombos.push_back( ssprintf("%f=%d=%d", beat, combo, miss) ); } LuaHelpers::CreateTableFromArray(vCombos, L); return 1; diff --git a/src/TimingData.h b/src/TimingData.h index a4b490e4cb..37b273f71c 100644 --- a/src/TimingData.h +++ b/src/TimingData.h @@ -668,6 +668,18 @@ public: * @return the Combo. */ int GetComboAtBeat( float fBeat ) const { return GetComboAtRow( BeatToNoteRow(fBeat) ); } + /** + * @brief Retrieve the Miss Combo at the given row. + * @param iNoteRow the row in question. + * @return the Miss Combo. + */ + int GetMissComboAtRow( int iNoteRow ) const; + /** + * @brief Retrieve the Miss Combo at the given beat. + * @param fBeat the beat in question. + * @return the Miss Combo. + */ + int GetMissComboAtBeat( float fBeat ) const { return GetMissComboAtRow( BeatToNoteRow(fBeat) ); } /** * @brief Set the row to have the new Combo. * @param iNoteRow the row to have the new Combo. @@ -680,6 +692,44 @@ public: * @param iCombo the Combo. */ void SetComboAtBeat( float fBeat, int iCombo ) { SetComboAtRow( BeatToNoteRow( fBeat ), iCombo ); } + /** + * @brief Set the row to have the new Combo and Miss Combo. + * @param iNoteRow the row to have the new Combo and Miss Combo. + * @param iCombo the Combo. + * @param iMiss the Miss Combo. + */ + void SetComboAtRow( int iNoteRow, int iCombo, int iMiss ); + /** + * @brief Set the beat to have the new Combo and Miss Combo. + * @param fBeat the beat to have the new Combo and Miss Combo. + * @param iCombo the Combo. + * @param iMiss the Miss Combo. + */ + void SetComboAtBeat( float fBeat, int iCombo, int iMiss ) { SetComboAtRow( BeatToNoteRow( fBeat ), iCombo, iMiss ); } + /** + * @brief Set the row to have the new Combo. + * @param iNoteRow the row to have the new Combo. + * @param iCombo the Combo. + */ + void SetHitComboAtRow( int iNoteRow, int iCombo ); + /** + * @brief Set the beat to have the new Combo. + * @param fBeat the beat to have the new Combo. + * @param iCombo the Combo. + */ + void SetHitComboAtBeat( float fBeat, int iCombo ) { SetHitComboAtRow( BeatToNoteRow( fBeat ), iCombo ); } + /** + * @brief Set the row to have the new Miss Combo. + * @param iNoteRow the row to have the new Miss Combo. + * @param iCombo the Miss Combo. + */ + void SetMissComboAtRow( int iNoteRow, int iCombo ); + /** + * @brief Set the beat to have the new Miss Combo. + * @param fBeat the beat to have the new Miss Combo. + * @param iCombo the Miss Combo. + */ + void SetMissComboAtBeat( float fBeat, int iCombo ) { SetMissComboAtRow( BeatToNoteRow( fBeat ), iCombo ); } /** * @brief Retrieve the ComboSegment at the specified row. * @param iNoteRow the row that has a ComboSegment. diff --git a/src/TimingSegments.cpp b/src/TimingSegments.cpp index 304623c285..c208672e01 100644 --- a/src/TimingSegments.cpp +++ b/src/TimingSegments.cpp @@ -125,10 +125,21 @@ void ComboSegment::SetCombo(const int i) this->combo = i; } +int ComboSegment::GetMissCombo() const +{ + return this->missCombo; +} + +void ComboSegment::SetMissCombo(const int i) +{ + this->missCombo = i; +} + bool ComboSegment::operator<( const ComboSegment &other ) const { LTCOMPARE(GetRow()); LTCOMPARE(GetCombo()); + LTCOMPARE(GetMissCombo()); return false; } diff --git a/src/TimingSegments.h b/src/TimingSegments.h index e18e881886..5e59daed90 100644 --- a/src/TimingSegments.h +++ b/src/TimingSegments.h @@ -344,7 +344,8 @@ struct ComboSegment : public TimingSegment ComboSegment(const ComboSegment &other) : TimingSegment(other), - combo(other.GetCombo()) {}; + combo(other.GetCombo()), + missCombo(other.GetMissCombo()) {}; /** * @brief Creates a Combo Segment with the specified values. @@ -354,18 +355,39 @@ struct ComboSegment : public TimingSegment template ComboSegment( StartType s, int t ): TimingSegment(max((StartType)0, s)), - combo(max(0,t)) {} + combo(max(0,t)), missCombo(max(0,t)) {} + + /** + * @brief Creates a Combo Segment with the specified values. + * @param s the starting row / beat of this segment. + * @param t the amount the combo increases on a succesful hit. + * @param m the amount the miss combo increases on missing. + */ + template + ComboSegment(StartType s, int t, int m): + TimingSegment(max((StartType)0, s)), + combo(max(0,t)), missCombo(max(0,m)) {} /** * @brief Get the combo in this ComboSegment. * @return the combo. */ int GetCombo() const; + /** + * @brief Get the miss combo in this ComboSegment. + * @return the miss combo. */ + int GetMissCombo() const; + /** * @brief Set the combo in this ComboSegment. * @param i the combo. */ void SetCombo(const int i); + /** + * @brief Set the miss combo in this ComboSegment. + * @param i the miss combo. */ + void SetMissCombo(const int i); + /** * @brief Compares two ComboSegments to see if one is less than the other. * @param other the other ComboSegment to compare to. @@ -377,6 +399,8 @@ private: * @brief The amount the combo increases at this point. */ int combo; + /** @brief The amount of miss combos given at this point. */ + int missCombo; };