Пример #1
0
void NoteData::Convert2sAnd3sToHoldNotes()
{
	// Any note will end a hold (not just a TAP_HOLD_TAIL).  This makes parsing DWIs much easier.
	// Plus, allowing tap notes in the middle of a hold doesn't make sense!

	int rows = GetLastRow();
	for( int col=0; col<m_iNumTracks; col++ )	// foreach column
	{
		for( int i=0; i<=rows; i++ )	// foreach TapNote element
		{
			if( GetTapNote(col,i).type != TapNote::hold_head )	// this is a HoldNote begin marker
				continue;
			SetTapNote(col, i, TAP_EMPTY);	// clear the hold head marker

			for( int j=i+1; j<=rows; j++ )	// search for end of HoldNote
			{
				// End hold on the next note we see.  This should be a hold_tail if the 
				// data is in a consistent state, but doesn't have to be.
				if( GetTapNote(col, j).type == TapNote::empty )
					continue;

				SetTapNote(col, j, TAP_EMPTY);

				AddHoldNote( HoldNote(col, i, j) );
				break;	// done searching for the end of this hold
			}
		}
	}
}
Пример #2
0
int NoteDataWithScoring::GetNumNWithScore( TapNoteScore tns, int MinTaps, const float fStartBeat, float fEndBeat ) const
{
	if( fEndBeat == -1 )
		fEndBeat = GetNumBeats();

	int iStartIndex = BeatToNoteRow( fStartBeat );
	int iEndIndex = BeatToNoteRow( fEndBeat );

	iStartIndex = max( iStartIndex, 0 );
	iEndIndex = min( iEndIndex, GetNumRows()-1 );

	int iNumSuccessfulDoubles = 0;
	for( int i=iStartIndex; i<=iEndIndex; i++ )
	{
		int iNumNotesThisIndex = 0;
		TapNoteScore	minTapNoteScore = TNS_MARVELOUS;
		for( int t=0; t<GetNumTracks(); t++ )
		{
			switch( GetTapNote(t, i).type )
			{
			case TapNote::tap:		
			case TapNote::hold_head: 
				iNumNotesThisIndex++;
				minTapNoteScore = min( minTapNoteScore, GetTapNoteScore(t, i) );
			}
		}
		if( iNumNotesThisIndex >= MinTaps && minTapNoteScore >= tns )
			iNumSuccessfulDoubles++;
	}
	
	return iNumSuccessfulDoubles;
}
Пример #3
0
/* Return the last tap score of a row: the grade of the tap that completed
 * the row.  If the row has no tap notes, return -1.  If any tap notes aren't
 * graded (any tap is TNS_NONE) or are missed (TNS_MISS), return it. */
int NoteDataWithScoring::LastTapNoteScoreTrack(unsigned row) const
{
	float scoretime = -9999;
	int best_track = -1;
	for( int t=0; t<GetNumTracks(); t++ )
	{
		/* Skip empty tracks and mines */
		TapNote tn = GetTapNote(t, row);
		if( tn.type == TapNote::empty || tn.type == TapNote::mine ) 
			continue;

		TapNoteScore tns = GetTapNoteScore(t, row);
		
		if( tns == TNS_MISS || tns == TNS_NONE )
			return t;

		float tm = GetTapNoteOffset(t, row);
		if(tm < scoretime) continue;
		
		scoretime = tm;
		best_track = t;
	}

	return best_track;
}
Пример #4
0
void NoteData::PruneUnusedAttacksFromMap()
{
	// Add all used AttackNote index values to a map.
	set<unsigned> setUsedIndices;

	int num_rows = GetNumRows();
	for( int t=0; t<m_iNumTracks; t++ )
	{
		for( int r=0; r<num_rows; r++ )
		{
			TapNote tn = GetTapNote(t, r);
			if( tn.type == TapNote::attack )
				setUsedIndices.insert( tn.attackIndex );
		}
	}

	// Remove all items from m_AttackMap that don't have corresponding
	// TapNotes in use.
	for( unsigned i=0; i<MAX_NUM_ATTACKS; i++ )
	{
		bool bInAttackMap = m_AttackMap.find(i) != m_AttackMap.end();
		bool bActuallyUsed = setUsedIndices.find(i) != setUsedIndices.end();

		if( bActuallyUsed && !bInAttackMap )
			ASSERT(0);	// something earlier than us didn't enforce consistency 

		if( bInAttackMap && !bActuallyUsed )
			m_AttackMap.erase( i );
	}
}
Пример #5
0
int NoteData::GetNumTapNonEmptyTracks( int index ) const
{
	int iNum = 0;
	for( int t=0; t<m_iNumTracks; t++ )
		if( GetTapNote(t, index).type != TapNote::empty )
			iNum++;
	return iNum;
}
Пример #6
0
/* "104444001" ==
 * "102000301"
 *
 * "4441" basically means "hold for three rows then hold for another tap";
 * since taps don't really have a length, it's equivalent to "4440".
 * So, make sure the character after a 4 is always a 0. */
void NoteData::Convert4sToHoldNotes()
{
	int rows = GetLastRow();
	for( int col=0; col<m_iNumTracks; col++ )	// foreach column
	{
		for( int i=0; i<=rows; i++ )	// foreach TapNote element
		{
			if( GetTapNote(col, i).type == TapNote::hold )	// this is a HoldNote body
			{
				HoldNote hn( col, i, 0 );
				// search for end of HoldNote
				do {
					SetTapNote(col, i, TAP_EMPTY);
					i++;
				} while( GetTapNote(col, i).type == TapNote::hold );
				SetTapNote(col, i, TAP_EMPTY);

				hn.iEndRow = i;
				AddHoldNote( hn );
			}
		}
	}
}
Пример #7
0
/* Return the minimum tap score of a row.  If the row isn't complete (not all
 * taps have been hit), return TNS_NONE or TNS_MISS. */
TapNoteScore NoteDataWithScoring::MinTapNoteScore(unsigned row) const
{
	TapNoteScore score = TNS_MARVELOUS;
	for( int t=0; t<GetNumTracks(); t++ )
	{
		/* Don't coun, or else the score 
		 * will always be TNS_NONE. */
		TapNote tn = GetTapNote(t, row);
		if( tn.type == TapNote::empty || tn.type == TapNote::mine) 
			continue;
		score = min( score, GetTapNoteScore(t, row) );
	}

	return score;
}
Пример #8
0
const Attack& NoteData::GetAttackAt( int track, int row )
{
	TapNote tn = GetTapNote(track, row);
	ASSERT( tn.type == TapNote::attack );	// don't call this if the TapNote here isn't an attack
	map<unsigned,Attack>::iterator iter = m_AttackMap.find( tn.attackIndex );

	/* Hack: if referencing an attack that doesn't exist, add it.  This is just
	 * to prevent crashes.  This hack isn't needed in newer versions, since this
	 * interface is gone. */
	if( iter == m_AttackMap.end() )
	{
		m_AttackMap[tn.attackIndex] = Attack();
		iter = m_AttackMap.find( tn.attackIndex );
		ASSERT( iter != m_AttackMap.end() );
	}
	return iter->second;
}
Пример #9
0
void NoteData::GetTapNonEmptyTracks( int index, set<int>& addTo ) const
{
	for( int t=0; t<m_iNumTracks; t++ )
		if( GetTapNote(t, index).type != TapNote::empty )
			addTo.insert(t);
}