m_NotesType => m_StepsType

split NoteDataUtil to sep file
This commit is contained in:
Chris Danford
2003-08-07 06:36:34 +00:00
parent f5cd95b4f9
commit 1a0d83cbc0
35 changed files with 1063 additions and 987 deletions
+1 -1
View File
@@ -180,7 +180,7 @@ void BPMDisplay::SetBPM( const Course* pCourse )
ASSERT( pCourse );
vector<Course::Info> ci;
pCourse->GetCourseInfo( GAMESTATE->GetCurrentStyleDef()->m_NotesType, ci );
pCourse->GetCourseInfo( GAMESTATE->GetCurrentStyleDef()->m_StepsType, ci );
ASSERT( ci.size() );
+2 -2
View File
@@ -95,7 +95,7 @@ int Course::GetMeter( int Difficult ) const
/*LOG->Trace( "Course file '%s' contains a song '%s%s%s' that is not present",
m_sPath.c_str(), sGroup.c_str(), sGroup.size()? SLASH:"", sSong.c_str());*/
vector<Info> ci;
GetCourseInfo( GAMESTATE->GetCurrentStyleDef()->m_NotesType, ci, Difficult );
GetCourseInfo( GAMESTATE->GetCurrentStyleDef()->m_StepsType, ci, Difficult );
/* Take the average meter. */
float fTotalMeter = 0;
@@ -942,7 +942,7 @@ void Course::UpdateCourseStats()
}
vector<Info> ci;
GetCourseInfo( GAMESTATE->GetCurrentStyleDef()->m_NotesType, ci );
GetCourseInfo( GAMESTATE->GetCurrentStyleDef()->m_StepsType, ci );
for( i = 0; i < ci.size(); i++ )
SortOrder_TotalDifficulty += ci[i].pNotes->GetMeter();
+1 -1
View File
@@ -55,7 +55,7 @@ void CourseContentsList::SetFromCourse( Course* pCourse )
m_iNumContents = 0;
vector<Course::Info> ci;
pCourse->GetCourseInfo( GAMESTATE->GetCurrentStyleDef()->m_NotesType, ci );
pCourse->GetCourseInfo( GAMESTATE->GetCurrentStyleDef()->m_StepsType, ci );
for( int i=0; i<min((int)ci.size(), MAX_TOTAL_CONTENTS); i++ )
{
+5 -5
View File
@@ -104,7 +104,7 @@ EditMenu::EditMenu()
// fill in data structures
SONGMAN->GetGroupNames( m_sGroups );
GAMEMAN->GetNotesTypesForGame( GAMESTATE->m_CurGame, m_NotesTypes );
GAMEMAN->GetNotesTypesForGame( GAMESTATE->m_CurGame, m_StepsTypes );
ChangeToRow( (Row)0 );
OnRowValueChanged( (Row)0 );
@@ -127,8 +127,8 @@ EditMenu::EditMenu()
// Select the current StepsType and difficulty if any
if( GAMESTATE->m_pCurNotes )
{
for( i=0; i<m_NotesTypes.size(); i++ )
if( m_NotesTypes[i] == GAMESTATE->m_pCurNotes[PLAYER_1]->m_NotesType )
for( i=0; i<m_StepsTypes.size(); i++ )
if( m_StepsTypes[i] == GAMESTATE->m_pCurNotes[PLAYER_1]->m_StepsType )
{
m_iSelection[ROW_NOTES_TYPE] = i;
OnRowValueChanged( ROW_NOTES_TYPE );
@@ -177,9 +177,9 @@ bool EditMenu::CanGoRight()
{
m_sGroups.size(),
m_pSongs.size(),
m_NotesTypes.size(),
m_StepsTypes.size(),
NUM_DIFFICULTIES,
m_NotesTypes.size(),
m_StepsTypes.size(),
NUM_DIFFICULTIES,
m_Actions.size()
};
+3 -3
View File
@@ -90,9 +90,9 @@ public:
CString GetSelectedGroup() { return m_sGroups[m_iSelection[ROW_GROUP]]; }
Song* GetSelectedSong() { return m_pSongs[m_iSelection[ROW_SONG]]; }
StepsType GetSelectedNotesType() { return m_NotesTypes[m_iSelection[ROW_NOTES_TYPE]]; }
StepsType GetSelectedNotesType() { return m_StepsTypes[m_iSelection[ROW_NOTES_TYPE]]; }
Difficulty GetSelectedDifficulty() { return (Difficulty)m_iSelection[ROW_DIFFICULTY]; }
StepsType GetSelectedSourceNotesType() { return m_NotesTypes[m_iSelection[ROW_SOURCE_NOTES_TYPE]]; }
StepsType GetSelectedSourceNotesType() { return m_StepsTypes[m_iSelection[ROW_SOURCE_NOTES_TYPE]]; }
Difficulty GetSelectedSourceDifficulty() { return (Difficulty)m_iSelection[ROW_SOURCE_DIFFICULTY]; }
Action GetSelectedAction() { return m_Actions[m_iSelection[ROW_ACTION]]; }
@@ -113,7 +113,7 @@ private:
DifficultyMeter m_SourceMeter;
CStringArray m_sGroups;
vector<StepsType> m_NotesTypes;
vector<StepsType> m_StepsTypes;
vector<Song*> m_pSongs;
vector<Action> m_Actions;
+23 -23
View File
@@ -637,7 +637,7 @@ StyleDef g_StyleDefs[NUM_STYLES] =
true, // m_bUsedForGameplay
true, // m_bUsedForEdit
"single", // m_szName
STEPS_TYPE_DANCE_SINGLE, // m_NotesType
STEPS_TYPE_DANCE_SINGLE, // m_StepsType
StyleDef::ONE_PLAYER_ONE_CREDIT, // m_StyleType
{ 160, 480 }, // m_iCenterX
4, // m_iColsPerPlayer
@@ -664,7 +664,7 @@ StyleDef g_StyleDefs[NUM_STYLES] =
true, // m_bUsedForGameplay
false, // m_bUsedForEdit
"versus", // m_szName
STEPS_TYPE_DANCE_SINGLE, // m_NotesType
STEPS_TYPE_DANCE_SINGLE, // m_StepsType
StyleDef::TWO_PLAYERS_TWO_CREDITS, // m_StyleType
{ 160, 480 }, // m_iCenterX
4, // m_iColsPerPlayer
@@ -691,7 +691,7 @@ StyleDef g_StyleDefs[NUM_STYLES] =
true, // m_bUsedForGameplay
true, // m_bUsedForEdit
"double", // m_szName
STEPS_TYPE_DANCE_DOUBLE, // m_NotesType
STEPS_TYPE_DANCE_DOUBLE, // m_StepsType
StyleDef::ONE_PLAYER_TWO_CREDITS, // m_StyleType
{ 320, 320 }, // m_iCenterX
8, // m_iColsPerPlayer
@@ -726,7 +726,7 @@ StyleDef g_StyleDefs[NUM_STYLES] =
true, // m_bUsedForGameplay
false, // m_bUsedForEdit
"couple", // m_szName
STEPS_TYPE_DANCE_COUPLE, // m_NotesType
STEPS_TYPE_DANCE_COUPLE, // m_StepsType
StyleDef::TWO_PLAYERS_TWO_CREDITS, // m_StyleType
{ 160, 480 }, // m_iCenterX
4, // m_iColsPerPlayer
@@ -753,7 +753,7 @@ StyleDef g_StyleDefs[NUM_STYLES] =
true, // m_bUsedForGameplay
true, // m_bUsedForEdit
"solo", // m_szName
STEPS_TYPE_DANCE_SOLO, // m_NotesType
STEPS_TYPE_DANCE_SOLO, // m_StepsType
StyleDef::ONE_PLAYER_ONE_CREDIT, // m_StyleType
{ 320, 320 }, // m_iCenterX
6, // m_iColsPerPlayer
@@ -784,7 +784,7 @@ StyleDef g_StyleDefs[NUM_STYLES] =
false, // m_bUsedForGameplay
true, // m_bUsedForEdit
"couple (edit)", // m_szName
STEPS_TYPE_DANCE_COUPLE, // m_NotesType
STEPS_TYPE_DANCE_COUPLE, // m_StepsType
StyleDef::ONE_PLAYER_ONE_CREDIT, // m_StyleType
{ 160, 480 }, // m_iCenterX
8, // m_iColsPerPlayer
@@ -816,7 +816,7 @@ StyleDef g_StyleDefs[NUM_STYLES] =
},
/* { // STYLE_DANCE_SOLO_VERSUS
"dance-solo-versus", // m_szName
STEPS_TYPE_DANCE_SOLO, // m_NotesType
STEPS_TYPE_DANCE_SOLO, // m_StepsType
StyleDef::ONE_PLAYER_ONE_CREDIT, // m_StyleType
{ 160, 480 }, // m_iCenterX
6, // m_iColsPerPlayer
@@ -847,7 +847,7 @@ StyleDef g_StyleDefs[NUM_STYLES] =
true, // m_bUsedForGameplay
true, // m_bUsedForEdit
"single", // m_szName
STEPS_TYPE_PUMP_SINGLE, // m_NotesType
STEPS_TYPE_PUMP_SINGLE, // m_StepsType
StyleDef::ONE_PLAYER_ONE_CREDIT, // m_StyleType
{ 160, 480 }, // m_iCenterX
5, // m_iColsPerPlayer
@@ -876,7 +876,7 @@ StyleDef g_StyleDefs[NUM_STYLES] =
true, // m_bUsedForGameplay
false, // m_bUsedForEdit
"versus", // m_szName
STEPS_TYPE_PUMP_SINGLE, // m_NotesType
STEPS_TYPE_PUMP_SINGLE, // m_StepsType
StyleDef::TWO_PLAYERS_TWO_CREDITS, // m_StyleType
{ 160, 480 }, // m_iCenterX
5, // m_iColsPerPlayer
@@ -905,7 +905,7 @@ StyleDef g_StyleDefs[NUM_STYLES] =
true, // m_bUsedForGameplay
true, // m_bUsedForEdit
"halfdouble", // m_szName
STEPS_TYPE_PUMP_HALFDOUBLE, // m_NotesType
STEPS_TYPE_PUMP_HALFDOUBLE, // m_StepsType
StyleDef::ONE_PLAYER_TWO_CREDITS, // m_StyleType
{ 320, 320 }, // m_iCenterX
6, // m_iColsPerPlayer
@@ -936,7 +936,7 @@ StyleDef g_StyleDefs[NUM_STYLES] =
true, // m_bUsedForGameplay
true, // m_bUsedForEdit
"double", // m_szName
STEPS_TYPE_PUMP_DOUBLE, // m_NotesType
STEPS_TYPE_PUMP_DOUBLE, // m_StepsType
StyleDef::ONE_PLAYER_TWO_CREDITS, // m_StyleType
{ 320, 320 }, // m_iCenterX
10, // m_iColsPerPlayer
@@ -975,7 +975,7 @@ StyleDef g_StyleDefs[NUM_STYLES] =
true, // m_bUsedForGameplay
false, // m_bUsedForEdit
"couple", // m_szName
STEPS_TYPE_PUMP_COUPLE, // m_NotesType
STEPS_TYPE_PUMP_COUPLE, // m_StepsType
StyleDef::TWO_PLAYERS_TWO_CREDITS, // m_StyleType
{ 160, 480 }, // m_iCenterX
5, // m_iColsPerPlayer
@@ -1004,7 +1004,7 @@ StyleDef g_StyleDefs[NUM_STYLES] =
false, // m_bUsedForGameplay
true, // m_bUsedForEdit
"couple (edit)", // m_szName
STEPS_TYPE_PUMP_COUPLE, // m_NotesType
STEPS_TYPE_PUMP_COUPLE, // m_StepsType
StyleDef::ONE_PLAYER_ONE_CREDIT, // m_StyleType
{ 160, 480 }, // m_iCenterX
10, // m_iColsPerPlayer
@@ -1038,7 +1038,7 @@ StyleDef g_StyleDefs[NUM_STYLES] =
true, // m_bUsedForGameplay
true, // m_bUsedForEdit
"single", // m_szName
STEPS_TYPE_EZ2_SINGLE, // m_NotesType
STEPS_TYPE_EZ2_SINGLE, // m_StepsType
StyleDef::ONE_PLAYER_ONE_CREDIT, // m_StyleType
{ 160, 480 }, // m_iCenterX
5, // m_iColsPerPlayer
@@ -1067,7 +1067,7 @@ StyleDef g_StyleDefs[NUM_STYLES] =
true, // m_bUsedForGameplay
true, // m_bUsedForEdit
"real", // m_szName
STEPS_TYPE_EZ2_REAL, // m_NotesType
STEPS_TYPE_EZ2_REAL, // m_StepsType
StyleDef::ONE_PLAYER_ONE_CREDIT, // m_StyleType
{ 160, 480 }, // m_iCenterX
7, // m_iColsPerPlayer
@@ -1100,7 +1100,7 @@ StyleDef g_StyleDefs[NUM_STYLES] =
true, // m_bUsedForGameplay
true, // m_bUsedForEdit
"versus", // m_szName
STEPS_TYPE_EZ2_SINGLE, // m_NotesType
STEPS_TYPE_EZ2_SINGLE, // m_StepsType
StyleDef::TWO_PLAYERS_TWO_CREDITS, // m_StyleType
{ 160, 480 }, // m_iCenterX
5, // m_iColsPerPlayer
@@ -1129,7 +1129,7 @@ StyleDef g_StyleDefs[NUM_STYLES] =
true, // m_bUsedForGameplay
true, // m_bUsedForEdit
"versusReal", // m_szName
STEPS_TYPE_EZ2_REAL, // m_NotesType
STEPS_TYPE_EZ2_REAL, // m_StepsType
StyleDef::TWO_PLAYERS_TWO_CREDITS, // m_StyleType
{ 160, 480 }, // m_iCenterX
7, // m_iColsPerPlayer
@@ -1162,7 +1162,7 @@ StyleDef g_StyleDefs[NUM_STYLES] =
true, // m_bUsedForGameplay
true, // m_bUsedForEdit
"double", // m_szName
STEPS_TYPE_EZ2_DOUBLE, // m_NotesType
STEPS_TYPE_EZ2_DOUBLE, // m_StepsType
StyleDef::ONE_PLAYER_ONE_CREDIT, // m_StyleType
{ 320, 320 }, // m_iCenterX
10, // m_iColsPerPlayer
@@ -1201,7 +1201,7 @@ StyleDef g_StyleDefs[NUM_STYLES] =
true, // m_bUsedForGameplay
true, // m_bUsedForEdit
"single", // m_szName
STEPS_TYPE_PARA_SINGLE, // m_NotesType
STEPS_TYPE_PARA_SINGLE, // m_StepsType
StyleDef::ONE_PLAYER_ONE_CREDIT, // m_StyleType
{ 320, 320 }, // m_iCenterX
5, // m_iColsPerPlayer
@@ -1230,7 +1230,7 @@ StyleDef g_StyleDefs[NUM_STYLES] =
true, // m_bUsedForGameplay
true, // m_bUsedForEdit
"single", // m_szName
STEPS_TYPE_DS3DDX_SINGLE, // m_NotesType
STEPS_TYPE_DS3DDX_SINGLE, // m_StepsType
StyleDef::ONE_PLAYER_ONE_CREDIT, // m_StyleType
{ 160, 480 }, // m_iCenterX
8, // m_iColsPerPlayer
@@ -1265,7 +1265,7 @@ StyleDef g_StyleDefs[NUM_STYLES] =
true, // m_bUsedForGameplay
true, // m_bUsedForEdit
"BM-single", // m_szName
STEPS_TYPE_BM_SINGLE, // m_NotesType
STEPS_TYPE_BM_SINGLE, // m_StepsType
StyleDef::ONE_PLAYER_ONE_CREDIT, // m_StyleType
{ 160, 480 }, // m_iCenterX
6, // m_iColsPerPlayer
@@ -1594,7 +1594,7 @@ void GameManager::GetStylesForGame( Game game, vector<Style>& aStylesAddTo, bool
Style GameManager::GetEditorStyleForNotesType( StepsType nt )
{
for( int s=0; s<NUM_STYLES; s++ )
if( g_StyleDefs[s].m_NotesType == nt && g_StyleDefs[s].m_bUsedForEdit )
if( g_StyleDefs[s].m_StepsType == nt && g_StyleDefs[s].m_bUsedForEdit )
return (Style)s;
ASSERT(0); // this style doesn't have a StyleDef that can be used with the editor!
@@ -1621,7 +1621,7 @@ void GameManager::GetNotesTypesForGame( Game game, vector<StepsType>& aNotesType
continue;
for( int pl = 0; !found && pl < NUM_PLAYERS; ++pl)
{
if( g_StyleDefs[s].m_NotesType != nt )
if( g_StyleDefs[s].m_StepsType != nt )
continue;
found=true;
+1 -1
View File
@@ -65,7 +65,7 @@ void GrooveGraph::SetFromSong( Song* pSong )
{
for( int i=0; i<NUM_DIFFICULTIES; i++ )
{
Steps* pNotes = pSong->GetNotes( GAMESTATE->GetCurrentStyleDef()->m_NotesType, (Difficulty)i );
Steps* pNotes = pSong->GetNotes( GAMESTATE->GetCurrentStyleDef()->m_StepsType, (Difficulty)i );
const float* fRadarValues = pNotes ? pNotes->GetRadarValues() : NULL;
for( int j=0; j<NUM_RADAR_CATEGORIES; j++ )
fValues[j][i] = fRadarValues ? fRadarValues[j] : 0;
+5 -5
View File
@@ -328,7 +328,7 @@ void MusicWheel::GetSongList(vector<Song*> &arraySongs, SongSortOrder so, CStrin
continue;
vector<Steps*> arraySteps;
pSong->GetNotes( arraySteps, GAMESTATE->GetCurrentStyleDef()->m_NotesType, DIFFICULTY_INVALID, -1, -1, "", PREFSMAN->m_bAutogenMissingTypes );
pSong->GetNotes( arraySteps, GAMESTATE->GetCurrentStyleDef()->m_StepsType, DIFFICULTY_INVALID, -1, -1, "", PREFSMAN->m_bAutogenMissingTypes );
if( !arraySteps.empty() )
arraySongs.push_back( pSong );
@@ -608,7 +608,7 @@ void MusicWheel::BuildWheelItemDatas( vector<WheelItemData> &arrayWheelItemDatas
}
// check that this course has at least one song playable in the current style
if( !pCourse->IsPlayableIn(GAMESTATE->GetCurrentStyleDef()->m_NotesType) )
if( !pCourse->IsPlayableIn(GAMESTATE->GetCurrentStyleDef()->m_StepsType) )
continue;
if( sThisSection != sLastSection ) // new section, make a section item
@@ -1418,21 +1418,21 @@ CString MusicWheel::GetSectionNameFromSongAndSort( const Song* pSong, SongSortOr
}
case SORT_EASY_METER:
{
Steps* pNotes = pSong->GetNotes(GAMESTATE->GetCurrentStyleDef()->m_NotesType,DIFFICULTY_EASY);
Steps* pNotes = pSong->GetNotes(GAMESTATE->GetCurrentStyleDef()->m_StepsType,DIFFICULTY_EASY);
if( pNotes )
return ssprintf("%02d", pNotes->GetMeter() );
return "N/A";
}
case SORT_MEDIUM_METER:
{
Steps* pNotes = pSong->GetNotes(GAMESTATE->GetCurrentStyleDef()->m_NotesType,DIFFICULTY_MEDIUM);
Steps* pNotes = pSong->GetNotes(GAMESTATE->GetCurrentStyleDef()->m_StepsType,DIFFICULTY_MEDIUM);
if( pNotes )
return ssprintf("%02d", pNotes->GetMeter() );
return "N/A";
}
case SORT_HARD_METER:
{
Steps* pNotes = pSong->GetNotes(GAMESTATE->GetCurrentStyleDef()->m_NotesType,DIFFICULTY_HARD);
Steps* pNotes = pSong->GetNotes(GAMESTATE->GetCurrentStyleDef()->m_StepsType,DIFFICULTY_HARD);
if( pNotes )
return ssprintf("%02d", pNotes->GetMeter() );
return "N/A";
-814
View File
@@ -12,14 +12,6 @@
#include "NoteData.h"
#include "RageUtil.h"
#include "GameConstantsAndTypes.h"
#include "ArrowEffects.h"
#include "GameState.h"
#include "RageException.h"
#include "GameState.h"
#include "math.h"
#include "NotesLoaderSM.h"
#include "RageLog.h"
NoteData::NoteData()
@@ -529,809 +521,3 @@ void NoteData::SetTapNote(int track, int row, TapNote t)
m_TapNotes[track][row]=t;
}
NoteType NoteDataUtil::GetSmallestNoteTypeForMeasure( const NoteData &n, int iMeasureIndex )
{
const int iMeasureStartIndex = iMeasureIndex * ROWS_PER_MEASURE;
const int iMeasureLastIndex = (iMeasureIndex+1) * ROWS_PER_MEASURE - 1;
// probe to find the smallest note type
NoteType nt;
for( nt=(NoteType)0; nt<NUM_NOTE_TYPES; nt=NoteType(nt+1) ) // for each NoteType, largest to largest
{
float fBeatSpacing = NoteTypeToBeat( nt );
int iRowSpacing = int(roundf( fBeatSpacing * ROWS_PER_BEAT ));
bool bFoundSmallerNote = false;
for( int i=iMeasureStartIndex; i<=iMeasureLastIndex; i++ ) // for each index in this measure
{
if( i % iRowSpacing == 0 )
continue; // skip
if( !n.IsRowEmpty(i) )
{
bFoundSmallerNote = true;
break;
}
}
if( bFoundSmallerNote )
continue; // searching the next NoteType
else
break; // stop searching. We found the smallest NoteType
}
if( nt == NUM_NOTE_TYPES ) // we didn't find one
return NOTE_TYPE_INVALID; // well-formed notes created in the editor should never get here
else
return nt;
}
void NoteDataUtil::LoadFromSMNoteDataString( NoteData &out, CString sSMNoteData )
{
/* 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 );
}
CStringArray asMeasures;
split( sSMNoteData, ",", asMeasures, true ); // ignore empty is important
for( unsigned m=0; m<asMeasures.size(); m++ ) // foreach measure
{
CString &sMeasureString = asMeasures[m];
TrimLeft(sMeasureString);
TrimRight(sMeasureString);
CStringArray asMeasureLines;
split( sMeasureString, "\n", asMeasureLines, true ); // ignore empty is important
//ASSERT( asMeasureLines.size() == 4 ||
// asMeasureLines.size() == 8 ||
// asMeasureLines.size() == 12 ||
// asMeasureLines.size() == 16 );
for( unsigned l=0; l<asMeasureLines.size(); l++ )
{
CString &sMeasureLine = asMeasureLines[l];
TrimLeft(sMeasureLine);
TrimRight(sMeasureLine);
const float fPercentIntoMeasure = l/(float)asMeasureLines.size();
const float fBeat = (m + fPercentIntoMeasure) * BEATS_PER_MEASURE;
const int iIndex = BeatToNoteRow( fBeat );
// if( m_iNumTracks != sMeasureLine.GetLength() )
// RageException::Throw( "Actual number of note columns (%d) is different from the StepsType (%d).", m_iNumTracks, sMeasureLine.GetLength() );
for( int c=0; c<min(sMeasureLine.GetLength(),out.GetNumTracks()); c++ )
{
TapNote t;
switch(sMeasureLine[c])
{
case '0': t = TAP_EMPTY; break;
case '1': t = TAP_TAP; break;
case '2': t = TAP_HOLD_HEAD; break;
case '3': t = TAP_HOLD_TAIL; break;
default:
/* 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.Convert2sAnd3sToHoldNotes();
}
CString NoteDataUtil::GetSMNoteDataString(NoteData &in)
{
in.ConvertHoldNotesTo2sAnd3s();
float fLastBeat = in.GetLastBeat();
int iLastMeasure = int( fLastBeat/BEATS_PER_MEASURE );
CString sRet;
for( int m=0; m<=iLastMeasure; m++ ) // foreach measure
{
NoteType nt = GetSmallestNoteTypeForMeasure( in, m );
int iRowSpacing;
if( nt == NOTE_TYPE_INVALID )
iRowSpacing = 1;
else
iRowSpacing = int(roundf( NoteTypeToBeat(nt) * ROWS_PER_BEAT ));
sRet += ssprintf(" // measure %d\n", m+1);
const int iMeasureStartRow = m * ROWS_PER_MEASURE;
const int iMeasureLastRow = (m+1) * ROWS_PER_MEASURE - 1;
for( int r=iMeasureStartRow; r<=iMeasureLastRow; r+=iRowSpacing )
{
for( int t=0; t<in.GetNumTracks(); t++ ) {
char c;
switch(in.GetTapNote(t, r)) {
case TAP_EMPTY: c = '0'; break;
case TAP_TAP: c = '1'; break;
case TAP_HOLD_HEAD: c = '2'; break;
case TAP_HOLD_TAIL: c = '3'; break;
default: ASSERT(0); c = '0'; break;
}
sRet.append(1, c);
}
sRet.append(1, '\n');
}
sRet.append(1, ',');
}
in.Convert2sAnd3sToHoldNotes();
return sRet;
}
float NoteDataUtil::GetRadarValue( const NoteData &in, RadarCategory rv, float fSongSeconds )
{
switch( rv )
{
case RADAR_STREAM: return GetStreamRadarValue( in, fSongSeconds );
case RADAR_VOLTAGE: return GetVoltageRadarValue( in, fSongSeconds );
case RADAR_AIR: return GetAirRadarValue( in, fSongSeconds );
case RADAR_FREEZE: return GetFreezeRadarValue( in, fSongSeconds );
case RADAR_CHAOS: return GetChaosRadarValue( in, fSongSeconds );
default: ASSERT(0); return 0;
}
}
float NoteDataUtil::GetStreamRadarValue( const NoteData &in, float fSongSeconds )
{
if( !fSongSeconds )
return 0.0f;
// density of steps
int iNumNotes = in.GetNumTapNotes() + in.GetNumHoldNotes();
float fNotesPerSecond = iNumNotes/fSongSeconds;
float fReturn = fNotesPerSecond / 7;
return min( fReturn, 1.0f );
}
float NoteDataUtil::GetVoltageRadarValue( const NoteData &in, float fSongSeconds )
{
if( !fSongSeconds )
return 0.0f;
const float fLastBeat = in.GetLastBeat();
const float fAvgBPS = fLastBeat / fSongSeconds;
// peak density of steps
float fMaxDensitySoFar = 0;
const int BEAT_WINDOW = 8;
for( int i=0; i<=int(fLastBeat); i+=BEAT_WINDOW )
{
int iNumNotesThisWindow = in.GetNumTapNotes((float)i,(float)i+BEAT_WINDOW) + in.GetNumHoldNotes((float)i,(float)i+BEAT_WINDOW);
float fDensityThisWindow = iNumNotesThisWindow/(float)BEAT_WINDOW;
fMaxDensitySoFar = max( fMaxDensitySoFar, fDensityThisWindow );
}
float fReturn = fMaxDensitySoFar*fAvgBPS/10;
return min( fReturn, 1.0f );
}
float NoteDataUtil::GetAirRadarValue( const NoteData &in, float fSongSeconds )
{
if( !fSongSeconds )
return 0.0f;
// number of doubles
int iNumDoubles = in.GetNumDoubles();
float fReturn = iNumDoubles / fSongSeconds;
return min( fReturn, 1.0f );
}
float NoteDataUtil::GetFreezeRadarValue( const NoteData &in, float fSongSeconds )
{
if( !fSongSeconds )
return 0.0f;
// number of hold steps
float fReturn = in.GetNumHoldNotes() / fSongSeconds;
return min( fReturn, 1.0f );
}
float NoteDataUtil::GetChaosRadarValue( const NoteData &in, float fSongSeconds )
{
if( !fSongSeconds )
return 0.0f;
// count number of triplets or 16ths
int iNumChaosNotes = 0;
int rows = in.GetLastRow();
for( int r=0; r<=rows; r++ )
{
if( !in.IsRowEmpty(r) && GetNoteType(r) >= NOTE_TYPE_12TH )
iNumChaosNotes++;
}
float fReturn = iNumChaosNotes / fSongSeconds * 0.5f;
return min( fReturn, 1.0f );
}
void NoteDataUtil::RemoveHoldNotes(NoteData &in)
{
vector<int> tracks, rows;
// turn all the HoldNotes into TapNotes
for( int i=0; i<in.GetNumHoldNotes(); i++ )
{
const HoldNote &hn = in.GetHoldNote(i);
tracks.push_back(hn.iTrack);
rows.push_back(BeatToNoteRow(hn.fStartBeat));
}
// Remove all HoldNotes
while(in.GetNumHoldNotes())
in.RemoveHoldNote(in.GetNumHoldNotes()-1);
for(unsigned j = 0; j < tracks.size(); ++j)
in.SetTapNote(tracks[j], rows[j], TAP_TAP);
}
void NoteDataUtil::Turn( NoteData &in, TurnType tt )
{
int iTakeFromTrack[MAX_NOTE_TRACKS]; // New track "t" will take from old track iTakeFromTrack[t]
int t;
switch( tt )
{
case left:
case right:
// Is there a way to do this withoutn handling each StepsType? -Chris
// Identity transform for ones not handled below. What should we do here?
for( t = 0; t < MAX_NOTE_TRACKS; ++t )
iTakeFromTrack[t] = t;
switch( GAMESTATE->GetCurrentStyleDef()->m_NotesType )
{
case STEPS_TYPE_DANCE_SINGLE:
case STEPS_TYPE_DANCE_DOUBLE:
case STEPS_TYPE_DANCE_COUPLE:
iTakeFromTrack[0] = 2;
iTakeFromTrack[1] = 0;
iTakeFromTrack[2] = 3;
iTakeFromTrack[3] = 1;
iTakeFromTrack[4] = 6;
iTakeFromTrack[5] = 4;
iTakeFromTrack[6] = 7;
iTakeFromTrack[7] = 5;
break;
case STEPS_TYPE_DANCE_SOLO:
iTakeFromTrack[0] = 5;
iTakeFromTrack[1] = 4;
iTakeFromTrack[2] = 0;
iTakeFromTrack[3] = 3;
iTakeFromTrack[4] = 1;
iTakeFromTrack[5] = 2;
break;
case STEPS_TYPE_PUMP_SINGLE:
case STEPS_TYPE_PUMP_COUPLE:
iTakeFromTrack[0] = 3;
iTakeFromTrack[1] = 4;
iTakeFromTrack[2] = 2;
iTakeFromTrack[3] = 0;
iTakeFromTrack[4] = 1;
iTakeFromTrack[5] = 8;
iTakeFromTrack[6] = 9;
iTakeFromTrack[7] = 7;
iTakeFromTrack[8] = 5;
iTakeFromTrack[9] = 6;
break;
case STEPS_TYPE_PUMP_HALFDOUBLE:
iTakeFromTrack[0] = 2;
iTakeFromTrack[1] = 0;
iTakeFromTrack[2] = 1;
iTakeFromTrack[3] = 3;
iTakeFromTrack[4] = 4;
iTakeFromTrack[5] = 5;
break;
case STEPS_TYPE_PUMP_DOUBLE:
iTakeFromTrack[0] = 8;
iTakeFromTrack[1] = 9;
iTakeFromTrack[2] = 7;
iTakeFromTrack[3] = 5;
iTakeFromTrack[4] = 6;
iTakeFromTrack[5] = 3;
iTakeFromTrack[6] = 4;
iTakeFromTrack[7] = 2;
iTakeFromTrack[8] = 0;
iTakeFromTrack[9] = 1;
break;
default: break;
}
if( tt == right )
{
/* Invert. */
int iTrack[MAX_NOTE_TRACKS];
memcpy( iTrack, iTakeFromTrack, sizeof(iTrack) );
for( t = 0; t < MAX_NOTE_TRACKS; ++t )
{
const int to = iTrack[t];
iTakeFromTrack[to] = t;
}
}
break;
case mirror:
for( t=0; t<in.GetNumTracks(); t++ )
iTakeFromTrack[t] = in.GetNumTracks()-t-1;
break;
case shuffle:
case super_shuffle: // use shuffle code to mix up HoldNotes without creating impossible patterns
{
vector<int> aiTracksLeftToMap;
for( t=0; t<in.GetNumTracks(); t++ )
aiTracksLeftToMap.push_back( t );
for( t=0; t<in.GetNumTracks(); t++ )
{
int iRandTrackIndex = rand()%aiTracksLeftToMap.size();
int iRandTrack = aiTracksLeftToMap[iRandTrackIndex];
aiTracksLeftToMap.erase( aiTracksLeftToMap.begin()+iRandTrackIndex,
aiTracksLeftToMap.begin()+iRandTrackIndex+1 );
iTakeFromTrack[t] = iRandTrack;
}
}
break;
default:
ASSERT(0);
}
NoteData tempNoteData; // write into here as we tranform
tempNoteData.Config(in);
in.ConvertHoldNotesTo2sAnd3s();
// transform notes
int max_row = in.GetLastRow();
for( t=0; t<in.GetNumTracks(); t++ )
for( int r=0; r<=max_row; r++ )
tempNoteData.SetTapNote(t, r, in.GetTapNote(iTakeFromTrack[t], r));
in.CopyAll( &tempNoteData ); // copy note data from newData back into this
in.Convert2sAnd3sToHoldNotes();
if( tt == super_shuffle )
SuperShuffleTaps( in );
}
void NoteDataUtil::SuperShuffleTaps( NoteData &in )
{
// We already did the normal shuffling code above, which did a good job
// of shuffling HoldNotes without creating impossible patterns.
// Now, go in and shuffle the TapNotes per-row.
in.ConvertHoldNotesTo4s();
int max_row = in.GetLastRow();
for( int r=0; r<=max_row; r++ )
{
for( int t1=0; t1<in.GetNumTracks(); t1++ )
{
TapNote tn1 = in.GetTapNote(t1, r);
if( tn1!=TAP_HOLD ) // a tap that is not part of a hold
{
// probe for a spot to swap with
while( 1 )
{
int t2 = rand() % in.GetNumTracks();
TapNote tn2 = in.GetTapNote(t2, r);
if( tn2!=TAP_HOLD ) // a tap that is not part of a hold
{
// swap
in.SetTapNote(t1, r, tn2);
in.SetTapNote(t2, r, tn1);
break;
}
}
}
}
}
in.Convert4sToHoldNotes();
}
void NoteDataUtil::Backwards( NoteData &in )
{
in.ConvertHoldNotesTo4s();
int max_row = in.GetLastRow();
for( int r=0; r<=max_row/2; r++ )
{
int iRowEarlier = r;
int iRowLater = max_row-r;
for( int t=0; t<in.GetNumTracks(); t++ )
{
TapNote tnEarlier = in.GetTapNote(t, iRowEarlier);
TapNote tnLater = in.GetTapNote(t, iRowLater);
in.SetTapNote(t, iRowEarlier, tnLater);
in.SetTapNote(t, iRowLater, tnEarlier);
}
}
in.Convert4sToHoldNotes();
}
void NoteDataUtil::SwapSides( NoteData &in )
{
in.ConvertHoldNotesTo4s();
int max_row = in.GetLastRow();
for( int r=0; r<=max_row; r++ )
{
for( int t=0; t<in.GetNumTracks()/2; t++ )
{
int iTrackEarlier = t;
int iTrackLater = t + in.GetNumTracks()/2 + in.GetNumTracks()%2;
// swap
TapNote tnEarlier = in.GetTapNote(iTrackEarlier, r);
TapNote tnLater = in.GetTapNote(iTrackLater, r);
in.SetTapNote(iTrackEarlier, r, tnLater);
in.SetTapNote(iTrackLater, r, tnEarlier);
}
}
in.Convert4sToHoldNotes();
}
void NoteDataUtil::Little(NoteData &in)
{
int i;
// filter out all non-quarter notes
int max_row = in.GetLastRow();
for( i=0; i<=max_row; i+=1 )
if( i % ROWS_PER_BEAT != 0 )
for( int c=0; c<in.GetNumTracks(); c++ )
in.SetTapNote(c, i, TAP_EMPTY);
for( i=in.GetNumHoldNotes()-1; i>=0; i-- )
if( fmodf(in.GetHoldNote(i).fStartBeat,1) != 0 ) // doesn't start on a beat
in.RemoveHoldNote( i );
}
void NoteDataUtil::Wide( NoteData &in )
{
in.ConvertHoldNotesTo4s();
// make all all quarter notes jumps
int max_row = in.GetLastRow();
for( int i=0; i<=max_row; i+=ROWS_PER_BEAT*2 ) // every even beat
{
if( in.GetNumTapNonEmptyTracks(i) != 1 )
continue; // skip. Don't place during holds
if( in.GetNumTracksWithTap(i) != 1 )
continue; // skip
bool bSpaceAroundIsEmpty = true; // no other notes with a 1/8th of this row
for( int j=i-ROWS_PER_BEAT/2+1; j<i+ROWS_PER_BEAT/2-1; j++ )
if( j!=i && in.GetNumTapNonEmptyTracks(j) > 0 )
{
bSpaceAroundIsEmpty = false;
break;
}
if( !bSpaceAroundIsEmpty )
continue; // skip
// add a note determinitsitcally
int iBeat = (int)roundf( NoteRowToBeat(i) );
int iTrackOfNote = in.GetFirstTrackWithTap(i);
int iTrackToAdd = iTrackOfNote + (iBeat%5)-2; // won't be more than 2 tracks away from the existing note
CLAMP( iTrackToAdd, 0, in.GetNumTracks()-1 );
if( iTrackToAdd == iTrackOfNote )
iTrackToAdd++;
CLAMP( iTrackToAdd, 0, in.GetNumTracks()-1 );
if( iTrackToAdd == iTrackOfNote )
iTrackToAdd--;
CLAMP( iTrackToAdd, 0, in.GetNumTracks()-1 );
if( in.GetTapNote(iTrackToAdd, i) != TAP_EMPTY )
{
iTrackToAdd = (iTrackToAdd+1) % in.GetNumTracks();
}
in.SetTapNote(iTrackToAdd, i, TAP_TAP);
}
in.Convert4sToHoldNotes();
}
void NoteDataUtil::Big( NoteData &in )
{
InsertIntelligentTaps(in,1.0f,0.5f,false); // add 8ths between 4ths
}
void NoteDataUtil::Quick( NoteData &in )
{
InsertIntelligentTaps(in,0.5f,0.25f,false); // add 16ths between 8ths
}
void NoteDataUtil::Skippy( NoteData &in )
{
InsertIntelligentTaps(in,1.0f,0.75f,true); // add 16ths between 4ths
}
void NoteDataUtil::InsertIntelligentTaps( NoteData &in, float fBeatInterval, float fInsertBeatOffset, bool bNewTapSameAsBeginning )
{
ASSERT( fInsertBeatOffset <= fBeatInterval );
in.ConvertHoldNotesTo4s();
// insert a beat in the middle of every fBeatInterval
int max_row = in.GetLastRow();
int rows_per_interval = BeatToNoteRow( fBeatInterval );
int insert_row_offset = BeatToNoteRow( fInsertBeatOffset );
for( int i=0; i<=max_row; i+=rows_per_interval )
{
int iRowEarlier = i;
int iRowLater = i + rows_per_interval;
int iRowToAdd = i + insert_row_offset;
if( in.GetNumTapNonEmptyTracks(iRowEarlier)!=1 || in.GetNumTracksWithTap(iRowEarlier)!=1 )
continue;
if( in.GetNumTapNonEmptyTracks(iRowLater)!=1 || in.GetNumTracksWithTap(iRowLater)!=1 )
continue;
// there is a 4th and 8th note surrounding iRowBetween
// don't insert a new note if there's already one within this interval
bool bNoteInMiddle = false;
for( int j=iRowEarlier+1; j<=iRowLater-1; j++ )
if( !in.IsRowEmpty(j) )
{
bNoteInMiddle = true;
break;
}
if( bNoteInMiddle )
continue;
// add a note determinitsitcally somewhere on a track different from the two surrounding notes
int iTrackOfNoteEarlier = in.GetFirstNonEmptyTrack(iRowEarlier);
int iTrackOfNoteLater = in.GetFirstNonEmptyTrack(iRowLater);
int iTrackOfNoteToAdd = 0;
if( bNewTapSameAsBeginning &&
iTrackOfNoteEarlier != iTrackOfNoteLater ) // Don't make skips on the same note
{
iTrackOfNoteToAdd = iTrackOfNoteEarlier;
}
else // bNewTapSameAsBeginning
{
// choose a randomish track
if( abs(iTrackOfNoteEarlier-iTrackOfNoteLater) == 2 )
iTrackOfNoteToAdd = (iTrackOfNoteEarlier+iTrackOfNoteLater)/2;
else
{
for( int t=min(iTrackOfNoteEarlier,iTrackOfNoteLater)-1; t<=max(iTrackOfNoteEarlier,iTrackOfNoteLater)+1; t++ )
{
iTrackOfNoteToAdd = t;
CLAMP( iTrackOfNoteToAdd, 0, in.GetNumTracks()-1 );
if( iTrackOfNoteToAdd!=iTrackOfNoteEarlier && iTrackOfNoteToAdd!=iTrackOfNoteLater )
break;
}
}
}
in.SetTapNote(iTrackOfNoteToAdd, iRowToAdd, TAP_TAP);
}
in.Convert4sToHoldNotes();
}
void NoteDataUtil::SnapToNearestNoteType( NoteData &in, NoteType nt1, NoteType nt2, float fBeginBeat, float fEndBeat )
{
// nt2 is optional and should be -1 if it is not used
float fSnapInterval1, fSnapInterval2;
switch( nt1 )
{
case NOTE_TYPE_4TH: fSnapInterval1 = 1/1.0f; break;
case NOTE_TYPE_8TH: fSnapInterval1 = 1/2.0f; break;
case NOTE_TYPE_12TH: fSnapInterval1 = 1/3.0f; break;
case NOTE_TYPE_16TH: fSnapInterval1 = 1/4.0f; break;
case NOTE_TYPE_24TH: fSnapInterval1 = 1/6.0f; break;
case NOTE_TYPE_32ND: fSnapInterval1 = 1/8.0f; break;
default: ASSERT( false ); return;
}
switch( nt2 )
{
case NOTE_TYPE_4TH: fSnapInterval2 = 1/1.0f; break;
case NOTE_TYPE_8TH: fSnapInterval2 = 1/2.0f; break;
case NOTE_TYPE_12TH: fSnapInterval2 = 1/3.0f; break;
case NOTE_TYPE_16TH: fSnapInterval2 = 1/4.0f; break;
case NOTE_TYPE_24TH: fSnapInterval2 = 1/6.0f; break;
case NOTE_TYPE_32ND: fSnapInterval2 = 1/8.0f; break;
case -1: fSnapInterval2 = 10000; break; // nothing will ever snap to this. That's what we want!
default: ASSERT( false ); return;
}
int iNoteIndexBegin = BeatToNoteRow( fBeginBeat );
int iNoteIndexEnd = BeatToNoteRow( fEndBeat );
in.ConvertHoldNotesTo2sAnd3s();
// iterate over all TapNotes in the interval and snap them
for( int i=iNoteIndexBegin; i<=iNoteIndexEnd; i++ )
{
LOG->Trace("index %i", i);
int iOldIndex = i;
float fOldBeat = NoteRowToBeat( iOldIndex );
float fNewBeat1 = froundf( fOldBeat, fSnapInterval1 );
float fNewBeat2 = froundf( fOldBeat, fSnapInterval2 );
LOG->Trace("oldbeat %.2f, nb1 %.2f, nb2 %.2f", fOldBeat, fNewBeat1, fNewBeat2);
bool bNewBeat1IsCloser = fabsf(fNewBeat1-fOldBeat) < fabsf(fNewBeat2-fOldBeat);
float fNewBeat = bNewBeat1IsCloser ? fNewBeat1 : fNewBeat2;
int iNewIndex = BeatToNoteRow( fNewBeat );
LOG->Trace("closer %i, newbeat %.2f, index %i",
bNewBeat1IsCloser, fNewBeat, iNewIndex);
for( int c=0; c<in.GetNumTracks(); c++ )
{
if( iOldIndex == iNewIndex )
continue;
TapNote note = in.GetTapNote(c, iOldIndex);
if( note == TAP_EMPTY )
continue;
in.SetTapNote(c, iOldIndex, TAP_EMPTY);
const TapNote oldnote = in.GetTapNote(c, iNewIndex);
if( note == TAP_TAP &&
(oldnote == TAP_HOLD_HEAD || oldnote == TAP_HOLD_TAIL) )
continue; // HoldNotes override TapNotes
/* If two hold note boundaries are getting snapped together,
* merge them. */
if( (note == TAP_HOLD_HEAD && oldnote == TAP_HOLD_TAIL) ||
(note == TAP_HOLD_TAIL && oldnote == TAP_HOLD_HEAD))
note = TAP_EMPTY;
in.SetTapNote(c, iNewIndex, note );
}
}
in.Convert2sAnd3sToHoldNotes();
}
void NoteDataUtil::CopyLeftToRight( NoteData &in )
{
in.ConvertHoldNotesTo4s();
int max_row = in.GetLastRow();
for( int r=0; r<=max_row; r++ )
{
for( int t=0; t<in.GetNumTracks()/2; t++ )
{
int iTrackEarlier = t;
int iTrackLater = in.GetNumTracks()-1-t;
// swap
TapNote tnEarlier = in.GetTapNote(iTrackEarlier, r);
// TapNote tnLater = in.GetTapNote(iTrackLater, r);
// in.SetTapNote(iTrackEarlier, r, tnLater);
in.SetTapNote(iTrackLater, r, tnEarlier);
}
}
in.Convert4sToHoldNotes();
}
void NoteDataUtil::CopyRightToLeft( NoteData &in )
{
in.ConvertHoldNotesTo4s();
int max_row = in.GetLastRow();
for( int r=0; r<=max_row; r++ )
{
for( int t=0; t<in.GetNumTracks()/2; t++ )
{
int iTrackEarlier = t;
int iTrackLater = in.GetNumTracks()-1-t;
// swap
// TapNote tnEarlier = in.GetTapNote(iTrackEarlier, r);
TapNote tnLater = in.GetTapNote(iTrackLater, r);
in.SetTapNote(iTrackEarlier, r, tnLater);
// in.SetTapNote(iTrackLater, r, tnEarlier);
}
}
in.Convert4sToHoldNotes();
}
void NoteDataUtil::ClearLeft( NoteData &in )
{
in.ConvertHoldNotesTo4s();
int max_row = in.GetLastRow();
for( int r=0; r<=max_row; r++ )
for( int t=0; t<in.GetNumTracks()/2; t++ )
in.SetTapNote(t, r, TAP_EMPTY);
in.Convert4sToHoldNotes();
}
void NoteDataUtil::ClearRight( NoteData &in )
{
in.ConvertHoldNotesTo4s();
int max_row = in.GetLastRow();
for( int r=0; r<=max_row; r++ )
for( int t=(in.GetNumTracks()+1)/2; t<in.GetNumTracks(); t++ )
in.SetTapNote(t, r, TAP_EMPTY);
in.Convert4sToHoldNotes();
}
void NoteDataUtil::CollapseToOne( NoteData &in )
{
in.ConvertHoldNotesTo2sAnd3s();
int max_row = in.GetLastRow();
for( int r=0; r<=max_row; r++ )
for( int t=0; t<in.GetNumTracks(); t++ )
if( in.GetTapNote(t,r) != TAP_EMPTY )
{
in.SetTapNote(0, r, in.GetTapNote(t,r));
in.SetTapNote(t, r, TAP_EMPTY);
}
in.Convert2sAnd3sToHoldNotes();
}
void NoteDataUtil::ShiftLeft( NoteData &in )
{
in.ConvertHoldNotesTo4s();
int max_row = in.GetLastRow();
for( int r=0; r<=max_row; r++ )
{
for( int t=0; t<in.GetNumTracks()-1; t++ ) // in.GetNumTracks()-1 times
{
int iTrackEarlier = t;
int iTrackLater = (t+1) % in.GetNumTracks();
// swap
TapNote tnEarlier = in.GetTapNote(iTrackEarlier, r);
TapNote tnLater = in.GetTapNote(iTrackLater, r);
in.SetTapNote(iTrackEarlier, r, tnLater);
in.SetTapNote(iTrackLater, r, tnEarlier);
}
}
in.Convert4sToHoldNotes();
}
void NoteDataUtil::ShiftRight( NoteData &in )
{
in.ConvertHoldNotesTo4s();
int max_row = in.GetLastRow();
for( int r=0; r<=max_row; r++ )
{
for( int t=in.GetNumTracks()-1; t>0; t-- ) // in.GetNumTracks()-1 times
{
int iTrackEarlier = t;
int iTrackLater = (t+1) % in.GetNumTracks();
// swap
TapNote tnEarlier = in.GetTapNote(iTrackEarlier, r);
TapNote tnLater = in.GetTapNote(iTrackLater, r);
in.SetTapNote(iTrackEarlier, r, tnLater);
in.SetTapNote(iTrackLater, r, tnEarlier);
}
}
in.Convert4sToHoldNotes();
}
+1 -45
View File
@@ -14,7 +14,7 @@
-----------------------------------------------------------------------------
*/
#include "GameConstantsAndTypes.h"
//#include "GameConstantsAndTypes.h"
#include "NoteTypes.h"
// '1' = tap note
@@ -135,49 +135,5 @@ public:
void ConvertHoldNotesTo4s();
};
/* Utils for NoteData. Things should go in here if they can be (cleanly and
* efficiently) implemented using only NoteData's primitives; this improves
* abstraction and makes it much easier to change NoteData internally in
* the future. */
namespace NoteDataUtil
{
NoteType GetSmallestNoteTypeForMeasure( const NoteData &n, int iMeasureIndex );
void LoadFromSMNoteDataString( NoteData &out, CString sSMNoteData );
CString GetSMNoteDataString(NoteData &in);
float GetStreamRadarValue( const NoteData &in, float fSongSeconds );
float GetVoltageRadarValue( const NoteData &in, float fSongSeconds );
float GetAirRadarValue( const NoteData &in, float fSongSeconds );
float GetFreezeRadarValue( const NoteData &in, float fSongSeconds );
float GetChaosRadarValue( const NoteData &in, float fSongSeconds );
// radar values - return between 0.0 and 1.2
float GetRadarValue( const NoteData &in, RadarCategory rv, float fSongSeconds );
void RemoveHoldNotes( NoteData &in );
enum TurnType { left, right, mirror, shuffle, super_shuffle, NUM_TURN_TYPES };
void Turn( NoteData &in, TurnType tt );
void Little( NoteData &in );
void Wide( NoteData &in );
void Big( NoteData &in );
void Quick( NoteData &in );
void Skippy( NoteData &in );
void InsertIntelligentTaps( NoteData &in, float fBeatInterval, float fInsertBeatOffset, bool bNewTapSameAsBeginning );
void SuperShuffleTaps( NoteData &in );
void Backwards( NoteData &in );
void SwapSides( NoteData &in );
void CopyLeftToRight( NoteData &in );
void CopyRightToLeft( NoteData &in );
void ClearLeft( NoteData &in );
void ClearRight( NoteData &in );
void CollapseToOne( NoteData &in );
void ShiftLeft( NoteData &in );
void ShiftRight( NoteData &in );
void SnapToNearestNoteType( NoteData &in, NoteType nt1, NoteType nt2, float fBeginBeat, float fEndBeat );
inline void SnapToNearestNoteType( NoteData &in, NoteType nt, float fBeginBeat, float fEndBeat ) { SnapToNearestNoteType( in, nt, (NoteType)-1, fBeginBeat, fEndBeat ); }
};
#endif
+831
View File
@@ -0,0 +1,831 @@
#include "global.h"
/*
-----------------------------------------------------------------------------
Class: NoteDataUtil
Desc: See header.
Copyright (c) 2001-2002 by the person(s) listed below. All rights reserved.
Chris Danford
-----------------------------------------------------------------------------
*/
#include "NoteDataUtil.h"
#include "RageUtil.h"
#include "RageLog.h"
NoteType NoteDataUtil::GetSmallestNoteTypeForMeasure( const NoteData &n, int iMeasureIndex )
{
const int iMeasureStartIndex = iMeasureIndex * ROWS_PER_MEASURE;
const int iMeasureLastIndex = (iMeasureIndex+1) * ROWS_PER_MEASURE - 1;
// probe to find the smallest note type
NoteType nt;
for( nt=(NoteType)0; nt<NUM_NOTE_TYPES; nt=NoteType(nt+1) ) // for each NoteType, largest to largest
{
float fBeatSpacing = NoteTypeToBeat( nt );
int iRowSpacing = int(roundf( fBeatSpacing * ROWS_PER_BEAT ));
bool bFoundSmallerNote = false;
for( int i=iMeasureStartIndex; i<=iMeasureLastIndex; i++ ) // for each index in this measure
{
if( i % iRowSpacing == 0 )
continue; // skip
if( !n.IsRowEmpty(i) )
{
bFoundSmallerNote = true;
break;
}
}
if( bFoundSmallerNote )
continue; // searching the next NoteType
else
break; // stop searching. We found the smallest NoteType
}
if( nt == NUM_NOTE_TYPES ) // we didn't find one
return NOTE_TYPE_INVALID; // well-formed notes created in the editor should never get here
else
return nt;
}
void NoteDataUtil::LoadFromSMNoteDataString( NoteData &out, CString sSMNoteData )
{
/* 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 );
}
CStringArray asMeasures;
split( sSMNoteData, ",", asMeasures, true ); // ignore empty is important
for( unsigned m=0; m<asMeasures.size(); m++ ) // foreach measure
{
CString &sMeasureString = asMeasures[m];
TrimLeft(sMeasureString);
TrimRight(sMeasureString);
CStringArray asMeasureLines;
split( sMeasureString, "\n", asMeasureLines, true ); // ignore empty is important
//ASSERT( asMeasureLines.size() == 4 ||
// asMeasureLines.size() == 8 ||
// asMeasureLines.size() == 12 ||
// asMeasureLines.size() == 16 );
for( unsigned l=0; l<asMeasureLines.size(); l++ )
{
CString &sMeasureLine = asMeasureLines[l];
TrimLeft(sMeasureLine);
TrimRight(sMeasureLine);
const float fPercentIntoMeasure = l/(float)asMeasureLines.size();
const float fBeat = (m + fPercentIntoMeasure) * BEATS_PER_MEASURE;
const int iIndex = BeatToNoteRow( fBeat );
// if( m_iNumTracks != sMeasureLine.GetLength() )
// RageException::Throw( "Actual number of note columns (%d) is different from the StepsType (%d).", m_iNumTracks, sMeasureLine.GetLength() );
for( int c=0; c<min(sMeasureLine.GetLength(),out.GetNumTracks()); c++ )
{
TapNote t;
switch(sMeasureLine[c])
{
case '0': t = TAP_EMPTY; break;
case '1': t = TAP_TAP; break;
case '2': t = TAP_HOLD_HEAD; break;
case '3': t = TAP_HOLD_TAIL; break;
default:
/* 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.Convert2sAnd3sToHoldNotes();
}
CString NoteDataUtil::GetSMNoteDataString(NoteData &in)
{
in.ConvertHoldNotesTo2sAnd3s();
float fLastBeat = in.GetLastBeat();
int iLastMeasure = int( fLastBeat/BEATS_PER_MEASURE );
CString sRet;
for( int m=0; m<=iLastMeasure; m++ ) // foreach measure
{
NoteType nt = GetSmallestNoteTypeForMeasure( in, m );
int iRowSpacing;
if( nt == NOTE_TYPE_INVALID )
iRowSpacing = 1;
else
iRowSpacing = int(roundf( NoteTypeToBeat(nt) * ROWS_PER_BEAT ));
sRet += ssprintf(" // measure %d\n", m+1);
const int iMeasureStartRow = m * ROWS_PER_MEASURE;
const int iMeasureLastRow = (m+1) * ROWS_PER_MEASURE - 1;
for( int r=iMeasureStartRow; r<=iMeasureLastRow; r+=iRowSpacing )
{
for( int t=0; t<in.GetNumTracks(); t++ ) {
char c;
switch(in.GetTapNote(t, r)) {
case TAP_EMPTY: c = '0'; break;
case TAP_TAP: c = '1'; break;
case TAP_HOLD_HEAD: c = '2'; break;
case TAP_HOLD_TAIL: c = '3'; break;
default: ASSERT(0); c = '0'; break;
}
sRet.append(1, c);
}
sRet.append(1, '\n');
}
sRet.append(1, ',');
}
in.Convert2sAnd3sToHoldNotes();
return sRet;
}
float NoteDataUtil::GetRadarValue( const NoteData &in, RadarCategory rv, float fSongSeconds )
{
switch( rv )
{
case RADAR_STREAM: return GetStreamRadarValue( in, fSongSeconds );
case RADAR_VOLTAGE: return GetVoltageRadarValue( in, fSongSeconds );
case RADAR_AIR: return GetAirRadarValue( in, fSongSeconds );
case RADAR_FREEZE: return GetFreezeRadarValue( in, fSongSeconds );
case RADAR_CHAOS: return GetChaosRadarValue( in, fSongSeconds );
default: ASSERT(0); return 0;
}
}
float NoteDataUtil::GetStreamRadarValue( const NoteData &in, float fSongSeconds )
{
if( !fSongSeconds )
return 0.0f;
// density of steps
int iNumNotes = in.GetNumTapNotes() + in.GetNumHoldNotes();
float fNotesPerSecond = iNumNotes/fSongSeconds;
float fReturn = fNotesPerSecond / 7;
return min( fReturn, 1.0f );
}
float NoteDataUtil::GetVoltageRadarValue( const NoteData &in, float fSongSeconds )
{
if( !fSongSeconds )
return 0.0f;
const float fLastBeat = in.GetLastBeat();
const float fAvgBPS = fLastBeat / fSongSeconds;
// peak density of steps
float fMaxDensitySoFar = 0;
const int BEAT_WINDOW = 8;
for( int i=0; i<=int(fLastBeat); i+=BEAT_WINDOW )
{
int iNumNotesThisWindow = in.GetNumTapNotes((float)i,(float)i+BEAT_WINDOW) + in.GetNumHoldNotes((float)i,(float)i+BEAT_WINDOW);
float fDensityThisWindow = iNumNotesThisWindow/(float)BEAT_WINDOW;
fMaxDensitySoFar = max( fMaxDensitySoFar, fDensityThisWindow );
}
float fReturn = fMaxDensitySoFar*fAvgBPS/10;
return min( fReturn, 1.0f );
}
float NoteDataUtil::GetAirRadarValue( const NoteData &in, float fSongSeconds )
{
if( !fSongSeconds )
return 0.0f;
// number of doubles
int iNumDoubles = in.GetNumDoubles();
float fReturn = iNumDoubles / fSongSeconds;
return min( fReturn, 1.0f );
}
float NoteDataUtil::GetFreezeRadarValue( const NoteData &in, float fSongSeconds )
{
if( !fSongSeconds )
return 0.0f;
// number of hold steps
float fReturn = in.GetNumHoldNotes() / fSongSeconds;
return min( fReturn, 1.0f );
}
float NoteDataUtil::GetChaosRadarValue( const NoteData &in, float fSongSeconds )
{
if( !fSongSeconds )
return 0.0f;
// count number of triplets or 16ths
int iNumChaosNotes = 0;
int rows = in.GetLastRow();
for( int r=0; r<=rows; r++ )
{
if( !in.IsRowEmpty(r) && GetNoteType(r) >= NOTE_TYPE_12TH )
iNumChaosNotes++;
}
float fReturn = iNumChaosNotes / fSongSeconds * 0.5f;
return min( fReturn, 1.0f );
}
void NoteDataUtil::RemoveHoldNotes(NoteData &in)
{
vector<int> tracks, rows;
// turn all the HoldNotes into TapNotes
for( int i=0; i<in.GetNumHoldNotes(); i++ )
{
const HoldNote &hn = in.GetHoldNote(i);
tracks.push_back(hn.iTrack);
rows.push_back(BeatToNoteRow(hn.fStartBeat));
}
// Remove all HoldNotes
while(in.GetNumHoldNotes())
in.RemoveHoldNote(in.GetNumHoldNotes()-1);
for(unsigned j = 0; j < tracks.size(); ++j)
in.SetTapNote(tracks[j], rows[j], TAP_TAP);
}
void NoteDataUtil::Turn( NoteData &in, StepsType st, TurnType tt )
{
int iTakeFromTrack[MAX_NOTE_TRACKS]; // New track "t" will take from old track iTakeFromTrack[t]
int t;
switch( tt )
{
case left:
case right:
// Is there a way to do this withoutn handling each StepsType? -Chris
// Identity transform for ones not handled below. What should we do here?
for( t = 0; t < MAX_NOTE_TRACKS; ++t )
iTakeFromTrack[t] = t;
switch( st )
{
case STEPS_TYPE_DANCE_SINGLE:
case STEPS_TYPE_DANCE_DOUBLE:
case STEPS_TYPE_DANCE_COUPLE:
iTakeFromTrack[0] = 2;
iTakeFromTrack[1] = 0;
iTakeFromTrack[2] = 3;
iTakeFromTrack[3] = 1;
iTakeFromTrack[4] = 6;
iTakeFromTrack[5] = 4;
iTakeFromTrack[6] = 7;
iTakeFromTrack[7] = 5;
break;
case STEPS_TYPE_DANCE_SOLO:
iTakeFromTrack[0] = 5;
iTakeFromTrack[1] = 4;
iTakeFromTrack[2] = 0;
iTakeFromTrack[3] = 3;
iTakeFromTrack[4] = 1;
iTakeFromTrack[5] = 2;
break;
case STEPS_TYPE_PUMP_SINGLE:
case STEPS_TYPE_PUMP_COUPLE:
iTakeFromTrack[0] = 3;
iTakeFromTrack[1] = 4;
iTakeFromTrack[2] = 2;
iTakeFromTrack[3] = 0;
iTakeFromTrack[4] = 1;
iTakeFromTrack[5] = 8;
iTakeFromTrack[6] = 9;
iTakeFromTrack[7] = 7;
iTakeFromTrack[8] = 5;
iTakeFromTrack[9] = 6;
break;
case STEPS_TYPE_PUMP_HALFDOUBLE:
iTakeFromTrack[0] = 2;
iTakeFromTrack[1] = 0;
iTakeFromTrack[2] = 1;
iTakeFromTrack[3] = 3;
iTakeFromTrack[4] = 4;
iTakeFromTrack[5] = 5;
break;
case STEPS_TYPE_PUMP_DOUBLE:
iTakeFromTrack[0] = 8;
iTakeFromTrack[1] = 9;
iTakeFromTrack[2] = 7;
iTakeFromTrack[3] = 5;
iTakeFromTrack[4] = 6;
iTakeFromTrack[5] = 3;
iTakeFromTrack[6] = 4;
iTakeFromTrack[7] = 2;
iTakeFromTrack[8] = 0;
iTakeFromTrack[9] = 1;
break;
default: break;
}
if( tt == right )
{
/* Invert. */
int iTrack[MAX_NOTE_TRACKS];
memcpy( iTrack, iTakeFromTrack, sizeof(iTrack) );
for( t = 0; t < MAX_NOTE_TRACKS; ++t )
{
const int to = iTrack[t];
iTakeFromTrack[to] = t;
}
}
break;
case mirror:
for( t=0; t<in.GetNumTracks(); t++ )
iTakeFromTrack[t] = in.GetNumTracks()-t-1;
break;
case shuffle:
case super_shuffle: // use shuffle code to mix up HoldNotes without creating impossible patterns
{
vector<int> aiTracksLeftToMap;
for( t=0; t<in.GetNumTracks(); t++ )
aiTracksLeftToMap.push_back( t );
for( t=0; t<in.GetNumTracks(); t++ )
{
int iRandTrackIndex = rand()%aiTracksLeftToMap.size();
int iRandTrack = aiTracksLeftToMap[iRandTrackIndex];
aiTracksLeftToMap.erase( aiTracksLeftToMap.begin()+iRandTrackIndex,
aiTracksLeftToMap.begin()+iRandTrackIndex+1 );
iTakeFromTrack[t] = iRandTrack;
}
}
break;
default:
ASSERT(0);
}
NoteData tempNoteData; // write into here as we tranform
tempNoteData.Config(in);
in.ConvertHoldNotesTo2sAnd3s();
// transform notes
int max_row = in.GetLastRow();
for( t=0; t<in.GetNumTracks(); t++ )
for( int r=0; r<=max_row; r++ )
tempNoteData.SetTapNote(t, r, in.GetTapNote(iTakeFromTrack[t], r));
in.CopyAll( &tempNoteData ); // copy note data from newData back into this
in.Convert2sAnd3sToHoldNotes();
if( tt == super_shuffle )
SuperShuffleTaps( in );
}
void NoteDataUtil::SuperShuffleTaps( NoteData &in )
{
// We already did the normal shuffling code above, which did a good job
// of shuffling HoldNotes without creating impossible patterns.
// Now, go in and shuffle the TapNotes per-row.
in.ConvertHoldNotesTo4s();
int max_row = in.GetLastRow();
for( int r=0; r<=max_row; r++ )
{
for( int t1=0; t1<in.GetNumTracks(); t1++ )
{
TapNote tn1 = in.GetTapNote(t1, r);
if( tn1!=TAP_HOLD ) // a tap that is not part of a hold
{
// probe for a spot to swap with
while( 1 )
{
int t2 = rand() % in.GetNumTracks();
TapNote tn2 = in.GetTapNote(t2, r);
if( tn2!=TAP_HOLD ) // a tap that is not part of a hold
{
// swap
in.SetTapNote(t1, r, tn2);
in.SetTapNote(t2, r, tn1);
break;
}
}
}
}
}
in.Convert4sToHoldNotes();
}
void NoteDataUtil::Backwards( NoteData &in )
{
in.ConvertHoldNotesTo4s();
int max_row = in.GetLastRow();
for( int r=0; r<=max_row/2; r++ )
{
int iRowEarlier = r;
int iRowLater = max_row-r;
for( int t=0; t<in.GetNumTracks(); t++ )
{
TapNote tnEarlier = in.GetTapNote(t, iRowEarlier);
TapNote tnLater = in.GetTapNote(t, iRowLater);
in.SetTapNote(t, iRowEarlier, tnLater);
in.SetTapNote(t, iRowLater, tnEarlier);
}
}
in.Convert4sToHoldNotes();
}
void NoteDataUtil::SwapSides( NoteData &in )
{
in.ConvertHoldNotesTo4s();
int max_row = in.GetLastRow();
for( int r=0; r<=max_row; r++ )
{
for( int t=0; t<in.GetNumTracks()/2; t++ )
{
int iTrackEarlier = t;
int iTrackLater = t + in.GetNumTracks()/2 + in.GetNumTracks()%2;
// swap
TapNote tnEarlier = in.GetTapNote(iTrackEarlier, r);
TapNote tnLater = in.GetTapNote(iTrackLater, r);
in.SetTapNote(iTrackEarlier, r, tnLater);
in.SetTapNote(iTrackLater, r, tnEarlier);
}
}
in.Convert4sToHoldNotes();
}
void NoteDataUtil::Little(NoteData &in)
{
int i;
// filter out all non-quarter notes
int max_row = in.GetLastRow();
for( i=0; i<=max_row; i+=1 )
if( i % ROWS_PER_BEAT != 0 )
for( int c=0; c<in.GetNumTracks(); c++ )
in.SetTapNote(c, i, TAP_EMPTY);
for( i=in.GetNumHoldNotes()-1; i>=0; i-- )
if( fmodf(in.GetHoldNote(i).fStartBeat,1) != 0 ) // doesn't start on a beat
in.RemoveHoldNote( i );
}
void NoteDataUtil::Wide( NoteData &in )
{
in.ConvertHoldNotesTo4s();
// make all all quarter notes jumps
int max_row = in.GetLastRow();
for( int i=0; i<=max_row; i+=ROWS_PER_BEAT*2 ) // every even beat
{
if( in.GetNumTapNonEmptyTracks(i) != 1 )
continue; // skip. Don't place during holds
if( in.GetNumTracksWithTap(i) != 1 )
continue; // skip
bool bSpaceAroundIsEmpty = true; // no other notes with a 1/8th of this row
for( int j=i-ROWS_PER_BEAT/2+1; j<i+ROWS_PER_BEAT/2-1; j++ )
if( j!=i && in.GetNumTapNonEmptyTracks(j) > 0 )
{
bSpaceAroundIsEmpty = false;
break;
}
if( !bSpaceAroundIsEmpty )
continue; // skip
// add a note determinitsitcally
int iBeat = (int)roundf( NoteRowToBeat(i) );
int iTrackOfNote = in.GetFirstTrackWithTap(i);
int iTrackToAdd = iTrackOfNote + (iBeat%5)-2; // won't be more than 2 tracks away from the existing note
CLAMP( iTrackToAdd, 0, in.GetNumTracks()-1 );
if( iTrackToAdd == iTrackOfNote )
iTrackToAdd++;
CLAMP( iTrackToAdd, 0, in.GetNumTracks()-1 );
if( iTrackToAdd == iTrackOfNote )
iTrackToAdd--;
CLAMP( iTrackToAdd, 0, in.GetNumTracks()-1 );
if( in.GetTapNote(iTrackToAdd, i) != TAP_EMPTY )
{
iTrackToAdd = (iTrackToAdd+1) % in.GetNumTracks();
}
in.SetTapNote(iTrackToAdd, i, TAP_TAP);
}
in.Convert4sToHoldNotes();
}
void NoteDataUtil::Big( NoteData &in )
{
InsertIntelligentTaps(in,1.0f,0.5f,false); // add 8ths between 4ths
}
void NoteDataUtil::Quick( NoteData &in )
{
InsertIntelligentTaps(in,0.5f,0.25f,false); // add 16ths between 8ths
}
void NoteDataUtil::Skippy( NoteData &in )
{
InsertIntelligentTaps(in,1.0f,0.75f,true); // add 16ths between 4ths
}
void NoteDataUtil::InsertIntelligentTaps( NoteData &in, float fBeatInterval, float fInsertBeatOffset, bool bNewTapSameAsBeginning )
{
ASSERT( fInsertBeatOffset <= fBeatInterval );
in.ConvertHoldNotesTo4s();
// insert a beat in the middle of every fBeatInterval
int max_row = in.GetLastRow();
int rows_per_interval = BeatToNoteRow( fBeatInterval );
int insert_row_offset = BeatToNoteRow( fInsertBeatOffset );
for( int i=0; i<=max_row; i+=rows_per_interval )
{
int iRowEarlier = i;
int iRowLater = i + rows_per_interval;
int iRowToAdd = i + insert_row_offset;
if( in.GetNumTapNonEmptyTracks(iRowEarlier)!=1 || in.GetNumTracksWithTap(iRowEarlier)!=1 )
continue;
if( in.GetNumTapNonEmptyTracks(iRowLater)!=1 || in.GetNumTracksWithTap(iRowLater)!=1 )
continue;
// there is a 4th and 8th note surrounding iRowBetween
// don't insert a new note if there's already one within this interval
bool bNoteInMiddle = false;
for( int j=iRowEarlier+1; j<=iRowLater-1; j++ )
if( !in.IsRowEmpty(j) )
{
bNoteInMiddle = true;
break;
}
if( bNoteInMiddle )
continue;
// add a note determinitsitcally somewhere on a track different from the two surrounding notes
int iTrackOfNoteEarlier = in.GetFirstNonEmptyTrack(iRowEarlier);
int iTrackOfNoteLater = in.GetFirstNonEmptyTrack(iRowLater);
int iTrackOfNoteToAdd = 0;
if( bNewTapSameAsBeginning &&
iTrackOfNoteEarlier != iTrackOfNoteLater ) // Don't make skips on the same note
{
iTrackOfNoteToAdd = iTrackOfNoteEarlier;
}
else // bNewTapSameAsBeginning
{
// choose a randomish track
if( abs(iTrackOfNoteEarlier-iTrackOfNoteLater) == 2 )
iTrackOfNoteToAdd = (iTrackOfNoteEarlier+iTrackOfNoteLater)/2;
else
{
for( int t=min(iTrackOfNoteEarlier,iTrackOfNoteLater)-1; t<=max(iTrackOfNoteEarlier,iTrackOfNoteLater)+1; t++ )
{
iTrackOfNoteToAdd = t;
CLAMP( iTrackOfNoteToAdd, 0, in.GetNumTracks()-1 );
if( iTrackOfNoteToAdd!=iTrackOfNoteEarlier && iTrackOfNoteToAdd!=iTrackOfNoteLater )
break;
}
}
}
in.SetTapNote(iTrackOfNoteToAdd, iRowToAdd, TAP_TAP);
}
in.Convert4sToHoldNotes();
}
void NoteDataUtil::SnapToNearestNoteType( NoteData &in, NoteType nt1, NoteType nt2, float fBeginBeat, float fEndBeat )
{
// nt2 is optional and should be -1 if it is not used
float fSnapInterval1, fSnapInterval2;
switch( nt1 )
{
case NOTE_TYPE_4TH: fSnapInterval1 = 1/1.0f; break;
case NOTE_TYPE_8TH: fSnapInterval1 = 1/2.0f; break;
case NOTE_TYPE_12TH: fSnapInterval1 = 1/3.0f; break;
case NOTE_TYPE_16TH: fSnapInterval1 = 1/4.0f; break;
case NOTE_TYPE_24TH: fSnapInterval1 = 1/6.0f; break;
case NOTE_TYPE_32ND: fSnapInterval1 = 1/8.0f; break;
default: ASSERT( false ); return;
}
switch( nt2 )
{
case NOTE_TYPE_4TH: fSnapInterval2 = 1/1.0f; break;
case NOTE_TYPE_8TH: fSnapInterval2 = 1/2.0f; break;
case NOTE_TYPE_12TH: fSnapInterval2 = 1/3.0f; break;
case NOTE_TYPE_16TH: fSnapInterval2 = 1/4.0f; break;
case NOTE_TYPE_24TH: fSnapInterval2 = 1/6.0f; break;
case NOTE_TYPE_32ND: fSnapInterval2 = 1/8.0f; break;
case -1: fSnapInterval2 = 10000; break; // nothing will ever snap to this. That's what we want!
default: ASSERT( false ); return;
}
int iNoteIndexBegin = BeatToNoteRow( fBeginBeat );
int iNoteIndexEnd = BeatToNoteRow( fEndBeat );
in.ConvertHoldNotesTo2sAnd3s();
// iterate over all TapNotes in the interval and snap them
for( int i=iNoteIndexBegin; i<=iNoteIndexEnd; i++ )
{
LOG->Trace("index %i", i);
int iOldIndex = i;
float fOldBeat = NoteRowToBeat( iOldIndex );
float fNewBeat1 = froundf( fOldBeat, fSnapInterval1 );
float fNewBeat2 = froundf( fOldBeat, fSnapInterval2 );
LOG->Trace("oldbeat %.2f, nb1 %.2f, nb2 %.2f", fOldBeat, fNewBeat1, fNewBeat2);
bool bNewBeat1IsCloser = fabsf(fNewBeat1-fOldBeat) < fabsf(fNewBeat2-fOldBeat);
float fNewBeat = bNewBeat1IsCloser ? fNewBeat1 : fNewBeat2;
int iNewIndex = BeatToNoteRow( fNewBeat );
LOG->Trace("closer %i, newbeat %.2f, index %i",
bNewBeat1IsCloser, fNewBeat, iNewIndex);
for( int c=0; c<in.GetNumTracks(); c++ )
{
if( iOldIndex == iNewIndex )
continue;
TapNote note = in.GetTapNote(c, iOldIndex);
if( note == TAP_EMPTY )
continue;
in.SetTapNote(c, iOldIndex, TAP_EMPTY);
const TapNote oldnote = in.GetTapNote(c, iNewIndex);
if( note == TAP_TAP &&
(oldnote == TAP_HOLD_HEAD || oldnote == TAP_HOLD_TAIL) )
continue; // HoldNotes override TapNotes
/* If two hold note boundaries are getting snapped together,
* merge them. */
if( (note == TAP_HOLD_HEAD && oldnote == TAP_HOLD_TAIL) ||
(note == TAP_HOLD_TAIL && oldnote == TAP_HOLD_HEAD))
note = TAP_EMPTY;
in.SetTapNote(c, iNewIndex, note );
}
}
in.Convert2sAnd3sToHoldNotes();
}
void NoteDataUtil::CopyLeftToRight( NoteData &in )
{
in.ConvertHoldNotesTo4s();
int max_row = in.GetLastRow();
for( int r=0; r<=max_row; r++ )
{
for( int t=0; t<in.GetNumTracks()/2; t++ )
{
int iTrackEarlier = t;
int iTrackLater = in.GetNumTracks()-1-t;
// swap
TapNote tnEarlier = in.GetTapNote(iTrackEarlier, r);
// TapNote tnLater = in.GetTapNote(iTrackLater, r);
// in.SetTapNote(iTrackEarlier, r, tnLater);
in.SetTapNote(iTrackLater, r, tnEarlier);
}
}
in.Convert4sToHoldNotes();
}
void NoteDataUtil::CopyRightToLeft( NoteData &in )
{
in.ConvertHoldNotesTo4s();
int max_row = in.GetLastRow();
for( int r=0; r<=max_row; r++ )
{
for( int t=0; t<in.GetNumTracks()/2; t++ )
{
int iTrackEarlier = t;
int iTrackLater = in.GetNumTracks()-1-t;
// swap
// TapNote tnEarlier = in.GetTapNote(iTrackEarlier, r);
TapNote tnLater = in.GetTapNote(iTrackLater, r);
in.SetTapNote(iTrackEarlier, r, tnLater);
// in.SetTapNote(iTrackLater, r, tnEarlier);
}
}
in.Convert4sToHoldNotes();
}
void NoteDataUtil::ClearLeft( NoteData &in )
{
in.ConvertHoldNotesTo4s();
int max_row = in.GetLastRow();
for( int r=0; r<=max_row; r++ )
for( int t=0; t<in.GetNumTracks()/2; t++ )
in.SetTapNote(t, r, TAP_EMPTY);
in.Convert4sToHoldNotes();
}
void NoteDataUtil::ClearRight( NoteData &in )
{
in.ConvertHoldNotesTo4s();
int max_row = in.GetLastRow();
for( int r=0; r<=max_row; r++ )
for( int t=(in.GetNumTracks()+1)/2; t<in.GetNumTracks(); t++ )
in.SetTapNote(t, r, TAP_EMPTY);
in.Convert4sToHoldNotes();
}
void NoteDataUtil::CollapseToOne( NoteData &in )
{
in.ConvertHoldNotesTo2sAnd3s();
int max_row = in.GetLastRow();
for( int r=0; r<=max_row; r++ )
for( int t=0; t<in.GetNumTracks(); t++ )
if( in.GetTapNote(t,r) != TAP_EMPTY )
{
in.SetTapNote(0, r, in.GetTapNote(t,r));
in.SetTapNote(t, r, TAP_EMPTY);
}
in.Convert2sAnd3sToHoldNotes();
}
void NoteDataUtil::ShiftLeft( NoteData &in )
{
in.ConvertHoldNotesTo4s();
int max_row = in.GetLastRow();
for( int r=0; r<=max_row; r++ )
{
for( int t=0; t<in.GetNumTracks()-1; t++ ) // in.GetNumTracks()-1 times
{
int iTrackEarlier = t;
int iTrackLater = (t+1) % in.GetNumTracks();
// swap
TapNote tnEarlier = in.GetTapNote(iTrackEarlier, r);
TapNote tnLater = in.GetTapNote(iTrackLater, r);
in.SetTapNote(iTrackEarlier, r, tnLater);
in.SetTapNote(iTrackLater, r, tnEarlier);
}
}
in.Convert4sToHoldNotes();
}
void NoteDataUtil::ShiftRight( NoteData &in )
{
in.ConvertHoldNotesTo4s();
int max_row = in.GetLastRow();
for( int r=0; r<=max_row; r++ )
{
for( int t=in.GetNumTracks()-1; t>0; t-- ) // in.GetNumTracks()-1 times
{
int iTrackEarlier = t;
int iTrackLater = (t+1) % in.GetNumTracks();
// swap
TapNote tnEarlier = in.GetTapNote(iTrackEarlier, r);
TapNote tnLater = in.GetTapNote(iTrackLater, r);
in.SetTapNote(iTrackEarlier, r, tnLater);
in.SetTapNote(iTrackLater, r, tnEarlier);
}
}
in.Convert4sToHoldNotes();
}
void NoteDataUtil::FixImpossibleRows( NoteData &in, StepsType st )
{
}
+69
View File
@@ -0,0 +1,69 @@
#ifndef NOTEDATAUTIL_H
#define NOTEDATAUTIL_H
/*
-----------------------------------------------------------------------------
File: NoteDataUtil.h
Desc: Holds data about the notes that the player is supposed to hit. NoteData
is organized by:
track - corresponds to different columns of notes on the screen
index - corresponds to subdivisions of beats
Copyright (c) 2001-2002 by the person(s) listed below. All rights reserved.
Chris Danford
-----------------------------------------------------------------------------
*/
#include "GameConstantsAndTypes.h" // for RadarCategory
#include "NoteTypes.h"
#include "NoteData.h"
/* Utils for NoteData. Things should go in here if they can be (cleanly and
* efficiently) implemented using only NoteData's primitives; this improves
* abstraction and makes it much easier to change NoteData internally in
* the future. */
namespace NoteDataUtil
{
NoteType GetSmallestNoteTypeForMeasure( const NoteData &n, int iMeasureIndex );
void LoadFromSMNoteDataString( NoteData &out, CString sSMNoteData );
CString GetSMNoteDataString(NoteData &in);
float GetStreamRadarValue( const NoteData &in, float fSongSeconds );
float GetVoltageRadarValue( const NoteData &in, float fSongSeconds );
float GetAirRadarValue( const NoteData &in, float fSongSeconds );
float GetFreezeRadarValue( const NoteData &in, float fSongSeconds );
float GetChaosRadarValue( const NoteData &in, float fSongSeconds );
// radar values - return between 0.0 and 1.2
float GetRadarValue( const NoteData &in, RadarCategory rv, float fSongSeconds );
void RemoveHoldNotes( NoteData &in );
enum TurnType { left, right, mirror, shuffle, super_shuffle, NUM_TURN_TYPES };
void Turn( NoteData &in, StepsType st, TurnType tt );
void Little( NoteData &in );
void Wide( NoteData &in );
void Big( NoteData &in );
void Quick( NoteData &in );
void Skippy( NoteData &in );
void InsertIntelligentTaps( NoteData &in, float fBeatInterval, float fInsertBeatOffset, bool bNewTapSameAsBeginning );
void SuperShuffleTaps( NoteData &in );
void Backwards( NoteData &in );
void SwapSides( NoteData &in );
void CopyLeftToRight( NoteData &in );
void CopyRightToLeft( NoteData &in );
void ClearLeft( NoteData &in );
void ClearRight( NoteData &in );
void CollapseToOne( NoteData &in );
void ShiftLeft( NoteData &in );
void ShiftRight( NoteData &in );
void SnapToNearestNoteType( NoteData &in, NoteType nt1, NoteType nt2, float fBeginBeat, float fEndBeat );
inline void SnapToNearestNoteType( NoteData &in, NoteType nt, float fBeginBeat, float fEndBeat ) { SnapToNearestNoteType( in, nt, (NoteType)-1, fBeginBeat, fEndBeat ); }
void FixImpossibleRows( NoteData &in, StepsType st );
};
#endif
+11 -11
View File
@@ -62,7 +62,7 @@ bool BMSLoader::LoadFromBMSFile( const CString &sPath, Steps &out )
{
LOG->Trace( "Steps::LoadFromBMSFile( '%s' )", sPath.c_str() );
out.m_NotesType = STEPS_TYPE_INVALID;
out.m_StepsType = STEPS_TYPE_INVALID;
NoteData* pNoteData = new NoteData;
pNoteData->SetNumTracks( MAX_NOTE_TRACKS );
@@ -107,14 +107,14 @@ bool BMSLoader::LoadFromBMSFile( const CString &sPath, Steps &out )
switch( atoi(value_data) )
{
case 1: // 4 or 6 single
out.m_NotesType = STEPS_TYPE_DANCE_SINGLE;
out.m_StepsType = STEPS_TYPE_DANCE_SINGLE;
// if the mode should be solo, then we'll update m_DanceStyle below when we read in step data
break;
case 2: // couple/battle
out.m_NotesType = STEPS_TYPE_DANCE_COUPLE;
out.m_StepsType = STEPS_TYPE_DANCE_COUPLE;
break;
case 3: // double
out.m_NotesType = STEPS_TYPE_DANCE_DOUBLE;
out.m_StepsType = STEPS_TYPE_DANCE_DOUBLE;
break;
default:
LOG->Warn( "Invalid value '%d' for '#player'", atoi(value_data) );
@@ -142,7 +142,7 @@ bool BMSLoader::LoadFromBMSFile( const CString &sPath, Steps &out )
// if there's a 6 in the description, it's probably part of "6panel" or "6-panel"
if( value_data.Find("6") != -1 )
out.m_NotesType = STEPS_TYPE_DANCE_SOLO;
out.m_StepsType = STEPS_TYPE_DANCE_SOLO;
}
if( -1 != value_name.Find("#playlevel") )
{
@@ -186,29 +186,29 @@ bool BMSLoader::LoadFromBMSFile( const CString &sPath, Steps &out )
}
}
if( out.m_NotesType == STEPS_TYPE_DANCE_SINGLE ||
out.m_NotesType == STEPS_TYPE_DANCE_DOUBLE ||
out.m_NotesType == STEPS_TYPE_DANCE_COUPLE) // if there are 4 panels, then the Up+Right track really contains the notes for Up
if( out.m_StepsType == STEPS_TYPE_DANCE_SINGLE ||
out.m_StepsType == STEPS_TYPE_DANCE_DOUBLE ||
out.m_StepsType == STEPS_TYPE_DANCE_COUPLE) // if there are 4 panels, then the Up+Right track really contains the notes for Up
{
pNoteData->MoveTapNoteTrack(DANCE_NOTE_PAD1_UP, DANCE_NOTE_PAD1_UPRIGHT);
}
// we're done reading in all of the BMS values
if( out.m_NotesType == STEPS_TYPE_INVALID )
if( out.m_StepsType == STEPS_TYPE_INVALID )
{
LOG->Warn("Couldn't determine note types of file '%s'", sPath.c_str() );
delete pNoteData;
return false;
}
int iNumNewTracks = GameManager::NotesTypeToNumTracks( out.m_NotesType );
int iNumNewTracks = GameManager::NotesTypeToNumTracks( out.m_StepsType );
int iTransformNewToOld[MAX_NOTE_TRACKS];
int i;
for( i = 0; i < MAX_NOTE_TRACKS; ++i)
iTransformNewToOld[i] = -1;
switch( out.m_NotesType )
switch( out.m_StepsType )
{
case STEPS_TYPE_DANCE_SINGLE:
iTransformNewToOld[0] = DANCE_NOTE_PAD1_LEFT;
+8 -8
View File
@@ -106,7 +106,7 @@ bool DWILoader::LoadFromDWITokens(
{
LOG->Trace( "Steps::LoadFromDWITokens()" );
out.m_NotesType = STEPS_TYPE_INVALID;
out.m_StepsType = STEPS_TYPE_INVALID;
sStepData1.Replace( "\n", "" );
sStepData1.Replace( "\r", "" );
@@ -115,19 +115,19 @@ bool DWILoader::LoadFromDWITokens(
sStepData2.Replace( "\r", "" );
sStepData2.Replace( " ", "" );
if( sMode == "SINGLE" ) out.m_NotesType = STEPS_TYPE_DANCE_SINGLE;
else if( sMode == "DOUBLE" ) out.m_NotesType = STEPS_TYPE_DANCE_DOUBLE;
else if( sMode == "COUPLE" ) out.m_NotesType = STEPS_TYPE_DANCE_COUPLE;
else if( sMode == "SOLO" ) out.m_NotesType = STEPS_TYPE_DANCE_SOLO;
if( sMode == "SINGLE" ) out.m_StepsType = STEPS_TYPE_DANCE_SINGLE;
else if( sMode == "DOUBLE" ) out.m_StepsType = STEPS_TYPE_DANCE_DOUBLE;
else if( sMode == "COUPLE" ) out.m_StepsType = STEPS_TYPE_DANCE_COUPLE;
else if( sMode == "SOLO" ) out.m_StepsType = STEPS_TYPE_DANCE_SOLO;
else
{
ASSERT(0); // Unrecognized DWI notes format
out.m_NotesType = STEPS_TYPE_DANCE_SINGLE;
out.m_StepsType = STEPS_TYPE_DANCE_SINGLE;
}
g_mapDanceNoteToNoteDataColumn.clear();
switch( out.m_NotesType )
switch( out.m_StepsType )
{
case STEPS_TYPE_DANCE_SINGLE:
g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_LEFT] = 0;
@@ -457,7 +457,7 @@ bool DWILoader::LoadFromDWIFile( CString sPath, Song &out )
(iNumParams==5) ? sParams[4] : "",
*pNewNotes
);
if(pNewNotes->m_NotesType != STEPS_TYPE_INVALID)
if(pNewNotes->m_StepsType != STEPS_TYPE_INVALID)
out.m_apNotes.push_back( pNewNotes );
else
delete pNewNotes;
+4 -4
View File
@@ -127,17 +127,17 @@ bool KSFLoader::LoadFromKSFFile( const CString &sPath, Steps &out, const Song &s
}
notedata.SetNumTracks( 5 );
out.m_NotesType = STEPS_TYPE_PUMP_SINGLE;
out.m_StepsType = STEPS_TYPE_PUMP_SINGLE;
if( sFName.Find("double") != -1 )
{
notedata.SetNumTracks( 10 );
out.m_NotesType = STEPS_TYPE_PUMP_DOUBLE;
out.m_StepsType = STEPS_TYPE_PUMP_DOUBLE;
} else if( sFName.Find("_2") != -1 ) {
notedata.SetNumTracks( 10 );
out.m_NotesType = STEPS_TYPE_PUMP_COUPLE;
out.m_StepsType = STEPS_TYPE_PUMP_COUPLE;
} else if( sFName.Find("halfdouble") != -1 ) {
notedata.SetNumTracks( 6 );
out.m_NotesType = STEPS_TYPE_PUMP_HALFDOUBLE;
out.m_StepsType = STEPS_TYPE_PUMP_HALFDOUBLE;
}
}
+1 -1
View File
@@ -27,7 +27,7 @@ void SMLoader::LoadFromSMTokens(
// LOG->Trace( "Steps::LoadFromSMTokens()" );
out.m_NotesType = GameManager::StringToNotesType(sNotesType);
out.m_StepsType = GameManager::StringToNotesType(sNotesType);
out.SetDescription(sDescription);
out.SetDifficulty(StringToDifficulty( sDifficulty ));
+5 -4
View File
@@ -5,6 +5,7 @@
#include "RageUtil.h"
#include "RageLog.h"
#include "RageFile.h"
#include "NoteDataUtil.h"
/* Output is an angle bracket expression without angle brackets, eg. "468". */
CString NotesWriterDWI::NotesToDWIString( const TapNote cNoteCols[6] )
@@ -227,7 +228,7 @@ void NotesWriterDWI::WriteDWINotesField( FILE* fp, const Steps &out, int start )
int row = BeatToNoteRow( (float)b );
CString str;
switch( out.m_NotesType )
switch( out.m_StepsType )
{
case STEPS_TYPE_DANCE_SINGLE:
case STEPS_TYPE_DANCE_COUPLE:
@@ -297,7 +298,7 @@ bool NotesWriterDWI::WriteDWINotesTag( FILE* fp, const Steps &out )
{
LOG->Trace( "Steps::WriteDWINotesTag" );
switch( out.m_NotesType )
switch( out.m_StepsType )
{
case STEPS_TYPE_DANCE_SINGLE: fprintf( fp, "#SINGLE:" ); break;
case STEPS_TYPE_DANCE_COUPLE: fprintf( fp, "#COUPLE:" ); break;
@@ -389,8 +390,8 @@ bool NotesWriterDWI::Write( CString sPath, const Song &out )
continue;
WriteDWINotesField( fp, *out.m_apNotes[i], 0 );
if(out.m_apNotes[i]->m_NotesType==STEPS_TYPE_DANCE_DOUBLE ||
out.m_apNotes[i]->m_NotesType==STEPS_TYPE_DANCE_COUPLE)
if(out.m_apNotes[i]->m_StepsType==STEPS_TYPE_DANCE_DOUBLE ||
out.m_apNotes[i]->m_StepsType==STEPS_TYPE_DANCE_COUPLE)
{
fprintf( fp, ":\n" );
WriteDWINotesField( fp, *out.m_apNotes[i], 4 );
+2 -2
View File
@@ -95,9 +95,9 @@ void NotesWriterSM::WriteGlobalTags(FILE *fp, const Song &out)
void NotesWriterSM::WriteSMNotesTag( const Steps &in, FILE* fp )
{
fprintf( fp, "\n//---------------%s - %s----------------\n",
GameManager::NotesTypeToString(in.m_NotesType).c_str(), in.GetDescription().c_str() );
GameManager::NotesTypeToString(in.m_StepsType).c_str(), in.GetDescription().c_str() );
fprintf( fp, "#NOTES:\n" );
fprintf( fp, " %s:\n", GameManager::NotesTypeToString(in.m_NotesType).c_str() );
fprintf( fp, " %s:\n", GameManager::NotesTypeToString(in.m_StepsType).c_str() );
fprintf( fp, " %s:\n", in.GetDescription().c_str() );
fprintf( fp, " %s:\n", DifficultyToString(in.GetDifficulty()).c_str() );
fprintf( fp, " %d:\n", in.GetMeter() );
+9 -6
View File
@@ -31,6 +31,7 @@
#include "LifeMeter.h"
#include "PlayerAI.h"
#include "NoteFieldPositioning.h"
#include "NoteDataUtil.h"
#define GRAY_ARROWS_Y THEME->GetMetricF("Player","GrayArrowsY")
#define JUDGMENT_X( p, both_sides ) THEME->GetMetricF("Player",both_sides ? "JudgmentXOffsetBothSides" : ssprintf("JudgmentXOffsetOneSideP%d",p+1))
@@ -124,14 +125,16 @@ void Player::Load( PlayerNumber pn, NoteData* pNoteData, LifeMeter* pLM, Combine
if( !GAMESTATE->m_PlayerOptions[pn].m_bHoldNotes )
NoteDataUtil::RemoveHoldNotes(*this);
StepsType st = GAMESTATE->GetCurrentStyleDef()->m_StepsType;
switch( GAMESTATE->m_PlayerOptions[pn].m_Turn )
{
case PlayerOptions::TURN_NONE: break;
case PlayerOptions::TURN_MIRROR: NoteDataUtil::Turn( *this, NoteDataUtil::mirror ); break;
case PlayerOptions::TURN_LEFT: NoteDataUtil::Turn( *this, NoteDataUtil::left ); break;
case PlayerOptions::TURN_RIGHT: NoteDataUtil::Turn( *this, NoteDataUtil::right ); break;
case PlayerOptions::TURN_SHUFFLE: NoteDataUtil::Turn( *this, NoteDataUtil::shuffle ); break;
case PlayerOptions::TURN_SUPER_SHUFFLE: NoteDataUtil::Turn( *this, NoteDataUtil::super_shuffle ); break;
case PlayerOptions::TURN_NONE: break;
case PlayerOptions::TURN_MIRROR: NoteDataUtil::Turn( *this, st, NoteDataUtil::mirror ); break;
case PlayerOptions::TURN_LEFT: NoteDataUtil::Turn( *this, st, NoteDataUtil::left ); break;
case PlayerOptions::TURN_RIGHT: NoteDataUtil::Turn( *this, st, NoteDataUtil::right ); break;
case PlayerOptions::TURN_SHUFFLE: NoteDataUtil::Turn( *this, st, NoteDataUtil::shuffle ); break;
case PlayerOptions::TURN_SUPER_SHUFFLE: NoteDataUtil::Turn( *this, st, NoteDataUtil::super_shuffle ); break;
default: ASSERT(0);
}
+7 -5
View File
@@ -32,6 +32,7 @@
#include <utility>
#include "NoteFieldPositioning.h"
#include "arch/arch.h"
#include "NoteDataUtil.h"
const float RECORD_HOLD_SECONDS = 0.3f;
@@ -1401,14 +1402,15 @@ void ScreenEdit::HandleAreaMenuChoice( AreaMenuChoice c, int* iAnswers )
{
HandleAreaMenuChoice( cut, NULL );
StepsType st = GAMESTATE->GetCurrentStyleDef()->m_StepsType;
TurnType tt = (TurnType)iAnswers[c];
switch( tt )
{
case left: NoteDataUtil::Turn( m_Clipboard, NoteDataUtil::left ); break;
case right: NoteDataUtil::Turn( m_Clipboard, NoteDataUtil::right ); break;
case mirror: NoteDataUtil::Turn( m_Clipboard, NoteDataUtil::mirror ); break;
case shuffle: NoteDataUtil::Turn( m_Clipboard, NoteDataUtil::shuffle ); break;
case super_shuffle: NoteDataUtil::Turn( m_Clipboard, NoteDataUtil::super_shuffle ); break;
case left: NoteDataUtil::Turn( m_Clipboard, st, NoteDataUtil::left ); break;
case right: NoteDataUtil::Turn( m_Clipboard, st, NoteDataUtil::right ); break;
case mirror: NoteDataUtil::Turn( m_Clipboard, st, NoteDataUtil::mirror ); break;
case shuffle: NoteDataUtil::Turn( m_Clipboard, st, NoteDataUtil::shuffle ); break;
case super_shuffle: NoteDataUtil::Turn( m_Clipboard, st, NoteDataUtil::super_shuffle ); break;
default: ASSERT(0);
}
+2 -2
View File
@@ -168,7 +168,7 @@ ScreenEvaluation::ScreenEvaluation( CString sClassName, Type type ) : Screen(sCl
break;
case summary:
{
StepsType nt = GAMESTATE->GetCurrentStyleDef()->m_NotesType;
StepsType nt = GAMESTATE->GetCurrentStyleDef()->m_StepsType;
bool bIsHumanPlayer[NUM_PLAYERS];
for( p=0; p<NUM_PLAYERS; p++ )
bIsHumanPlayer[p] = GAMESTATE->IsHumanPlayer(p);
@@ -196,7 +196,7 @@ ScreenEvaluation::ScreenEvaluation( CString sClassName, Type type ) : Screen(sCl
break;
case course:
{
StepsType nt = GAMESTATE->GetCurrentStyleDef()->m_NotesType;
StepsType nt = GAMESTATE->GetCurrentStyleDef()->m_StepsType;
bool bIsHumanPlayer[NUM_PLAYERS];
for( p=0; p<NUM_PLAYERS; p++ )
bIsHumanPlayer[p] = GAMESTATE->IsHumanPlayer(p);
+1 -1
View File
@@ -610,7 +610,7 @@ void ScreenEz2SelectMusic::MusicChanged()
for( pn = 0; pn < NUM_PLAYERS; ++pn)
{
pSong->GetNotes( m_arrayNotes[pn], GAMESTATE->GetCurrentStyleDef()->m_NotesType );
pSong->GetNotes( m_arrayNotes[pn], GAMESTATE->GetCurrentStyleDef()->m_StepsType );
SortNotesArrayByDifficulty( m_arrayNotes[pn] );
}
+2 -1
View File
@@ -43,6 +43,7 @@
#include "CombinedLifeMeterTug.h"
#include "Inventory.h"
#include "Course.h"
#include "NoteDataUtil.h"
//
// Defines
@@ -146,7 +147,7 @@ ScreenGameplay::ScreenGameplay( bool bDemonstration ) : Screen("ScreenGameplay")
if( GAMESTATE->IsCourseMode() )
{
vector<Course::Info> ci;
GAMESTATE->m_pCurCourse->GetCourseInfo( GAMESTATE->GetCurrentStyleDef()->m_NotesType, ci );
GAMESTATE->m_pCurCourse->GetCourseInfo( GAMESTATE->GetCurrentStyleDef()->m_StepsType, ci );
for( int p=0; p<NUM_PLAYERS; p++ )
{
m_apNotesQueue[p].clear();
+1 -1
View File
@@ -36,7 +36,7 @@ ScreenHowToPlay::ScreenHowToPlay() : ScreenAttract("ScreenHowToPlay")
default: ASSERT(0); // we should cover all gametypes....
}
StepsType nt = GAMESTATE->GetCurrentStyleDef()->m_NotesType;
StepsType nt = GAMESTATE->GetCurrentStyleDef()->m_StepsType;
int iNumOfTracks = GAMEMAN->NotesTypeToNumTracks( nt );
ASSERT(iNumOfTracks > 0); // crazy to have less than 1 track....
+2 -2
View File
@@ -49,11 +49,11 @@ bool ScreenJukebox::SetSong()
Difficulty dc = GAMESTATE->m_PreferredDifficulty[PLAYER_1];
Steps* pNotes = NULL;
if( dc != DIFFICULTY_INVALID )
pNotes = pSong->GetNotes( GAMESTATE->GetCurrentStyleDef()->m_NotesType, GAMESTATE->m_PreferredDifficulty[PLAYER_1] );
pNotes = pSong->GetNotes( GAMESTATE->GetCurrentStyleDef()->m_StepsType, GAMESTATE->m_PreferredDifficulty[PLAYER_1] );
else // "all difficulties"
{
vector<Steps*> vNotes;
pSong->GetNotes( vNotes, GAMESTATE->GetCurrentStyleDef()->m_NotesType );
pSong->GetNotes( vNotes, GAMESTATE->GetCurrentStyleDef()->m_StepsType );
if( vNotes.size() > 0 )
pNotes = vNotes[rand()%vNotes.size()];
}
+5 -5
View File
@@ -109,13 +109,13 @@ void ScreenPlayerOptions::ImportOptions()
if( GAMESTATE->m_pCurCourse ) // playing a course
{
m_OptionRow[PO_STEP].choices.push_back( "REGULAR" );
if( GAMESTATE->m_pCurCourse->HasDifficult( GAMESTATE->GetCurrentStyleDef()->m_NotesType ) )
if( GAMESTATE->m_pCurCourse->HasDifficult( GAMESTATE->GetCurrentStyleDef()->m_StepsType ) )
m_OptionRow[PO_STEP].choices.push_back( "DIFFICULT" );
}
else
{
vector<Steps*> vNotes;
GAMESTATE->m_pCurSong->GetNotes( vNotes, GAMESTATE->GetCurrentStyleDef()->m_NotesType );
GAMESTATE->m_pCurSong->GetNotes( vNotes, GAMESTATE->GetCurrentStyleDef()->m_StepsType );
SortNotesArrayByDifficulty( vNotes );
for( unsigned i=0; i<vNotes.size(); i++ )
{
@@ -218,7 +218,7 @@ void ScreenPlayerOptions::ImportOptions()
if( GAMESTATE->m_pCurCourse ) // playing a course
{
if( GAMESTATE->m_bDifficultCourses &&
GAMESTATE->m_pCurCourse->HasDifficult( GAMESTATE->GetCurrentStyleDef()->m_NotesType ) )
GAMESTATE->m_pCurCourse->HasDifficult( GAMESTATE->GetCurrentStyleDef()->m_StepsType ) )
m_iSelectedOption[p][PO_STEP] = 1;
else
m_iSelectedOption[p][PO_STEP] = 0;
@@ -226,7 +226,7 @@ void ScreenPlayerOptions::ImportOptions()
else
{
vector<Steps*> vNotes;
GAMESTATE->m_pCurSong->GetNotes( vNotes, GAMESTATE->GetCurrentStyleDef()->m_NotesType );
GAMESTATE->m_pCurSong->GetNotes( vNotes, GAMESTATE->GetCurrentStyleDef()->m_StepsType );
SortNotesArrayByDifficulty( vNotes );
for( unsigned i=0; i<vNotes.size(); i++ )
{
@@ -338,7 +338,7 @@ void ScreenPlayerOptions::ExportOptions()
else
{
vector<Steps*> vNotes;
GAMESTATE->m_pCurSong->GetNotes( vNotes, GAMESTATE->GetCurrentStyleDef()->m_NotesType );
GAMESTATE->m_pCurSong->GetNotes( vNotes, GAMESTATE->GetCurrentStyleDef()->m_StepsType );
SortNotesArrayByDifficulty( vNotes );
GAMESTATE->m_pCurNotes[p] = vNotes[ m_iSelectedOption[p][PO_STEP] ];
}
+1 -1
View File
@@ -360,7 +360,7 @@ void ScreenSelectCourse::MenuStart( PlayerNumber pn )
//Song* pSong;
//Steps* pNotes;
//CString sModifiers;
//pCourse->GetFirstStageInfo( pSong, pNotes, sModifiers, GAMESTATE->GetCurrentStyleDef()->m_NotesType );
//pCourse->GetFirstStageInfo( pSong, pNotes, sModifiers, GAMESTATE->GetCurrentStyleDef()->m_StepsType );
//for( int p=0; p<NUM_PLAYERS; p++ )
// GAMESTATE->m_PlayerOptions[p].FromString( sModifiers );
//GAMESTATE->m_SongOptions.FromString( sModifiers );
+2 -2
View File
@@ -975,7 +975,7 @@ void ScreenSelectMusic::AfterMusicChange()
m_fSampleStartSeconds = pSong->m_fMusicSampleStartSeconds;
m_fSampleLengthSeconds = pSong->m_fMusicSampleLengthSeconds;
pSong->GetNotes( m_arrayNotes, GAMESTATE->GetCurrentStyleDef()->m_NotesType );
pSong->GetNotes( m_arrayNotes, GAMESTATE->GetCurrentStyleDef()->m_StepsType );
SortNotesArrayByDifficulty( m_arrayNotes );
m_Banner.LoadFromSong( pSong );
@@ -996,7 +996,7 @@ void ScreenSelectMusic::AfterMusicChange()
TEXTUREMAN->EnableOddDimensionWarning();
FlipSpriteHorizontally(m_sprCDTitleBack);
m_DifficultyDisplay.SetDifficulties( pSong, GAMESTATE->GetCurrentStyleDef()->m_NotesType );
m_DifficultyDisplay.SetDifficulties( pSong, GAMESTATE->GetCurrentStyleDef()->m_StepsType );
SwitchToPreferredDifficulty();
+11 -10
View File
@@ -31,6 +31,7 @@
#include "PrefsManager.h"
#include "arch/arch.h"
#include "RageFile.h"
#include "NoteDataUtil.h"
#include "NotesLoaderSM.h"
#include "NotesLoaderDWI.h"
@@ -833,7 +834,7 @@ void Song::GetNotes( vector<Steps*>& arrayAddTo, StepsType nt, Difficulty dc, in
{
for( unsigned i=0; i<m_apNotes.size(); i++ ) // for each of the Song's Steps
{
if( m_apNotes[i]->m_NotesType != nt ) continue;
if( m_apNotes[i]->m_StepsType != nt ) continue;
if( dc != DIFFICULTY_INVALID && dc != m_apNotes[i]->GetDifficulty() )
continue;
if( iMeterLow != -1 && iMeterLow > m_apNotes[i]->GetMeter() )
@@ -915,7 +916,7 @@ void Song::GetEdits( vector<Steps*>& arrayAddTo, StepsType nt, bool bIncludeAuto
/* Return whether the song is playable in the given style. */
bool Song::SongCompleteForStyle( const StyleDef *st ) const
{
if(!SongHasNotesType(st->m_NotesType))
if(!SongHasNotesType(st->m_StepsType))
return false;
return true;
}
@@ -923,7 +924,7 @@ bool Song::SongCompleteForStyle( const StyleDef *st ) const
bool Song::SongHasNotesType( StepsType nt ) const
{
for( unsigned i=0; i < m_apNotes.size(); i++ ) // foreach Steps
if( m_apNotes[i]->m_NotesType == nt )
if( m_apNotes[i]->m_StepsType == nt )
return true;
return false;
}
@@ -931,7 +932,7 @@ bool Song::SongHasNotesType( StepsType nt ) const
bool Song::SongHasNotesTypeAndDifficulty( StepsType nt, Difficulty dc ) const
{
for( unsigned i=0; i < m_apNotes.size(); i++ ) // foreach Steps
if( m_apNotes[i]->m_NotesType == nt && m_apNotes[i]->GetDifficulty() == dc )
if( m_apNotes[i]->m_StepsType == nt && m_apNotes[i]->GetDifficulty() == dc )
return true;
return false;
}
@@ -1042,7 +1043,7 @@ void Song::AutoGen( StepsType ntTo, StepsType ntFrom )
for( unsigned int j=0; j<m_apNotes.size(); j++ )
{
Steps* pOriginalNotes = m_apNotes[j];
if( pOriginalNotes->m_NotesType == ntFrom )
if( pOriginalNotes->m_StepsType == ntFrom )
{
Steps* pNewNotes = new Steps;
pNewNotes->AutogenFrom(pOriginalNotes, ntTo);
@@ -1068,7 +1069,7 @@ Grade Song::GetGradeForDifficulty( const StyleDef *st, PlayerNumber pn, Difficul
{
// return max grade of notes in difficulty class
vector<Steps*> aNotes;
this->GetNotes( aNotes, st->m_NotesType );
this->GetNotes( aNotes, st->m_StepsType );
SortNotesArrayByDifficulty( aNotes );
Grade grade = GRADE_NO_DATA;
@@ -1182,7 +1183,7 @@ void SortSongPointerArrayByTitle( vector<Song*> &arraySongPointers )
static int GetSongSortDifficulty(const Song *pSong)
{
vector<Steps*> aNotes;
pSong->GetNotes( aNotes, GAMESTATE->GetCurrentStyleDef()->m_NotesType );
pSong->GetNotes( aNotes, GAMESTATE->GetCurrentStyleDef()->m_StepsType );
// sort by anything but beginner
/* This makes the sort a little odd; songs can end up in unintuitive places because,
@@ -1390,8 +1391,8 @@ struct CompareSongByMeter
CompareSongByMeter(Difficulty d): dc(d) { }
bool operator() (const Song* pSong1, const Song* pSong2)
{
Steps* pNotes1 = pSong1->GetNotes( GAMESTATE->GetCurrentStyleDef()->m_NotesType, dc );
Steps* pNotes2 = pSong2->GetNotes( GAMESTATE->GetCurrentStyleDef()->m_NotesType, dc );
Steps* pNotes1 = pSong1->GetNotes( GAMESTATE->GetCurrentStyleDef()->m_StepsType, dc );
Steps* pNotes2 = pSong2->GetNotes( GAMESTATE->GetCurrentStyleDef()->m_StepsType, dc );
const int iMeter1 = pNotes1 ? pNotes1->GetMeter() : 0;
const int iMeter2 = pNotes2 ? pNotes2->GetMeter() : 0;
@@ -1578,7 +1579,7 @@ int Song::GetNumNotesWithGrade( Grade g ) const
{
int iCount = 0;
vector<Steps*> vNotes;
this->GetNotes( vNotes, GAMESTATE->GetCurrentStyleDef()->m_NotesType );
this->GetNotes( vNotes, GAMESTATE->GetCurrentStyleDef()->m_StepsType );
for( unsigned j=0; j<vNotes.size(); j++ )
if( vNotes[j]->m_MemCardScores[MEMORY_CARD_MACHINE].grade == g )
iCount++;
+5 -5
View File
@@ -557,7 +557,7 @@ void SongManager::SaveNoteScoresToFile( CString fn, int c )
ASSERT(pNotes);
fprintf(fp, "%d %d\n%s\n",
pNotes->m_NotesType,
pNotes->m_StepsType,
pNotes->GetDifficulty(),
pNotes->GetDescription().c_str() );
@@ -661,14 +661,14 @@ RageColor SongManager::GetSongColor( const Song* pSong )
* set up, which is too restrictive. How to handle this?
*
* XXX: Once we support edits, ignore them, too. */
// const StepsType nt = GAMESTATE->GetCurrentStyleDef()->m_NotesType;
// const StepsType nt = GAMESTATE->GetCurrentStyleDef()->m_StepsType;
for( unsigned i=0; i<pSong->m_apNotes.size(); i++ )
{
const Steps* pNotes = pSong->m_apNotes[i];
if( pNotes->GetDifficulty() == DIFFICULTY_CHALLENGE )
continue;
// if(pNotes->m_NotesType != nt)
// if(pNotes->m_StepsType != nt)
// continue;
if( pNotes->GetMeter() >= 10 && PREFSMAN->m_bTenFooterInRed )
@@ -925,7 +925,7 @@ bool SongManager::GetExtraStageInfoFromCourse( bool bExtra2, CString sPreferredG
if( course.GetEstimatedNumStages() <= 0 ) return false;
vector<Course::Info> ci;
course.GetCourseInfo( GAMESTATE->GetCurrentStyleDef()->m_NotesType, ci );
course.GetCourseInfo( GAMESTATE->GetCurrentStyleDef()->m_StepsType, ci );
if( ci.empty() )
return false;
@@ -990,7 +990,7 @@ void SongManager::GetExtraStageInfo( bool bExtra2, const StyleDef *sd,
Song* pSong = apSongs[s];
vector<Steps*> apNotes;
pSong->GetNotes( apNotes, sd->m_NotesType );
pSong->GetNotes( apNotes, sd->m_StepsType );
for( unsigned n=0; n<apNotes.size(); n++ ) // foreach Steps
{
Steps* pNotes = apNotes[n];
+23 -4
View File
@@ -65,7 +65,7 @@ IntDir=.\../Debug6
TargetDir=\stepmania\stepmania
TargetName=StepMania-debug
SOURCE="$(InputPath)"
PreLink_Cmds=disasm\verinc cl /Zl /nologo /c verstub.cpp /Fo$(IntDir)\
PreLink_Cmds=disasm\verinc cl /Zl /nologo /c verstub.cpp /Fo$(IntDir)\
PostBuild_Cmds=disasm\mapconv $(IntDir)\$(TargetName).map $(TargetDir)\StepMania.vdi ia32.vdi
# End Special Build Tool
@@ -102,7 +102,7 @@ IntDir=.\Debug
TargetDir=\stepmania\stepmania
TargetName=default
SOURCE="$(InputPath)"
PreLink_Cmds=disasm\verinc cl /Zl /nologo /c verstub.cpp /Fo$(IntDir)\
PreLink_Cmds=disasm\verinc cl /Zl /nologo /c verstub.cpp /Fo$(IntDir)\
PostBuild_Cmds=disasm\mapconv $(IntDir)\$(TargetName).map $(TargetDir)\StepMania.vdi ia32.vdi
# End Special Build Tool
@@ -142,7 +142,7 @@ IntDir=.\../Release6
TargetDir=\stepmania\stepmania
TargetName=StepMania
SOURCE="$(InputPath)"
PreLink_Cmds=disasm\verinc cl /Zl /nologo /c verstub.cpp /Fo$(IntDir)\
PreLink_Cmds=disasm\verinc cl /Zl /nologo /c verstub.cpp /Fo$(IntDir)\
PostBuild_Cmds=disasm\mapconv $(IntDir)\$(TargetName).map $(TargetDir)\StepMania.vdi ia32.vdi
# End Special Build Tool
@@ -183,7 +183,7 @@ IntDir=.\StepMania___Xbox_Release
TargetDir=\stepmania\stepmania
TargetName=default
SOURCE="$(InputPath)"
PreLink_Cmds=disasm\verinc cl /Zl /nologo /c verstub.cpp /Fo$(IntDir)\
PreLink_Cmds=disasm\verinc cl /Zl /nologo /c verstub.cpp /Fo$(IntDir)\
PostBuild_Cmds=disasm\mapconv $(IntDir)\$(TargetName).map $(TargetDir)\StepMania.vdi ia32.vdi
# End Special Build Tool
@@ -1181,6 +1181,25 @@ SOURCE=.\NoteData.h
# End Source File
# Begin Source File
SOURCE=.\NoteDataUtil.cpp
!IF "$(CFG)" == "StepMania - Win32 Debug"
!ELSEIF "$(CFG)" == "StepMania - Xbox Debug"
!ELSEIF "$(CFG)" == "StepMania - Win32 Release"
!ELSEIF "$(CFG)" == "StepMania - Xbox Release"
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\NoteDataUtil.h
# End Source File
# Begin Source File
SOURCE=.\NoteDataWithScoring.cpp
!IF "$(CFG)" == "StepMania - Win32 Debug"
+15 -9
View File
@@ -23,7 +23,7 @@
#include "RageException.h"
#include "MsdFile.h"
#include "GameManager.h"
#include "NoteDataUtil.h"
Steps::Steps()
@@ -32,7 +32,7 @@ Steps::Steps()
* I have a feeling that it's the right thing to do but that
* it'd trip obscure asserts all over the place, so I'll wait
* until after b6 to do this. -glenn */
m_NotesType = STEPS_TYPE_DANCE_SINGLE;
m_StepsType = STEPS_TYPE_DANCE_SINGLE;
m_Difficulty = DIFFICULTY_INVALID;
m_iMeter = 0;
for(int i = 0; i < NUM_RADAR_CATEGORIES; ++i)
@@ -58,7 +58,7 @@ Steps::~Steps()
void Steps::SetNoteData( NoteData* pNewNoteData )
{
ASSERT( pNewNoteData->GetNumTracks() == GameManager::NotesTypeToNumTracks(m_NotesType) );
ASSERT( pNewNoteData->GetNumTracks() == GameManager::NotesTypeToNumTracks(m_StepsType) );
DeAutogen();
@@ -81,7 +81,7 @@ void Steps::GetNoteData( NoteData* pNoteDataOut ) const
else
{
pNoteDataOut->ClearAll();
pNoteDataOut->SetNumTracks( GameManager::NotesTypeToNumTracks(m_NotesType) );
pNoteDataOut->SetNumTracks( GameManager::NotesTypeToNumTracks(m_StepsType) );
}
}
@@ -160,11 +160,16 @@ void Steps::Decompress() const
parent->GetNoteData(&pdata);
notes = new NoteData;
notes->SetNumTracks( GameManager::NotesTypeToNumTracks(m_NotesType) );
notes->SetNumTracks( GameManager::NotesTypeToNumTracks(m_StepsType) );
if(pdata.GetNumTracks() == notes->GetNumTracks())
{
notes->CopyRange( &pdata, 0, pdata.GetLastRow(), 0 );
}
else
{
notes->LoadTransformedSlidingWindow( &pdata, notes->GetNumTracks() );
NoteDataUtil::FixImpossibleRows( pdata, m_StepsType );
}
}
else if(!notes_comp)
{
@@ -174,7 +179,7 @@ void Steps::Decompress() const
{
// load from compressed
notes = new NoteData;
notes->SetNumTracks( GameManager::NotesTypeToNumTracks(m_NotesType) );
notes->SetNumTracks( GameManager::NotesTypeToNumTracks(m_StepsType) );
NoteDataUtil::LoadFromSMNoteDataString(*notes, *notes_comp);
}
@@ -215,12 +220,12 @@ void Steps::DeAutogen()
void Steps::AutogenFrom( Steps *parent_, StepsType ntTo )
{
parent = parent_;
m_NotesType = ntTo;
m_StepsType = ntTo;
}
void Steps::CopyFrom( Steps* pSource, StepsType ntTo ) // pSource does not have to be of the same StepsType!
{
m_NotesType = ntTo;
m_StepsType = ntTo;
NoteData noteData;
pSource->GetNoteData( &noteData );
noteData.SetNumTracks( GameManager::NotesTypeToNumTracks(ntTo) );
@@ -236,7 +241,7 @@ void Steps::CopyFrom( Steps* pSource, StepsType ntTo ) // pSource does not have
void Steps::CreateBlank( StepsType ntTo )
{
m_NotesType = ntTo;
m_StepsType = ntTo;
NoteData noteData;
noteData.SetNumTracks( GameManager::NotesTypeToNumTracks(ntTo) );
this->SetNoteData( &noteData );
@@ -279,6 +284,7 @@ void Steps::SetRadarValue(int r, float val)
m_fRadarValues[r] = val;
}
/* Make sure we treat AAAA as higher than AAA, even though the score
* is the same.
*
+2 -1
View File
@@ -44,7 +44,8 @@ public:
void SetRadarValue(int r, float val);
bool IsAutogen() const; // Was created by autogen?
StepsType m_NotesType;
StepsType m_StepsType;
void GetNoteData( NoteData* pNoteDataOut ) const;
void SetNoteData( NoteData* pNewNoteData );
+1 -1
View File
@@ -84,7 +84,7 @@ PlayerNumber StyleDef::ControllerToPlayerNumber( GameController controller ) con
bool StyleDef::MatchesNotesType( StepsType type ) const
{
if(type == m_NotesType) return true;
if(type == m_StepsType) return true;
return false;
}
+1 -1
View File
@@ -45,7 +45,7 @@ public:
/* Steps format used for each player. For example, "dance versus" reads
* the Steps with the tag "dance-single". */
StepsType m_NotesType;
StepsType m_StepsType;
enum StyleType
{