more work on a new course editor

This commit is contained in:
Chris Danford
2005-06-28 08:11:30 +00:00
parent 6d9b726210
commit 6ab20c5ad9
20 changed files with 367 additions and 203 deletions
+82 -67
View File
@@ -23,6 +23,17 @@
#include <limits.h>
static const CString SongSortNames[] = {
"Randomize",
"MostPlays",
"FewestPlays",
"TopGrades",
"LowestGrades",
};
XToString( SongSort, NUM_SongSort );
XToThemedString( SongSort, NUM_SongSort );
/* Maximum lower value of ranges when difficult: */
const int MAX_BOTTOM_RANGE = 10;
@@ -44,7 +55,7 @@ CourseType Course::GetCourseType() const
return COURSE_TYPE_ENDLESS;
if( m_iLives > 0 )
return COURSE_TYPE_ONI;
FOREACH_CONST( CourseEntry, m_entries, e )
FOREACH_CONST( CourseEntry, m_vEntries, e )
{
if( e->fGainSeconds > 0 )
return COURSE_TYPE_SURVIVAL;
@@ -211,13 +222,15 @@ void Course::LoadFromCRSFile( CString sPath )
// infer entry::Type from the first param
if( sParams[1].Left(strlen("BEST")) == "BEST" )
{
new_entry.iMostPopularIndex = atoi( sParams[1].Right(sParams[1].size()-strlen("BEST")) ) - 1;
CLAMP( new_entry.iMostPopularIndex, 0, 500 );
new_entry.iChooseIndex = atoi( sParams[1].Right(sParams[1].size()-strlen("BEST")) ) - 1;
CLAMP( new_entry.iChooseIndex, 0, 500 );
new_entry.songSort = SongSort_MostPlays;
}
else if( sParams[1].Left(strlen("WORST")) == "WORST" )
{
new_entry.iLeastPopularIndex = atoi( sParams[1].Right(sParams[1].size()-strlen("WORST")) ) - 1;
CLAMP( new_entry.iLeastPopularIndex, 0, 500 );
new_entry.iChooseIndex = atoi( sParams[1].Right(sParams[1].size()-strlen("WORST")) ) - 1;
CLAMP( new_entry.iChooseIndex, 0, 500 );
new_entry.songSort = SongSort_FewestPlays;
}
else if( sParams[1] == "*" )
{
@@ -231,11 +244,16 @@ void Course::LoadFromCRSFile( CString sPath )
CStringArray bits;
split( sSong, "/", bits );
if( bits.size() == 2 )
{
new_entry.sSongGroup = bits[0];
}
else
{
LOG->Warn( "Course file '%s' contains a random_within_group entry '%s' that is invalid. "
"Song should be in the format '<group>/*'.",
sPath.c_str(), sSong.c_str());
}
if( !SONGMAN->DoesSongGroupExist(new_entry.sSongGroup) )
{
/* XXX: We need a place to put "user warnings". This is too loud for info.txt--
@@ -304,7 +322,7 @@ void Course::LoadFromCRSFile( CString sPath )
new_entry.fGainSeconds = fGainSeconds;
attacks.clear();
m_entries.push_back( new_entry );
m_vEntries.push_back( new_entry );
}
else if( bUseCache && !stricmp(sValueName, "RADAR") )
{
@@ -331,7 +349,7 @@ void Course::LoadFromCRSFile( CString sPath )
/* Cache and load the course banner. Only bother doing this if at least one
* song was found in the course. */
if( m_sBannerPath != "" && !m_entries.empty() )
if( m_sBannerPath != "" && !m_vEntries.empty() )
BANNERCACHE->CacheBanner( m_sBannerPath );
/* Cache each trail RadarValues that's slow to load, so we
@@ -371,10 +389,10 @@ void Course::Init()
m_bRandomize = false;
m_iLives = -1;
m_bSortByMeter = false;
m_entries.clear();
m_vEntries.clear();
FOREACH_Difficulty(dc)
m_iCustomMeter[dc] = -1;
m_entries.clear();
m_vEntries.clear();
m_sPath = "";
m_sGroupName = "";
m_sMainTitle = "";
@@ -439,9 +457,9 @@ void Course::Save( CString sPath, bool bSavingCache )
f.PutLine( "// end cache tags" );
}
for( unsigned i=0; i<m_entries.size(); i++ )
for( unsigned i=0; i<m_vEntries.size(); i++ )
{
const CourseEntry& entry = m_entries[i];
const CourseEntry& entry = m_vEntries[i];
for( unsigned j = 0; j < entry.attacks.size(); ++j )
{
@@ -462,13 +480,13 @@ void Course::Save( CString sPath, bool bSavingCache )
if( entry.fGainSeconds > 0 )
f.PutLine( ssprintf("#GAINSECONDS:%f;", entry.fGainSeconds) );
if( entry.iMostPopularIndex != -1 )
if( entry.songSort == SongSort_MostPlays && entry.iChooseIndex != -1 )
{
f.Write( ssprintf( "#SONG:BEST%d", entry.iMostPopularIndex+1 ) );
f.Write( ssprintf( "#SONG:BEST%d", entry.iChooseIndex+1 ) );
}
else if( entry.iLeastPopularIndex != -1 )
else if( entry.songSort == SongSort_FewestPlays && entry.iChooseIndex != -1 )
{
f.Write( ssprintf( "#SONG:WORST%d", entry.iLeastPopularIndex+1 ) );
f.Write( ssprintf( "#SONG:WORST%d", entry.iChooseIndex+1 ) );
}
else if( entry.pSong )
{
@@ -550,7 +568,7 @@ void Course::AutogenEndlessFromGroup( CString sGroupName, Difficulty diff )
vector<Song*> vSongs;
SONGMAN->GetSongs( vSongs, e.sSongGroup );
for( unsigned i = 0; i < vSongs.size(); ++i)
m_entries.push_back( e );
m_vEntries.push_back( e );
}
void Course::AutogenNonstopFromGroup( CString sGroupName, Difficulty diff )
@@ -562,10 +580,10 @@ void Course::AutogenNonstopFromGroup( CString sGroupName, Difficulty diff )
m_sMainTitle += " Random";
// resize to 4
while( m_entries.size() < 4 )
m_entries.push_back( m_entries[0] );
while( m_entries.size() > 4 )
m_entries.pop_back();
while( m_vEntries.size() < 4 )
m_vEntries.push_back( m_vEntries[0] );
while( m_vEntries.size() > 4 )
m_vEntries.pop_back();
}
void Course::AutogenOniFromArtist( CString sArtistName, CString sArtistNameTranslit, vector<Song*> aSongs, Difficulty dc )
@@ -608,7 +626,7 @@ void Course::AutogenOniFromArtist( CString sArtistName, CString sArtistNameTrans
for( unsigned i = 0; i < aSongs.size(); ++i )
{
e.pSong = aSongs[i];
m_entries.push_back( e );
m_vEntries.push_back( e );
}
}
@@ -672,7 +690,7 @@ Trail* Course::GetTrail( StepsType st, CourseDifficulty cd ) const
{
/* If we have any random entries (so that the seed matters), invalidate the cache. */
bool bHaveRandom = false;
FOREACH_CONST( CourseEntry, m_entries, e )
FOREACH_CONST( CourseEntry, m_vEntries, e )
{
if( e->IsRandomSong() )
{
@@ -792,11 +810,11 @@ bool Course::GetTrailUnsorted( StepsType st, CourseDifficulty cd, Trail &trail )
/* Always randomize the same way per round. Otherwise, the displayed course
* will change every time it's viewed, and the displayed order will have no
* bearing on what you'll actually play. */
tmp_entries = m_entries;
tmp_entries = m_vEntries;
random_shuffle( tmp_entries.begin(), tmp_entries.end(), rnd );
}
const vector<CourseEntry> &entries = m_bRandomize? tmp_entries:m_entries;
const vector<CourseEntry> &entries = m_bRandomize? tmp_entries:m_vEntries;
/* This can take some time, so don't fill it out unless we need it. */
bool bMostPlayedSet = false;
@@ -936,39 +954,36 @@ bool Course::GetTrailUnsorted( StepsType st, CourseDifficulty cd, Trail &trail )
// TODO: Move Course initialization after PROFILEMAN is created
if( PROFILEMAN && e->iMostPopularIndex != -1 )
switch( e->songSort )
{
SongUtil::SortSongPointerArrayByNumPlays( vpPossibleSongs, PROFILEMAN->GetMachineProfile(), true ); // descending
if( e->iMostPopularIndex < vpPossibleSongs.size() )
{
pResolvedSong = vpPossibleSongs[e->iMostPopularIndex];
vector<Steps*> &vpPossibleSteps = mapSongToSteps[pResolvedSong];
pResolvedSteps = vpPossibleSteps[0];
}
default:
ASSERT(0);
case SongSort_Randomize:
random_shuffle( vpPossibleSongs.begin(), vpPossibleSongs.end(), rnd );
break;
case SongSort_MostPlays:
if( PROFILEMAN )
SongUtil::SortSongPointerArrayByNumPlays( vpPossibleSongs, PROFILEMAN->GetMachineProfile(), true ); // descending
break;
case SongSort_FewestPlays:
if( PROFILEMAN )
SongUtil::SortSongPointerArrayByNumPlays( vpPossibleSongs, PROFILEMAN->GetMachineProfile(), false ); // ascending
break;
case SongSort_TopGrades:
SongUtil::SortSongPointerArrayByGrades( vpPossibleSongs, true ); // descending
break;
case SongSort_LowestGrades:
SongUtil::SortSongPointerArrayByGrades( vpPossibleSongs, false ); // ascending
break;
}
else if( PROFILEMAN && e->iLeastPopularIndex != -1 )
if( e->iChooseIndex < vpPossibleSongs.size() )
{
SongUtil::SortSongPointerArrayByNumPlays( vpPossibleSongs, PROFILEMAN->GetMachineProfile(), false ); // ascending
if( e->iLeastPopularIndex < vpPossibleSongs.size() )
{
pResolvedSong = vpPossibleSongs[e->iLeastPopularIndex];
vector<Steps*> &vpPossibleSteps = mapSongToSteps[pResolvedSong];
pResolvedSteps = vpPossibleSteps[0];
}
}
else
{
if( !vpPossibleSongs.empty() )
{
random_shuffle( vpPossibleSongs.begin(), vpPossibleSongs.end(), rnd );
pResolvedSong = vpPossibleSongs[0];
vector<Steps*> &vpPossibleSteps = mapSongToSteps[pResolvedSong];
if( !vpPossibleSteps.empty() )
{
random_shuffle( vpPossibleSteps.begin(), vpPossibleSteps.end(), rnd );
pResolvedSteps = vpPossibleSteps[0];
}
}
pResolvedSong = vpPossibleSongs[e->iChooseIndex];
vector<Steps*> &vpPossibleSteps = mapSongToSteps[pResolvedSong];
ASSERT( !vpPossibleSteps.empty() ); // if no steps are playable, this shouldn't be a possible song
random_shuffle( vpPossibleSteps.begin(), vpPossibleSteps.end(), rnd );
pResolvedSteps = vpPossibleSteps[0];
}
@@ -1096,7 +1111,7 @@ void Course::GetAllTrails( vector<Trail*> &AddTo ) const
bool Course::HasMods() const
{
FOREACH_CONST( CourseEntry, m_entries, e )
FOREACH_CONST( CourseEntry, m_vEntries, e )
{
if( !e->sModifiers.empty() || !e->attacks.empty() )
return true;
@@ -1107,7 +1122,7 @@ bool Course::HasMods() const
bool Course::AllSongsAreFixed() const
{
FOREACH_CONST( CourseEntry, m_entries, e )
FOREACH_CONST( CourseEntry, m_vEntries, e )
{
if( e->pSong == NULL )
return false;
@@ -1117,7 +1132,7 @@ bool Course::AllSongsAreFixed() const
void Course::Invalidate( Song *pStaleSong )
{
FOREACH_CONST( CourseEntry, m_entries, e )
FOREACH_CONST( CourseEntry, m_vEntries, e )
{
if( e->pSong == pStaleSong ) // a fixed entry that references the stale Song
{
@@ -1161,8 +1176,8 @@ RageColor Course::GetColor() const
switch( PREFSMAN->m_CourseSortOrder )
{
case PrefsManager::COURSE_SORT_SONGS:
if( m_entries.size() >= 7 ) return SORT_LEVEL2_COLOR;
else if( m_entries.size() >= 4 ) return SORT_LEVEL4_COLOR;
if( m_vEntries.size() >= 7 ) return SORT_LEVEL2_COLOR;
else if( m_vEntries.size() >= 4 ) return SORT_LEVEL4_COLOR;
else return SORT_LEVEL5_COLOR;
case PrefsManager::COURSE_SORT_METER:
@@ -1192,9 +1207,9 @@ RageColor Course::GetColor() const
bool Course::IsFixed() const
{
for(unsigned i = 0; i < m_entries.size(); i++)
for(unsigned i = 0; i < m_vEntries.size(); i++)
{
if ( m_entries[i].pSong == NULL )
if ( m_vEntries[i].pSong == NULL )
continue;
return false;
@@ -1217,11 +1232,11 @@ bool Course::GetTotalSeconds( StepsType st, float& fSecondsOut ) const
bool Course::CourseHasBestOrWorst() const
{
FOREACH_CONST( CourseEntry, m_entries, e )
FOREACH_CONST( CourseEntry, m_vEntries, e )
{
if( e->iMostPopularIndex != -1 )
if( e->iChooseIndex == SongSort_MostPlays && e->iChooseIndex != -1 )
return true;
if( e->iLeastPopularIndex != -1 )
if( e->iChooseIndex == SongSort_FewestPlays && e->iChooseIndex != -1 )
return true;
}
@@ -1238,9 +1253,9 @@ void Course::UpdateCourseStats( StepsType st )
m_SortOrder_TotalDifficulty = 0;
// courses with random/players best-worst songs should go at the end
for(unsigned i = 0; i < m_entries.size(); i++)
for(unsigned i = 0; i < m_vEntries.size(); i++)
{
if ( m_entries[i].pSong != NULL )
if ( m_vEntries[i].pSong != NULL )
continue;
if ( m_SortOrder_Ranking == 2 )
@@ -1277,7 +1292,7 @@ bool Course::IsRanking() const
const CourseEntry *Course::FindFixedSong( const Song *pSong ) const
{
FOREACH_CONST( CourseEntry, m_entries, e )
FOREACH_CONST( CourseEntry, m_vEntries, e )
{
const CourseEntry &entry = *e;
if( entry.pSong == pSong )
+22 -8
View File
@@ -32,6 +32,19 @@ inline PlayMode CourseTypeToPlayMode( CourseType ct ) { return (PlayMode)(PLAY_M
inline CourseType PlayModeToCourseType( PlayMode pm ) { return (CourseType)(pm-PLAY_MODE_NONSTOP); }
enum SongSort
{
SongSort_Randomize,
SongSort_MostPlays,
SongSort_FewestPlays,
SongSort_TopGrades,
SongSort_LowestGrades,
NUM_SongSort
};
#define FOREACH_SongSort( i ) FOREACH_ENUM( SongSort, NUM_SongSort, i )
const CString& SongSortToString( SongSort ss );
const CString& SongSortToThemedString( SongSort ss );
class CourseEntry
{
public:
@@ -44,8 +57,9 @@ public:
bool bNoDifficult; // if true, CourseDifficulty doesn't affect this entry
int iLowMeter; // don't filter if -1
int iHighMeter; // don't filter if -1
int iMostPopularIndex; // don't filter if -1
int iLeastPopularIndex; // don't filter if -1
SongSort songSort; // sort by this after filtering
int iChooseIndex; //
CString sModifiers; // set player and song options using these
AttackArray attacks; // timed sModifiers
@@ -61,8 +75,9 @@ public:
bNoDifficult = false;
iLowMeter = -1;
iHighMeter = -1;
iMostPopularIndex = -1;
iLeastPopularIndex = -1;
songSort = SongSort_Randomize;
iChooseIndex = 0;
sModifiers = "";
fGainSeconds = 0;
@@ -71,8 +86,7 @@ public:
bool IsRandomSong() const
{
return
iMostPopularIndex == -1 &&
iLeastPopularIndex == -1 &&
iChooseIndex == -1 &&
pSong == NULL;
}
};
@@ -101,7 +115,7 @@ public:
int m_iCustomMeter[NUM_DIFFICULTIES]; // -1 = no meter specified
bool m_bSortByMeter;
vector<CourseEntry> m_entries;
vector<CourseEntry> m_vEntries;
/* If PREFSMAN->m_bShowNative is off, these are the same as GetTranslit* below.
* Otherwise, they return the main titles. */
@@ -124,7 +138,7 @@ public:
bool HasMods() const;
bool AllSongsAreFixed() const;
int GetEstimatedNumStages() const { return m_entries.size(); }
int GetEstimatedNumStages() const { return m_vEntries.size(); }
bool IsPlayableIn( StepsType st ) const;
bool CourseHasBestOrWorst() const;
RageColor GetColor() const;
+1 -3
View File
@@ -75,8 +75,7 @@ GameState::GameState() :
m_stEdit( MESSAGE_EDIT_STEPS_TYPE_CHANGED ),
m_pEditSourceSteps( MESSAGE_EDIT_SOURCE_STEPS_CHANGED ),
m_stEditSource( MESSAGE_EDIT_SOURCE_STEPS_TYPE_CHANGED ),
m_iEditCourseEntryIndex(MESSAGE_EDIT_COURSE_ENTRY_INDEX_CHANGED ),
m_EditCourseEntryAction(MESSAGE_EDIT_COURSE_ENTRY_ACTION_CHANGED )
m_iEditCourseEntryIndex(MESSAGE_EDIT_COURSE_ENTRY_INDEX_CHANGED )
{
m_pCurStyle.Set( NULL );
@@ -255,7 +254,6 @@ void GameState::Reset()
m_pEditSourceSteps.Set( NULL );
m_stEditSource.Set( STEPS_TYPE_INVALID );
m_iEditCourseEntryIndex.Set( -1 );
m_EditCourseEntryAction.Set( ACTION_EDIT );
ApplyCmdline();
}
-2
View File
@@ -299,8 +299,6 @@ public:
BroadcastOnChangePtr<Steps> m_pEditSourceSteps;
BroadcastOnChange<StepsType> m_stEditSource;
BroadcastOnChange<int> m_iEditCourseEntryIndex;
enum EditCourseEntryAction { ACTION_EDIT, ACTION_INSERT };
BroadcastOnChange<EditCourseEntryAction> m_EditCourseEntryAction;
// Workout stuff
float GetGoalPercentComplete( PlayerNumber pn );
+1 -1
View File
@@ -75,7 +75,7 @@ void LifeMeterTime::OnLoadSong()
Course* pCourse = GAMESTATE->m_pCurCourse;
ASSERT( pCourse );
const CourseEntry *pEntry = &pCourse->m_entries[GAMESTATE->GetCourseSongIndex()];
const CourseEntry *pEntry = &pCourse->m_vEntries[GAMESTATE->GetCourseSongIndex()];
m_fLifeTotalGainedSeconds += pEntry->fGainSeconds;
if( GAMESTATE->GetCourseSongIndex() > 0 )
-1
View File
@@ -24,7 +24,6 @@ static const CString MessageNames[] = {
"EditPreferredCourseDifficutyP1Changed",
"EditPreferredCourseDifficutyP2Changed",
"EditCourseEntryIndexChanged",
"EditCourseEntryActionChanged",
"GoalCompleteP1",
"GoalCompleteP2",
"NoteCrossed",
-1
View File
@@ -32,7 +32,6 @@ enum Message
MESSAGE_EDIT_PREFERRED_COURSE_DIFFICULTY_P1_CHANGED,
MESSAGE_EDIT_PREFERRED_COURSE_DIFFICULTY_P2_CHANGED,
MESSAGE_EDIT_COURSE_ENTRY_INDEX_CHANGED,
MESSAGE_EDIT_COURSE_ENTRY_ACTION_CHANGED,
MESSAGE_GOAL_COMPLETE_P1,
MESSAGE_GOAL_COMPLETE_P2,
MESSAGE_NOTE_CROSSED,
+1 -1
View File
@@ -508,7 +508,7 @@ void MusicWheel::BuildWheelItemDatas( vector<WheelItemData> &arrayWheelItemDatas
bUseSections = false;
break;
case SORT_TOP_GRADES:
SongUtil::SortSongPointerArrayByGrade( arraySongs );
SongUtil::SortSongPointerArrayByGrades( arraySongs, true );
break;
case SORT_ARTIST:
SongUtil::SortSongPointerArrayByArtist( arraySongs );
+30
View File
@@ -691,6 +691,36 @@ void OptionRow::SetOneSharedSelection( int iChoice )
SetOneSelection( pn, iChoice );
}
int OptionRow::GetChoiceInRowWithFocus( PlayerNumber pn ) const
{
if( m_RowDef.bOneChoiceForAllPlayers )
pn = PLAYER_1;
if( m_RowDef.choices.empty() )
return -1;
int iChoice = m_iChoiceInRowWithFocus[pn];
return iChoice;
}
int OptionRow::GetChoiceInRowWithFocusShared() const
{
return GetChoiceInRowWithFocus( (PlayerNumber)0 );
}
void OptionRow::SetChoiceInRowWithFocus( PlayerNumber pn, int iChoice )
{
if( m_RowDef.bOneChoiceForAllPlayers )
pn = PLAYER_1;
ASSERT(iChoice >= 0 && iChoice < (int)m_RowDef.choices.size());
m_iChoiceInRowWithFocus[pn] = iChoice;
}
void OptionRow::SetChoiceInRowWithFocusShared( int iChoice )
{
FOREACH_PlayerNumber( pn )
SetChoiceInRowWithFocus( pn, iChoice );
}
void OptionRow::SetExitText( CString sExitText )
{
BitmapText *bt = m_textItems.back();
+5 -16
View File
@@ -107,22 +107,11 @@ public:
void SetOneSelection( PlayerNumber pn, int iChoice );
void SetOneSharedSelection( int iChoice );
int GetChoiceInRowWithFocus( PlayerNumber pn ) const
{
if( m_RowDef.bOneChoiceForAllPlayers )
pn = PLAYER_1;
if( m_RowDef.choices.empty() )
return -1;
int iChoice = m_iChoiceInRowWithFocus[pn];
return iChoice;
}
void SetChoiceInRowWithFocus( PlayerNumber pn, int iChoice )
{
if( m_RowDef.bOneChoiceForAllPlayers )
pn = PLAYER_1;
ASSERT(iChoice >= 0 && iChoice < (int)m_RowDef.choices.size());
m_iChoiceInRowWithFocus[pn] = iChoice;
}
int GetChoiceInRowWithFocus( PlayerNumber pn ) const;
int GetChoiceInRowWithFocusShared() const;
void SetChoiceInRowWithFocus( PlayerNumber pn, int iChoice );
void SetChoiceInRowWithFocusShared( int iChoice );
bool GetSelected( PlayerNumber pn, int iChoice ) const
{
if( m_RowDef.bOneChoiceForAllPlayers )
+1 -1
View File
@@ -78,7 +78,7 @@ void ScoreDisplayLifeTime::OnLoadSong()
Course* pCourse = GAMESTATE->m_pCurCourse;
ASSERT( pCourse );
const CourseEntry *pEntry = &pCourse->m_entries[GAMESTATE->GetCourseSongIndex()];
const CourseEntry *pEntry = &pCourse->m_vEntries[GAMESTATE->GetCourseSongIndex()];
PlayGainLoss( GAIN_LIFE_COMMAND_NAME, pEntry->fGainSeconds );
}
+1
View File
@@ -204,6 +204,7 @@ void ScreenCourseManager::GoToNextScreen()
default:
ASSERT(0);
case ACTION_EDIT:
GAMESTATE->m_iEditCourseEntryIndex.Set( 0 );
SCREENMAN->SetNewScreen( "ScreenEditCourse" );
break;
case ACTION_DELETE:
+5 -5
View File
@@ -1390,9 +1390,9 @@ void ScreenEdit::InputEdit( const DeviceInput& DeviceI, const InputEventType typ
const Course *crs = courses[i];
bool bUsesThisSong = false;
for( unsigned e = 0; e < crs->m_entries.size(); ++e )
for( unsigned e = 0; e < crs->m_vEntries.size(); ++e )
{
if( crs->m_entries[e].pSong != m_pSong )
if( crs->m_vEntries[e].pSong != m_pSong )
continue;
bUsesThisSong = true;
}
@@ -2812,12 +2812,12 @@ void ScreenEdit::SetupCourseAttacks()
m_pAttacksFromCourse->LoadFromCRSFile( m_pAttacksFromCourse->m_sPath );
AttackArray Attacks;
for( unsigned e = 0; e < m_pAttacksFromCourse->m_entries.size(); ++e )
for( unsigned e = 0; e < m_pAttacksFromCourse->m_vEntries.size(); ++e )
{
if( m_pAttacksFromCourse->m_entries[e].pSong != m_pSong )
if( m_pAttacksFromCourse->m_vEntries[e].pSong != m_pSong )
continue;
Attacks = m_pAttacksFromCourse->m_entries[e].attacks;
Attacks = m_pAttacksFromCourse->m_vEntries[e].attacks;
break;
}
+68 -57
View File
@@ -17,6 +17,7 @@ enum EditCourseRow
ROW_TYPE_METER,
ROW_EDIT_ENTRY,
ROW_INSERT_ENTRY,
ROW_DELETE_ENTRY,
ROW_DONE,
};
@@ -56,14 +57,18 @@ void ScreenEditCourse::Init()
{
ScreenOptions::Init();
// save a backup that we'll use if we revert.
Course *pCourse = GAMESTATE->m_pCurCourse;
m_Original = *pCourse;
vector<OptionRowDefinition> vDefs;
vector<OptionRowHandler*> vHands;
OptionRowDefinition def;
def.layoutType = LAYOUT_SHOW_ONE_IN_ROW;
Course *pCourse = GAMESTATE->m_pCurCourse;
def.name = "Title";
def.choices.clear();
def.choices.push_back( pCourse->GetTranslitFullTitle() );
@@ -94,7 +99,6 @@ void ScreenEditCourse::Init()
def.name = "Type";
def.choices.clear();
FOREACH_CONST( StepsType, STEPS_TYPES_TO_SHOW.GetValue(), st )
def.choices.push_back( GAMEMAN->StepsTypeToString(*st) );
vDefs.push_back( def );
@@ -102,19 +106,36 @@ void ScreenEditCourse::Init()
def.name = "Type Meter";
def.choices.clear();
def.choices.push_back( "" );
for( int i=MIN_METER; i<=MAX_METER; i++ )
def.choices.push_back( ssprintf("%d",i) );
vDefs.push_back( def );
vHands.push_back( NULL );
def.name = "Edit Entry";
def.choices.clear();
def.choices.push_back( "" );
for( unsigned i=0; i<pCourse->m_vEntries.size(); i++ )
def.choices.push_back( ssprintf("%u of %u",i+1,pCourse->m_vEntries.size()) );
vDefs.push_back( def );
vHands.push_back( NULL );
def.name = "Insert Entry";
def.choices.clear();
def.choices.push_back( "" );
for( unsigned i=0; i<=pCourse->m_vEntries.size(); i++ )
{
CString s;
if( i == pCourse->m_vEntries.size() )
s = ssprintf("After %u",i);
else
s = ssprintf("Before %u",i+1);
def.choices.push_back( s );
}
vDefs.push_back( def );
vHands.push_back( NULL );
def.name = "Delete Entry";
def.choices.clear();
for( unsigned i=0; i<pCourse->m_vEntries.size(); i++ )
def.choices.push_back( ssprintf("%u of %u",i+1,pCourse->m_vEntries.size()) );
vDefs.push_back( def );
vHands.push_back( NULL );
@@ -131,6 +152,7 @@ void ScreenEditCourse::HandleScreenMessage( const ScreenMessage SM )
void ScreenEditCourse::AfterChangeValueInRow( PlayerNumber pn )
{
ScreenOptions::AfterChangeValueInRow( pn );
Course *pCourse = GAMESTATE->m_pCurCourse;
StepsType st = STEPS_TYPE_INVALID;
CourseDifficulty cd = DIFFICULTY_INVALID;
@@ -174,48 +196,8 @@ void ScreenEditCourse::AfterChangeValueInRow( PlayerNumber pn )
OptionRow &row = *m_pRows[ROW_TYPE_METER];
OptionRowDefinition def = row.GetRowDef();
Trail *pTrail = GAMESTATE->m_pCurTrail[GAMESTATE->m_MasterPlayerNumber];
def.choices.clear();
if( pTrail != NULL )
{
for( int i=MIN_METER; i<=MAX_METER; i++ )
def.choices.push_back( ssprintf("%d",i) );
row.SetOneSharedSelection( pTrail->GetMeter()-MIN_METER );
}
else
{
def.choices.push_back( "N/A" );
}
row.Reload( def );
}
// refresh edit entry
{
OptionRow &row = *m_pRows[ROW_EDIT_ENTRY];
OptionRowDefinition def = row.GetRowDef();
def.choices.clear();
Trail *pTrail = GAMESTATE->m_pCurTrail[GAMESTATE->m_MasterPlayerNumber];
ASSERT( pTrail );
for( unsigned i=0; i<pTrail->m_vEntries.size(); i++ )
def.choices.push_back( ssprintf("%u of %u",i+1,pTrail->m_vEntries.size()) );
row.SetOneSharedSelection( 0 );
row.Reload( def );
}
// refresh insert entry
{
OptionRow &row = *m_pRows[ROW_INSERT_ENTRY];
OptionRowDefinition def = row.GetRowDef();
def.choices.clear();
Trail *pTrail = GAMESTATE->m_pCurTrail[GAMESTATE->m_MasterPlayerNumber];
ASSERT( pTrail );
for( unsigned i=0; i<=pTrail->m_vEntries.size(); i++ )
{
CString s;
if( i == pTrail->m_vEntries.size() )
s = ssprintf("After %u",i);
else
s = ssprintf("Before %u",i+1);
def.choices.push_back( s );
}
row.SetOneSharedSelection( 0 );
row.SetOneSharedSelection( pTrail->GetMeter()-MIN_METER );
row.Reload( def );
}
// fall through
@@ -228,8 +210,6 @@ void ScreenEditCourse::AfterChangeValueInRow( PlayerNumber pn )
}
// fall through
case ROW_EDIT_ENTRY:
// fall through
case ROW_INSERT_ENTRY:
// export entry number
{
EditCourseRow ecr = m_iCurrentRow[GAMESTATE->m_MasterPlayerNumber] == ROW_EDIT_ENTRY ? ROW_EDIT_ENTRY : ROW_INSERT_ENTRY;
@@ -238,14 +218,28 @@ void ScreenEditCourse::AfterChangeValueInRow( PlayerNumber pn )
GAMESTATE->m_iEditCourseEntryIndex.Set( iChoice );
}
// fall through
case ROW_INSERT_ENTRY:
// fall through
case ROW_DELETE_ENTRY:
// fall through
case ROW_DONE:
break;
}
}
void ScreenEditCourse::ImportOptions( int row, const vector<PlayerNumber> &vpns )
void ScreenEditCourse::ImportOptions( int iRow, const vector<PlayerNumber> &vpns )
{
Course *pCourse = GAMESTATE->m_pCurCourse;
switch( iRow )
{
case ROW_EDIT_ENTRY:
case ROW_INSERT_ENTRY:
case ROW_DELETE_ENTRY:
OptionRow &row = *m_pRows[iRow];
row.SetChoiceInRowWithFocusShared( GAMESTATE->m_iEditCourseEntryIndex );
break;
}
}
void ScreenEditCourse::ExportOptions( int row, const vector<PlayerNumber> &vpns )
@@ -265,6 +259,10 @@ void ScreenEditCourse::GoToNextScreen()
case ROW_TYPE:
case ROW_TYPE_METER:
ASSERT(0);
case ROW_INSERT_ENTRY:
case ROW_DELETE_ENTRY:
SCREENMAN->SetNewScreen( "ScreenEditCourse" );
break;
case ROW_EDIT_ENTRY:
SCREENMAN->SetNewScreen( "ScreenEditCourseEntry" );
break;
@@ -276,11 +274,17 @@ void ScreenEditCourse::GoToNextScreen()
void ScreenEditCourse::GoToPrevScreen()
{
// revert
Course *pCourse = GAMESTATE->m_pCurCourse;
*pCourse = m_Original;
SCREENMAN->SetNewScreen( "ScreenCourseManager" );
}
void ScreenEditCourse::ProcessMenuStart( PlayerNumber pn, const InputEventType type )
{
Course *pCourse = GAMESTATE->m_pCurCourse;
switch( m_iCurrentRow[GAMESTATE->m_MasterPlayerNumber] )
{
default:
@@ -293,16 +297,23 @@ void ScreenEditCourse::ProcessMenuStart( PlayerNumber pn, const InputEventType t
case ROW_TYPE_METER:
SCREENMAN->PlayInvalidSound();
break;
case ROW_EDIT_ENTRY:
case ROW_INSERT_ENTRY:
{
Trail *pTrail = GAMESTATE->m_pCurTrail[GAMESTATE->m_MasterPlayerNumber];
if( pTrail == NULL )
{
SCREENMAN->PlayInvalidSound();
return;
}
OptionRow &row = *m_pRows[ROW_INSERT_ENTRY];
int iChoice = row.GetChoiceInRowWithFocus( GAMESTATE->m_MasterPlayerNumber );
pCourse->m_vEntries.insert( pCourse->m_vEntries.begin()+iChoice, CourseEntry() );
ScreenOptions::BeginFadingOut();
}
break;
case ROW_DELETE_ENTRY:
{
OptionRow &row = *m_pRows[ROW_DELETE_ENTRY];
int iChoice = row.GetChoiceInRowWithFocus( GAMESTATE->m_MasterPlayerNumber );
pCourse->m_vEntries.erase( pCourse->m_vEntries.begin()+iChoice );
ScreenOptions::BeginFadingOut();
}
break;
case ROW_EDIT_ENTRY:
case ROW_DONE:
ScreenOptions::BeginFadingOut();
break;
+3
View File
@@ -2,6 +2,7 @@
#define ScreenEditCourse_H
#include "ScreenOptions.h"
#include "Course.h"
class ScreenEditCourse : public ScreenOptions
{
@@ -21,6 +22,8 @@ protected:
virtual void AfterChangeValueInRow( PlayerNumber pn );
virtual void ProcessMenuStart( PlayerNumber pn, const InputEventType type );
Course m_Original;
};
#endif
+134 -34
View File
@@ -14,13 +14,15 @@ enum EditCourseEntryRow
ROW_BASE_DIFFICULTY,
ROW_LOW_METER,
ROW_HIGH_METER,
ROW_BEST_WORST_VALUE,
ROW_SORT,
ROW_CHOOSE_INDEX,
ROW_SET_MODS,
ROW_DONE,
NUM_EditCourseEntryRow
};
#define FOREACH_EditCourseEntryRow( i ) FOREACH_ENUM( EditCourseEntryRow, NUM_EditCourseEntryRow, i )
REGISTER_SCREEN_CLASS( ScreenEditCourseEntry );
ScreenEditCourseEntry::ScreenEditCourseEntry( CString sName ) : ScreenOptions( sName )
{
@@ -31,6 +33,12 @@ void ScreenEditCourseEntry::Init()
{
ScreenOptions::Init();
// save a backup that we'll use if we revert.
Course *pCourse = GAMESTATE->m_pCurCourse;
m_Original = pCourse->m_vEntries[ GAMESTATE->m_iEditCourseEntryIndex ];
vector<OptionRowDefinition> vDefs;
vector<OptionRowHandler*> vHands;
@@ -41,6 +49,7 @@ void ScreenEditCourseEntry::Init()
def.choices.clear();
vector<CString> vsSongGroups;
SONGMAN->GetSongGroupNames( vsSongGroups );
def.choices.push_back( "(any)" );
FOREACH_CONST( CString, vsSongGroups, s )
def.choices.push_back( *s );
vDefs.push_back( def );
@@ -54,6 +63,7 @@ void ScreenEditCourseEntry::Init()
def.name = "Base Difficulty";
def.choices.clear();
def.choices.push_back( "(any)" );
FOREACH_CONST( Difficulty, DIFFICULTIES_TO_SHOW.GetValue(), dc )
def.choices.push_back( DifficultyToThemedString(*dc) );
vDefs.push_back( def );
@@ -61,6 +71,7 @@ void ScreenEditCourseEntry::Init()
def.name = "Low Meter";
def.choices.clear();
def.choices.push_back( "(any)" );
for( int i=MIN_METER; i<=MAX_METER; i++ )
def.choices.push_back( ssprintf("%i",i) );
vDefs.push_back( def );
@@ -68,15 +79,23 @@ void ScreenEditCourseEntry::Init()
def.name = "High Meter";
def.choices.clear();
def.choices.push_back( "(any)" );
for( int i=MIN_METER; i<=MAX_METER; i++ )
def.choices.push_back( ssprintf("%i",i) );
vDefs.push_back( def );
vHands.push_back( NULL );
def.name = "Best/Worst Value";
def.name = "Sort";
def.choices.clear();
for( int i=1; i<=20; i++ )
def.choices.push_back( ssprintf("%i",i) );
FOREACH_SongSort( i )
def.choices.push_back( SongSortToThemedString(i) );
vDefs.push_back( def );
vHands.push_back( NULL );
def.name = "Choose";
def.choices.clear();
for( int i=0; i<20; i++ )
def.choices.push_back( FormatNumberAndSuffix(i+1) );
vDefs.push_back( def );
vHands.push_back( NULL );
@@ -88,7 +107,7 @@ void ScreenEditCourseEntry::Init()
ScreenOptions::InitMenu( INPUTMODE_SHARE_CURSOR, vDefs, vHands );
AfterChangeValueInRow( GAMESTATE->m_MasterPlayerNumber );
ImportAllOptions();
}
void ScreenEditCourseEntry::HandleScreenMessage( const ScreenMessage SM )
@@ -100,8 +119,7 @@ void ScreenEditCourseEntry::AfterChangeValueInRow( PlayerNumber pn )
{
ScreenOptions::AfterChangeValueInRow( pn );
Course *pCourse = GAMESTATE->m_pCurCourse;
CourseEntry &ce = pCourse->m_entries[ GAMESTATE->m_iEditCourseEntryIndex ];
CString sSongGroup;
CourseEntry &ce = pCourse->m_vEntries[ GAMESTATE->m_iEditCourseEntryIndex ];
switch( m_iCurrentRow[pn] )
{
@@ -110,22 +128,29 @@ void ScreenEditCourseEntry::AfterChangeValueInRow( PlayerNumber pn )
{
OptionRow &row = *m_pRows[ROW_SONG_GROUP];
int iChoice = row.GetChoiceInRowWithFocus( GAMESTATE->m_MasterPlayerNumber );
sSongGroup = row.GetRowDef().choices[ iChoice ];
if( iChoice == 0 )
ce.sSongGroup = "";
else
ce.sSongGroup = row.GetRowDef().choices[ iChoice ];
}
// refresh songs
{
OptionRow &row = *m_pRows[ROW_SONG];
OptionRowDefinition def = row.GetRowDef();
def.choices.clear();
def.choices.push_back( "(any)" );
vector<Song*> vpSongs;
SONGMAN->GetSongs( vpSongs, sSongGroup );
if( ce.sSongGroup.empty() )
SONGMAN->GetSongs( vpSongs );
else
SONGMAN->GetSongs( vpSongs, ce.sSongGroup );
FOREACH_CONST( Song*, vpSongs, s )
def.choices.push_back( (*s)->GetTranslitFullTitle() );
vector<Song*>::const_iterator iter = find( vpSongs.begin(), vpSongs.end(), ce.pSong );
if( iter != vpSongs.end() )
{
int iSongIndex = iter - vpSongs.begin();
row.SetOneSharedSelection( iSongIndex );
row.SetOneSharedSelection( iSongIndex+1 );
}
else
{
@@ -139,7 +164,10 @@ void ScreenEditCourseEntry::AfterChangeValueInRow( PlayerNumber pn )
{
OptionRow &row = *m_pRows[ROW_SONG];
int iChoice = row.GetChoiceInRowWithFocus( GAMESTATE->m_MasterPlayerNumber );
ce.pSong = SONGMAN->GetAllSongs()[iChoice];
if( iChoice == 0 )
ce.pSong = NULL;
else
ce.pSong = SONGMAN->GetAllSongs()[iChoice-1];
}
// fall through
case ROW_BASE_DIFFICULTY:
@@ -153,16 +181,39 @@ void ScreenEditCourseEntry::AfterChangeValueInRow( PlayerNumber pn )
case ROW_LOW_METER:
// export low meter
{
OptionRow &row = *m_pRows[ROW_LOW_METER];
int iChoice = row.GetChoiceInRowWithFocus( GAMESTATE->m_MasterPlayerNumber );
if( iChoice == 0 )
ce.iLowMeter = -1;
else
ce.iLowMeter = iChoice;
}
// fall through
case ROW_HIGH_METER:
// export high meter
{
OptionRow &row = *m_pRows[ROW_HIGH_METER];
int iChoice = row.GetChoiceInRowWithFocus( GAMESTATE->m_MasterPlayerNumber );
if( iChoice == 0 )
ce.iHighMeter = -1;
else
ce.iHighMeter = iChoice;
}
// fall through
case ROW_BEST_WORST_VALUE:
// export best/worst value
case ROW_SORT:
// export sort
{
OptionRow &row = *m_pRows[ROW_SORT];
int iChoice = row.GetChoiceInRowWithFocus( GAMESTATE->m_MasterPlayerNumber );
ce.songSort = (SongSort)iChoice;
}
// fall through
case ROW_CHOOSE_INDEX:
// export choose index
{
OptionRow &row = *m_pRows[ROW_CHOOSE_INDEX];
int iChoice = row.GetChoiceInRowWithFocus( GAMESTATE->m_MasterPlayerNumber );
ce.iChooseIndex = iChoice;
}
// fall through
case ROW_SET_MODS:
@@ -172,33 +223,77 @@ void ScreenEditCourseEntry::AfterChangeValueInRow( PlayerNumber pn )
}
}
void ScreenEditCourseEntry::ImportOptions( int row, const vector<PlayerNumber> &vpns )
void ScreenEditCourseEntry::ImportAllOptions()
{
Course *pCourse = GAMESTATE->m_pCurCourse;
CourseEntry &ce = pCourse->m_entries[ GAMESTATE->m_iEditCourseEntryIndex ];
// fill choices before importing
AfterChangeValueInRow( GAMESTATE->m_MasterPlayerNumber );
// import entry song
Course *pCourse = GAMESTATE->m_pCurCourse;
CourseEntry &ce = pCourse->m_vEntries[ GAMESTATE->m_iEditCourseEntryIndex ];
// import song group
{
int iSongIndex = -1;
vector<Song*>::const_iterator iter = find( SONGMAN->GetAllSongs().begin(), SONGMAN->GetAllSongs().end(), ce.pSong );
if( iter != SONGMAN->GetAllSongs().end() )
iSongIndex = iter - SONGMAN->GetAllSongs().begin();
OptionRow &row = *m_pRows[ROW_SONG_GROUP];
FOREACH_CONST( CString, row.GetRowDef().choices, s )
{
if( *s == ce.sSongGroup )
{
int iChoice = s - row.GetRowDef().choices.begin();
row.SetOneSharedSelection( iChoice );
AfterChangeValueInRow( GAMESTATE->m_MasterPlayerNumber );
break;
}
}
}
// import song
{
vector<Song*> vpSongs;
SONGMAN->GetSongs( vpSongs, ce.sSongGroup );
vector<Song*>::const_iterator iter = find( vpSongs.begin(), vpSongs.end(), ce.pSong );
int iChoice = 0;
if( iter != vpSongs.end() )
iChoice = iter - vpSongs.begin() + 1;
OptionRow &row = *m_pRows[ROW_SONG];
if( iSongIndex != -1 )
row.SetOneSharedSelection( iSongIndex );
row.SetOneSharedSelection( iChoice );
}
/*
// import entry difficulty
// import base difficulty
{
int iDifficultyIndex = -1;
vector<Difficulty>::const_iterator iter = find( DIFFICULTIES_TO_SHOW.GetValue().begin(), DIFFICULTIES_TO_SHOW.GetValue().end(), ce.difficulty );
vector<Difficulty>::const_iterator iter = find( DIFFICULTIES_TO_SHOW.GetValue().begin(), DIFFICULTIES_TO_SHOW.GetValue().end(), ce.baseDifficulty );
int iChoice = 0;
if( iter != DIFFICULTIES_TO_SHOW.GetValue().end() )
iDifficultyIndex = iter - DIFFICULTIES_TO_SHOW.GetValue().begin();
OptionRow &row = *m_pRows[ROW_DIFFICULTY];
if( iDifficultyIndex != -1 )
row.SetOneSharedSelection( iDifficultyIndex );
iChoice = iter - DIFFICULTIES_TO_SHOW.GetValue().begin() + 1;
OptionRow &row = *m_pRows[ROW_BASE_DIFFICULTY];
row.SetOneSharedSelection( iChoice );
}
// import low meter
{
int iChoice = 0;
if( ce.iLowMeter != -1 )
iChoice = ce.iLowMeter;
OptionRow &row = *m_pRows[ROW_LOW_METER];
row.SetOneSharedSelection( iChoice );
}
// import high meter
{
int iChoice = 0;
if( ce.iHighMeter != -1 )
iChoice = ce.iHighMeter;
OptionRow &row = *m_pRows[ROW_HIGH_METER];
row.SetOneSharedSelection( iChoice );
}
// import sort
{
int iChoice = ce.songSort;
OptionRow &row = *m_pRows[ROW_SORT];
row.SetOneSharedSelection( iChoice );
}
// import choose index
{
int iChoice = ce.iChooseIndex;
OptionRow &row = *m_pRows[ROW_CHOOSE_INDEX];
row.SetOneSharedSelection( iChoice );
}
*/
}
void ScreenEditCourseEntry::ExportOptions( int row, const vector<PlayerNumber> &vpns )
@@ -215,7 +310,7 @@ void ScreenEditCourseEntry::GoToNextScreen()
case ROW_BASE_DIFFICULTY:
case ROW_LOW_METER:
case ROW_HIGH_METER:
case ROW_BEST_WORST_VALUE:
case ROW_CHOOSE_INDEX:
break;
case ROW_SET_MODS:
SCREENMAN->SetNewScreen( "ScreenEditCourseMods" );
@@ -228,6 +323,10 @@ void ScreenEditCourseEntry::GoToNextScreen()
void ScreenEditCourseEntry::GoToPrevScreen()
{
// revert
Course *pCourse = GAMESTATE->m_pCurCourse;
pCourse->m_vEntries[ GAMESTATE->m_iEditCourseEntryIndex ] = m_Original;
SCREENMAN->SetNewScreen( "ScreenEditCourse" );
}
@@ -240,7 +339,8 @@ void ScreenEditCourseEntry::ProcessMenuStart( PlayerNumber pn, const InputEventT
case ROW_BASE_DIFFICULTY:
case ROW_LOW_METER:
case ROW_HIGH_METER:
case ROW_BEST_WORST_VALUE:
case ROW_SORT:
case ROW_CHOOSE_INDEX:
break;
case ROW_SET_MODS:
case ROW_DONE:
+6 -1
View File
@@ -2,6 +2,7 @@
#define ScreenEditCourseEntry_H
#include "ScreenOptions.h"
#include "Course.h"
class ScreenEditCourseEntry : public ScreenOptions
{
@@ -13,7 +14,7 @@ public:
virtual void HandleScreenMessage( const ScreenMessage SM );
protected:
virtual void ImportOptions( int row, const vector<PlayerNumber> &vpns );
virtual void ImportOptions( int row, const vector<PlayerNumber> &vpns ) {}
virtual void ExportOptions( int row, const vector<PlayerNumber> &vpns );
virtual void GoToNextScreen();
@@ -21,6 +22,10 @@ protected:
virtual void AfterChangeValueInRow( PlayerNumber pn );
virtual void ProcessMenuStart( PlayerNumber pn, const InputEventType type );
void ImportAllOptions();
CourseEntry m_Original;
};
#endif
+2 -2
View File
@@ -34,8 +34,8 @@ void ScreenJukebox::SetSong()
//then we pick a song from this course.
Course *pCourse = SONGMAN->GetCourseFromName( THEME->GetCurThemeName() );
if( pCourse != NULL )
for ( unsigned i = 0; i < pCourse->m_entries.size(); i++ )
vSongs.push_back( pCourse->m_entries[i].pSong );
for ( unsigned i = 0; i < pCourse->m_vEntries.size(); i++ )
vSongs.push_back( pCourse->m_vEntries[i].pSong );
if ( vSongs.size() == 0 )
SONGMAN->GetSongs( vSongs, GAMESTATE->m_sPreferredSongGroup );
+4 -2
View File
@@ -107,8 +107,10 @@ void AppendOctal( int n, int digits, CString &out )
bool CompDescending( const pair<Song *, CString> &a, const pair<Song *, CString> &b )
{ return a.second > b.second; }
bool CompAscending( const pair<Song *, CString> &a, const pair<Song *, CString> &b )
{ return a.second < b.second; }
void SongUtil::SortSongPointerArrayByGrade( vector<Song*> &vpSongsInOut )
void SongUtil::SortSongPointerArrayByGrades( vector<Song*> &vpSongsInOut, bool bDescending )
{
/* Optimize by pre-writing a string to compare, since doing GetNumNotesWithGrade
* inside the sort is too slow. */
@@ -130,7 +132,7 @@ void SongUtil::SortSongPointerArrayByGrade( vector<Song*> &vpSongsInOut )
vals.push_back( val(pSong, foo) );
}
sort( vals.begin(), vals.end(), CompDescending );
sort( vals.begin(), vals.end(), bDescending ? CompDescending : CompAscending );
for( unsigned i = 0; i < vpSongsInOut.size(); ++i )
vpSongsInOut[i] = vals[i].first;
+1 -1
View File
@@ -15,7 +15,7 @@ namespace SongUtil
CString MakeSortString( CString s );
void SortSongPointerArrayByTitle( vector<Song*> &vpSongsInOut );
void SortSongPointerArrayByBPM( vector<Song*> &vpSongsInOut );
void SortSongPointerArrayByGrade( vector<Song*> &vpSongsInOut );
void SortSongPointerArrayByGrades( vector<Song*> &vpSongsInOut, bool bDescending );
void SortSongPointerArrayByArtist( vector<Song*> &vpSongsInOut );
void SortSongPointerArrayByDisplayArtist( vector<Song*> &vpSongsInOut );
void SortSongPointerArrayByGenre( vector<Song*> &vpSongsInOut );