diff --git a/stepmania/src/NoteData.cpp b/stepmania/src/NoteData.cpp index c7ebee6e2d..4155dc134d 100644 --- a/stepmania/src/NoteData.cpp +++ b/stepmania/src/NoteData.cpp @@ -375,37 +375,101 @@ void NoteData::RemoveHoldNote( int iHoldIndex ) } /* Return true if a hold note lies on the given spot. Must be in 2sAnd3s. */ -bool NoteData::IsHoldNoteAtBeat( int iTrack, int iRow ) const +bool NoteData::IsHoldNoteAtBeat( int iTrack, int iRow, int *pHeadRow, int *pTailRow ) const { - /* Starting at iRow, search upwards. If we find a TapNote::hold_head, we're within - * a hold. If we find a tap, mine or attack, we're not--those never lie within hold - * notes. Ignore autoKeysound. */ - FOREACH_NONEMPTY_ROW_IN_TRACK_RANGE_REVERSE( *this, iTrack, r, 0, iRow ) - { - const TapNote &tn = GetTapNote( iTrack, r ); - switch( tn.type ) - { - case TapNote::hold_head: - return true; + /* If neither the actual head nor tail row were requested, search for the head to + * determine the return value. */ + int iDummy; + if( pHeadRow == NULL ) + pHeadRow = &iDummy; - case TapNote::tap: - case TapNote::mine: - case TapNote::attack: - case TapNote::hold_tail: - return false; - case TapNote::empty: - case TapNote::autoKeysound: - /* ignore */ - continue; - case TapNote::hold: - /* Don't call this function when in 4s mode! */ - FAIL_M("hold"); - default: - FAIL_M( ssprintf("%i", tn.type) ); + bool bFoundHead = false; + if( pHeadRow != NULL ) + { + /* Starting at iRow, search upwards. If we find a TapNote::hold_head, we're within + * a hold. If we find a tap, mine or attack, we're not--those never lie within hold + * notes. Ignore autoKeysound. */ + FOREACH_NONEMPTY_ROW_IN_TRACK_RANGE_REVERSE( *this, iTrack, r, 0, iRow ) + { + const TapNote &tn = GetTapNote( iTrack, r ); + switch( tn.type ) + { + case TapNote::hold_head: + *pHeadRow = r; + bFoundHead = true; + break; + + case TapNote::tap: + case TapNote::mine: + case TapNote::attack: + case TapNote::hold_tail: + return false; + case TapNote::empty: + case TapNote::autoKeysound: + /* ignore */ + continue; + case TapNote::hold: + /* Don't call this function when in 4s mode! */ + FAIL_M("hold"); + default: + FAIL_M( ssprintf("%i", tn.type) ); + } + + if( bFoundHead ) + break; } + + /* If we didn't find a matching head, we're not within a hold note, so don't bother + * searching for a tail. */ + if( !bFoundHead ) + return false; } - return false; + bool bFoundTail = false; + if( pTailRow != NULL ) + { + FOREACH_NONEMPTY_ROW_IN_TRACK_RANGE( *this, iTrack, r, iRow, MAX_NOTE_ROW ) + { + const TapNote &tn = GetTapNote( iTrack, r ); + + switch( tn.type ) + { + case TapNote::hold_tail: + *pTailRow = r; + bFoundTail = true; + break; + case TapNote::tap: + case TapNote::mine: + case TapNote::attack: + return false; + case TapNote::hold_head: + /* If iRow is a hold head, we're within a hold note, and need to continue searching; + * if any row after that is a head, we're not in it, so stop. This is different + * than above, since holds are [head,tail); the row of the tail isn't actually + * part of the hold. */ + if( r == iRow ) + continue; + + return false; + + case TapNote::empty: + case TapNote::autoKeysound: + /* ignore */ + continue; + case TapNote::hold: + /* Don't call this function when in 4s mode! */ + FAIL_M("hold"); + default: + FAIL_M( ssprintf("%i", tn.type) ); + } + + if( bFoundTail ) + break; + return true; + } + } + + return bFoundHead || bFoundTail; } int NoteData::GetFirstRow() const diff --git a/stepmania/src/NoteData.h b/stepmania/src/NoteData.h index e9ee3b2a65..d7c587c075 100644 --- a/stepmania/src/NoteData.h +++ b/stepmania/src/NoteData.h @@ -104,7 +104,12 @@ public: void RemoveHoldNote( int index ); HoldNote &GetHoldNote( int index ) { ASSERT( index < (int) m_HoldNotes.size() ); return m_HoldNotes[index]; } const HoldNote &GetHoldNote( int index ) const { ASSERT( index < (int) m_HoldNotes.size() ); return m_HoldNotes[index]; } - bool IsHoldNoteAtBeat( int iTrack, int iRow ) const; /* must be in 2sAnd3s */ + + /* Determine if a given spot is within a hold note (being on the tail doesn't count). + * Return true if so. If pHeadRow is non-NULL, return the row of the head. If pTailRow is + * non-NULL, return the row of the tail. This function is faster if pTailRow is NULL. + * Must be in 2sAnd3s. */ + bool IsHoldNoteAtBeat( int iTrack, int iRow, int *pHeadRow = NULL, int *pTailRow = NULL ) const; // // statistics diff --git a/stepmania/src/NoteDataUtil.cpp b/stepmania/src/NoteDataUtil.cpp index 347ae96c4d..5ce9f4ea94 100644 --- a/stepmania/src/NoteDataUtil.cpp +++ b/stepmania/src/NoteDataUtil.cpp @@ -381,6 +381,21 @@ void NoteDataUtil::LoadOverlapped( const NoteData &input, NoteData &out, int iNe out.Convert4sToHoldNotes(); } +int FindLongestOverlappingHoldNoteForAnyTrack( const NoteData &in, int iRow ) +{ + int iMaxTailRow = -1; + for( int t=0; t