int NoteData::GetNumN( int MinTaps, float fStartBeat, float fEndBeat ) const { if( fEndBeat == -1 ) fEndBeat = GetNumBeats(); int iStartIndex = BeatToNoteRow( fStartBeat ); int iEndIndex = BeatToNoteRow( fEndBeat ); /* Clamp to known-good ranges. */ iStartIndex = max( iStartIndex, 0 ); iEndIndex = min( iEndIndex, GetNumRows()-1 ); int iNum = 0; for( int i=iStartIndex; i<=iEndIndex; i++ ) { int iNumNotesThisIndex = 0; for( int t=0; t<m_iNumTracks; t++ ) { TapNote tn = GetTapNoteX(t, i); if( tn.type != TapNote::mine && tn.type != TapNote::empty ) // mines don't count iNumNotesThisIndex++; } if( iNumNotesThisIndex >= MinTaps ) iNum++; } return iNum; }
int NoteData::GetNumTapNotes( float fStartBeat, float fEndBeat ) const { int iNumNotes = 0; if( fEndBeat == -1 ) fEndBeat = GetNumBeats(); int iStartIndex = BeatToNoteRow( fStartBeat ); int iEndIndex = BeatToNoteRow( fEndBeat ); /* Clamp to known-good ranges. */ iStartIndex = max( iStartIndex, 0 ); iEndIndex = min( iEndIndex, GetNumRows()-1 ); for( int t=0; t<m_iNumTracks; t++ ) { for( int i=iStartIndex; i<=iEndIndex; i++ ) { TapNote tn = GetTapNoteX(t, i); if( tn.type != TapNote::empty && tn.type != TapNote::mine ) iNumNotes++; } } return iNumNotes; }
int NoteData::RowNeedsHands( const int row ) const { int iNumNotesThisIndex = 0; for( int t=0; t<m_iNumTracks; t++ ) { TapNote tn = GetTapNoteX(t, row); switch( tn.type ) { case TapNote::mine: case TapNote::empty: case TapNote::hold_tail: continue; // skip these types - they don't count } ++iNumNotesThisIndex; } /* We must have at least one non-hold-body at this row to count it. */ if( !iNumNotesThisIndex ) return false; if( iNumNotesThisIndex < 3 ) { /* We have at least one, but not enough. Count holds. */ for( int j=0; j<GetNumHoldNotes(); j++ ) { const HoldNote &hn = GetHoldNote(j); if( hn.iStartRow+1 <= row && row <= hn.iEndRow ) ++iNumNotesThisIndex; } } return iNumNotesThisIndex >= 3; }
/* See NoteData::GetNumHands(). */ int NoteDataWithScoring::GetSuccessfulHands( float fStartBeat, float fEndBeat ) const { if( fEndBeat == -1 ) fEndBeat = GetNumBeats(); int iStartIndex = BeatToNoteRow( fStartBeat ); int iEndIndex = BeatToNoteRow( fEndBeat ); /* Clamp to known-good ranges. */ iStartIndex = max( iStartIndex, 0 ); iEndIndex = min( iEndIndex, GetNumRows()-1 ); int iNum = 0; for( int i=iStartIndex; i<=iEndIndex; i++ ) { if( !RowNeedsHands(i) ) continue; bool Missed = false; for( int t=0; t<GetNumTracks(); t++ ) { TapNote tn = GetTapNoteX(t, i); if( tn.type == TapNote::empty ) continue; if( tn.type == TapNote::mine ) // mines don't count continue; if( GetTapNoteScore(t, i) <= TNS_BOO ) Missed = true; } if( Missed ) continue; /* Check hold scores. */ for( int j=0; j<GetNumHoldNotes(); j++ ) { const HoldNote &hn = GetHoldNote(j); HoldNoteResult hnr = GetHoldNoteResult( hn ); /* Check if the row we're checking is in range. */ if( !hn.RowIsInRange(i) ) continue; /* If a hold is released *after* a hands containing it, the hands is * still good. So, ignore the judgement and only examine iLastHeldRow * to be sure that the hold was still held at the point of this row. * (Note that if the hold head tap was missed, then iLastHeldRow == i * and this won't fail--but the tap check above will have already failed.) */ if( hnr.iLastHeldRow < i ) Missed = true; } if( !Missed ) iNum++; } return iNum; }
int NoteData::GetFirstNonEmptyTrack( int index ) const { /* If this is out of range, we don't have any notes there, so all tracks are empty. */ if( index < 0 || index >= GetNumRows() ) return 0; for( int t=0; t<m_iNumTracks; t++ ) if( GetTapNoteX( t, index ).type != TapNote::empty ) return t; return -1; }
bool NoteData::IsRowEmpty( int index ) const { /* If this is out of range, we don't have any notes there, so all tracks are empty. */ if( index < 0 || index >= GetNumRows() ) return true; for( int t=0; t<m_iNumTracks; t++ ) if( GetTapNoteX(t, index).type != TapNote::empty ) return false; return true; }
bool NoteData::IsRangeEmpty( int track, int iIndexBegin, int iIndexEnd ) const { ASSERT( track<m_iNumTracks ); CLAMP( iIndexBegin, 0, GetNumRows()-1 ); CLAMP( iIndexEnd, 0, GetNumRows()-1 ); for( int i=iIndexBegin; i<=iIndexEnd; i++ ) if( GetTapNoteX(track,i).type != TapNote::empty ) return false; return true; }
int NoteData::GetFirstTrackWithTapOrHoldHead( int index ) const { /* If this is out of range, we don't have any notes there, so all tracks are empty. */ if( index < 0 || index >= GetNumRows() ) return -1; for( int t=0; t<m_iNumTracks; t++ ) { TapNote tn = GetTapNoteX( t, index ); if( tn.type == TapNote::tap || tn.type == TapNote::hold_head ) return t; } return -1; }
int NoteData::GetNumTracksWithTap( int index ) const { /* If this is out of range, we don't have any notes there, so all tracks are empty. */ if( index < 0 || index >= GetNumRows() ) return 0; int iNum = 0; for( int t=0; t<m_iNumTracks; t++ ) { TapNote tn = GetTapNoteX( t, index ); if( tn.type == TapNote::tap ) iNum++; } return iNum; }