store course group names
show courses on wheel with a group color
This commit is contained in:
@@ -72,6 +72,15 @@ void Course::LoadFromCRSFile( CString sPath )
|
||||
|
||||
m_sPath = sPath; // save path
|
||||
|
||||
// save group name
|
||||
{
|
||||
CStringArray parts;
|
||||
split( sPath, "/", parts, false );
|
||||
if( parts.size() >= 4 ) // e.g. "/Courses/blah/fun.cvs"
|
||||
m_sGroupName = parts[parts.size()-2];
|
||||
}
|
||||
|
||||
|
||||
bool bUseCache = true;
|
||||
{
|
||||
/* First look in the cache for this course. Don't bother
|
||||
@@ -375,6 +384,7 @@ void Course::Init()
|
||||
m_iCustomMeter[dc] = -1;
|
||||
m_entries.clear();
|
||||
m_sPath = "";
|
||||
m_sGroupName = "";
|
||||
m_sMainTitle = "";
|
||||
m_sMainTitleTranslit = "";
|
||||
m_sSubTitle = "";
|
||||
|
||||
@@ -102,6 +102,7 @@ public:
|
||||
|
||||
CString m_sBannerPath;
|
||||
CString m_sCDTitlePath;
|
||||
CString m_sGroupName;
|
||||
|
||||
bool m_bRepeat; // repeat after last song? "Endless"
|
||||
bool m_bRandomize; // play the songs in a random order
|
||||
|
||||
@@ -79,7 +79,7 @@ void GroupList::Load( const CStringArray& asGroupNames )
|
||||
else
|
||||
{
|
||||
label->TurnRainbowOff();
|
||||
label->SetDiffuse( SONGMAN->GetGroupColor(asGroupNames[i]) );
|
||||
label->SetDiffuse( SONGMAN->GetSongGroupColor(asGroupNames[i]) );
|
||||
}
|
||||
|
||||
m_bHidden.push_back( ItemIsOnScreen(i) );
|
||||
|
||||
+246
-245
@@ -441,35 +441,35 @@ void MusicWheel::BuildWheelItemDatas( vector<WheelItemData> &arrayWheelItemDatas
|
||||
switch( so )
|
||||
{
|
||||
case SORT_MODE_MENU:
|
||||
{
|
||||
arrayWheelItemDatas.clear(); // clear out the previous wheel items
|
||||
vector<CString> vsNames;
|
||||
split( MODE_MENU_CHOICE_NAMES, ",", vsNames );
|
||||
for( unsigned i=0; i<vsNames.size(); ++i )
|
||||
{
|
||||
WheelItemData wid( TYPE_SORT, NULL, "", NULL, SORT_MENU_COLOR );
|
||||
wid.m_sLabel = vsNames[i];
|
||||
wid.m_Action.Load( i, ParseCommands(CHOICE.GetValue(vsNames[i])) );
|
||||
wid.m_sLabel = wid.m_Action.m_sName;
|
||||
|
||||
switch( so )
|
||||
arrayWheelItemDatas.clear(); // clear out the previous wheel items
|
||||
vector<CString> vsNames;
|
||||
split( MODE_MENU_CHOICE_NAMES, ",", vsNames );
|
||||
for( unsigned i=0; i<vsNames.size(); ++i )
|
||||
{
|
||||
case SORT_ALL_COURSES:
|
||||
case SORT_NONSTOP_COURSES:
|
||||
case SORT_ONI_COURSES:
|
||||
case SORT_ENDLESS_COURSES:
|
||||
/* Don't display course modes after the first stage. */
|
||||
if( !GAMESTATE->IsEventMode() && GAMESTATE->m_iCurrentStageIndex )
|
||||
WheelItemData wid( TYPE_SORT, NULL, "", NULL, SORT_MENU_COLOR );
|
||||
wid.m_sLabel = vsNames[i];
|
||||
wid.m_Action.Load( i, ParseCommands(CHOICE.GetValue(vsNames[i])) );
|
||||
wid.m_sLabel = wid.m_Action.m_sName;
|
||||
|
||||
switch( so )
|
||||
{
|
||||
case SORT_ALL_COURSES:
|
||||
case SORT_NONSTOP_COURSES:
|
||||
case SORT_ONI_COURSES:
|
||||
case SORT_ENDLESS_COURSES:
|
||||
/* Don't display course modes after the first stage. */
|
||||
if( !GAMESTATE->IsEventMode() && GAMESTATE->m_iCurrentStageIndex )
|
||||
continue;
|
||||
}
|
||||
|
||||
if( !wid.m_Action.IsPlayable() )
|
||||
continue;
|
||||
}
|
||||
|
||||
if( !wid.m_Action.IsPlayable() )
|
||||
continue;
|
||||
|
||||
arrayWheelItemDatas.push_back( wid );
|
||||
}
|
||||
break;
|
||||
}
|
||||
arrayWheelItemDatas.push_back( wid );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SORT_PREFERRED:
|
||||
case SORT_ROULETTE:
|
||||
case SORT_GROUP:
|
||||
@@ -483,253 +483,254 @@ void MusicWheel::BuildWheelItemDatas( vector<WheelItemData> &arrayWheelItemDatas
|
||||
case SORT_MEDIUM_METER:
|
||||
case SORT_HARD_METER:
|
||||
case SORT_CHALLENGE_METER:
|
||||
{
|
||||
///////////////////////////////////
|
||||
// Make an array of Song*, then sort them
|
||||
///////////////////////////////////
|
||||
vector<Song*> arraySongs;
|
||||
|
||||
GetSongList(arraySongs, so, GAMESTATE->m_sPreferredSongGroup );
|
||||
|
||||
bool bUseSections = true;
|
||||
|
||||
// sort the songs
|
||||
switch( so )
|
||||
{
|
||||
case SORT_PREFERRED:
|
||||
case SORT_ROULETTE:
|
||||
SongUtil::SortSongPointerArrayByMeter( arraySongs, DIFFICULTY_EASY );
|
||||
if( (bool)PREFSMAN->m_bPreferredSortUsesGroups )
|
||||
stable_sort( arraySongs.begin(), arraySongs.end(), SongUtil::CompareSongPointersByGroup );
|
||||
bUseSections = false;
|
||||
break;
|
||||
case SORT_GROUP:
|
||||
SongUtil::SortSongPointerArrayByGroupAndTitle( arraySongs );
|
||||
bUseSections = GAMESTATE->m_sPreferredSongGroup == GROUP_ALL_MUSIC;
|
||||
break;
|
||||
case SORT_TITLE:
|
||||
SongUtil::SortSongPointerArrayByTitle( arraySongs );
|
||||
break;
|
||||
case SORT_BPM:
|
||||
SongUtil::SortSongPointerArrayByBPM( arraySongs );
|
||||
break;
|
||||
case SORT_POPULARITY:
|
||||
if( (int) arraySongs.size() > MOST_PLAYED_SONGS_TO_SHOW )
|
||||
arraySongs.erase( arraySongs.begin()+MOST_PLAYED_SONGS_TO_SHOW, arraySongs.end() );
|
||||
bUseSections = false;
|
||||
break;
|
||||
case SORT_TOP_GRADES:
|
||||
SongUtil::SortSongPointerArrayByGrade( arraySongs );
|
||||
break;
|
||||
case SORT_ARTIST:
|
||||
SongUtil::SortSongPointerArrayByArtist( arraySongs );
|
||||
break;
|
||||
case SORT_GENRE:
|
||||
SongUtil::SortSongPointerArrayByGenre( arraySongs );
|
||||
break;
|
||||
case SORT_EASY_METER:
|
||||
SongUtil::SortSongPointerArrayByMeter( arraySongs, DIFFICULTY_EASY );
|
||||
break;
|
||||
case SORT_MEDIUM_METER:
|
||||
SongUtil::SortSongPointerArrayByMeter( arraySongs, DIFFICULTY_MEDIUM );
|
||||
break;
|
||||
case SORT_HARD_METER:
|
||||
SongUtil::SortSongPointerArrayByMeter( arraySongs, DIFFICULTY_HARD );
|
||||
break;
|
||||
case SORT_CHALLENGE_METER:
|
||||
SongUtil::SortSongPointerArrayByMeter( arraySongs, DIFFICULTY_CHALLENGE );
|
||||
break;
|
||||
default:
|
||||
ASSERT(0); // unhandled SortOrder
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////
|
||||
// Build an array of WheelItemDatas from the sorted list of Song*'s
|
||||
///////////////////////////////////
|
||||
arrayWheelItemDatas.clear(); // clear out the previous wheel items
|
||||
arrayWheelItemDatas.reserve( arraySongs.size() );
|
||||
|
||||
switch( PREFSMAN->m_MusicWheelUsesSections )
|
||||
{
|
||||
case PrefsManager::NEVER:
|
||||
bUseSections = false;
|
||||
break;
|
||||
case PrefsManager::ABC_ONLY:
|
||||
if( so != SORT_TITLE && so != SORT_GROUP )
|
||||
bUseSections = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if( bUseSections )
|
||||
{
|
||||
// Sorting twice isn't necessary. Instead, modify the compatator functions
|
||||
// in Song.cpp to have the desired effect. -Chris
|
||||
/* Keeping groups together with the sorts is tricky and brittle; we
|
||||
* keep getting OTHER split up without this. However, it puts the
|
||||
* Grade and BPM sorts in the wrong order, and they're already correct,
|
||||
* so don't re-sort for them. */
|
||||
// /* We're using sections, so use the section name as the top-level
|
||||
// * sort. */
|
||||
if( so != SORT_TOP_GRADES && so != SORT_BPM )
|
||||
SongUtil::SortSongPointerArrayBySectionName(arraySongs, so);
|
||||
|
||||
// make WheelItemDatas with sections
|
||||
CString sLastSection = "";
|
||||
int iSectionColorIndex = 0;
|
||||
for( unsigned i=0; i< arraySongs.size(); i++ )
|
||||
{
|
||||
Song* pSong = arraySongs[i];
|
||||
CString sThisSection = SongUtil::GetSectionNameFromSongAndSort( pSong, so );
|
||||
|
||||
if( sThisSection != sLastSection) // new section, make a section item
|
||||
{
|
||||
RageColor colorSection = (so==SORT_GROUP) ? SONGMAN->GetGroupColor(pSong->m_sGroupName) : SECTION_COLORS.GetValue(iSectionColorIndex);
|
||||
iSectionColorIndex = (iSectionColorIndex+1) % NUM_SECTION_COLORS;
|
||||
arrayWheelItemDatas.push_back( WheelItemData(TYPE_SECTION, NULL, sThisSection, NULL, colorSection) );
|
||||
sLastSection = sThisSection;
|
||||
}
|
||||
|
||||
arrayWheelItemDatas.push_back( WheelItemData( TYPE_SONG, pSong, sThisSection, NULL, SONGMAN->GetSongColor(pSong)) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( unsigned i=0; i<arraySongs.size(); i++ )
|
||||
{
|
||||
Song* pSong = arraySongs[i];
|
||||
arrayWheelItemDatas.push_back( WheelItemData(TYPE_SONG, pSong, "", NULL, SONGMAN->GetSongColor(pSong)) );
|
||||
}
|
||||
}
|
||||
|
||||
if( so != SORT_ROULETTE )
|
||||
{
|
||||
if( SHOW_ROULETTE )
|
||||
arrayWheelItemDatas.push_back( WheelItemData(TYPE_ROULETTE, NULL, "", NULL, RageColor(1,0,0,1)) );
|
||||
/* Only add TYPE_PORTAL if there's at least one song on the list. */
|
||||
bool bFoundAnySong = false;
|
||||
for( unsigned i=0; !bFoundAnySong && i < arrayWheelItemDatas.size(); i++ )
|
||||
if( arrayWheelItemDatas[i].m_Type == TYPE_SONG )
|
||||
bFoundAnySong = true;
|
||||
|
||||
if( SHOW_RANDOM && bFoundAnySong )
|
||||
arrayWheelItemDatas.push_back( WheelItemData(TYPE_RANDOM, NULL, "", NULL, RageColor(1,0,0,1)) );
|
||||
|
||||
if( SHOW_PORTAL && bFoundAnySong )
|
||||
arrayWheelItemDatas.push_back( WheelItemData(TYPE_PORTAL, NULL, "", NULL, RageColor(1,0,0,1)) );
|
||||
}
|
||||
|
||||
if( GAMESTATE->IsExtraStage() || GAMESTATE->IsExtraStage2() )
|
||||
{
|
||||
Song* pSong;
|
||||
Steps* pSteps;
|
||||
PlayerOptions po;
|
||||
SongOptions so;
|
||||
SONGMAN->GetExtraStageInfo( GAMESTATE->IsExtraStage2(), GAMESTATE->GetCurrentStyle(), pSong, pSteps, po, so );
|
||||
///////////////////////////////////
|
||||
// Make an array of Song*, then sort them
|
||||
///////////////////////////////////
|
||||
vector<Song*> arraySongs;
|
||||
|
||||
for( unsigned i=0; i<arrayWheelItemDatas.size(); i++ )
|
||||
GetSongList(arraySongs, so, GAMESTATE->m_sPreferredSongGroup );
|
||||
|
||||
bool bUseSections = true;
|
||||
|
||||
// sort the songs
|
||||
switch( so )
|
||||
{
|
||||
if( arrayWheelItemDatas[i].m_pSong == pSong )
|
||||
case SORT_PREFERRED:
|
||||
case SORT_ROULETTE:
|
||||
SongUtil::SortSongPointerArrayByMeter( arraySongs, DIFFICULTY_EASY );
|
||||
if( (bool)PREFSMAN->m_bPreferredSortUsesGroups )
|
||||
stable_sort( arraySongs.begin(), arraySongs.end(), SongUtil::CompareSongPointersByGroup );
|
||||
bUseSections = false;
|
||||
break;
|
||||
case SORT_GROUP:
|
||||
SongUtil::SortSongPointerArrayByGroupAndTitle( arraySongs );
|
||||
bUseSections = GAMESTATE->m_sPreferredSongGroup == GROUP_ALL_MUSIC;
|
||||
break;
|
||||
case SORT_TITLE:
|
||||
SongUtil::SortSongPointerArrayByTitle( arraySongs );
|
||||
break;
|
||||
case SORT_BPM:
|
||||
SongUtil::SortSongPointerArrayByBPM( arraySongs );
|
||||
break;
|
||||
case SORT_POPULARITY:
|
||||
if( (int) arraySongs.size() > MOST_PLAYED_SONGS_TO_SHOW )
|
||||
arraySongs.erase( arraySongs.begin()+MOST_PLAYED_SONGS_TO_SHOW, arraySongs.end() );
|
||||
bUseSections = false;
|
||||
break;
|
||||
case SORT_TOP_GRADES:
|
||||
SongUtil::SortSongPointerArrayByGrade( arraySongs );
|
||||
break;
|
||||
case SORT_ARTIST:
|
||||
SongUtil::SortSongPointerArrayByArtist( arraySongs );
|
||||
break;
|
||||
case SORT_GENRE:
|
||||
SongUtil::SortSongPointerArrayByGenre( arraySongs );
|
||||
break;
|
||||
case SORT_EASY_METER:
|
||||
SongUtil::SortSongPointerArrayByMeter( arraySongs, DIFFICULTY_EASY );
|
||||
break;
|
||||
case SORT_MEDIUM_METER:
|
||||
SongUtil::SortSongPointerArrayByMeter( arraySongs, DIFFICULTY_MEDIUM );
|
||||
break;
|
||||
case SORT_HARD_METER:
|
||||
SongUtil::SortSongPointerArrayByMeter( arraySongs, DIFFICULTY_HARD );
|
||||
break;
|
||||
case SORT_CHALLENGE_METER:
|
||||
SongUtil::SortSongPointerArrayByMeter( arraySongs, DIFFICULTY_CHALLENGE );
|
||||
break;
|
||||
default:
|
||||
ASSERT(0); // unhandled SortOrder
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////
|
||||
// Build an array of WheelItemDatas from the sorted list of Song*'s
|
||||
///////////////////////////////////
|
||||
arrayWheelItemDatas.clear(); // clear out the previous wheel items
|
||||
arrayWheelItemDatas.reserve( arraySongs.size() );
|
||||
|
||||
switch( PREFSMAN->m_MusicWheelUsesSections )
|
||||
{
|
||||
case PrefsManager::NEVER:
|
||||
bUseSections = false;
|
||||
break;
|
||||
case PrefsManager::ABC_ONLY:
|
||||
if( so != SORT_TITLE && so != SORT_GROUP )
|
||||
bUseSections = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if( bUseSections )
|
||||
{
|
||||
// Sorting twice isn't necessary. Instead, modify the compatator functions
|
||||
// in Song.cpp to have the desired effect. -Chris
|
||||
/* Keeping groups together with the sorts is tricky and brittle; we
|
||||
* keep getting OTHER split up without this. However, it puts the
|
||||
* Grade and BPM sorts in the wrong order, and they're already correct,
|
||||
* so don't re-sort for them. */
|
||||
// /* We're using sections, so use the section name as the top-level
|
||||
// * sort. */
|
||||
if( so != SORT_TOP_GRADES && so != SORT_BPM )
|
||||
SongUtil::SortSongPointerArrayBySectionName(arraySongs, so);
|
||||
|
||||
// make WheelItemDatas with sections
|
||||
CString sLastSection = "";
|
||||
int iSectionColorIndex = 0;
|
||||
for( unsigned i=0; i< arraySongs.size(); i++ )
|
||||
{
|
||||
/* Change the song color. */
|
||||
arrayWheelItemDatas[i].m_color = SONG_REAL_EXTRA_COLOR;
|
||||
break;
|
||||
Song* pSong = arraySongs[i];
|
||||
CString sThisSection = SongUtil::GetSectionNameFromSongAndSort( pSong, so );
|
||||
|
||||
if( sThisSection != sLastSection) // new section, make a section item
|
||||
{
|
||||
RageColor colorSection = (so==SORT_GROUP) ? SONGMAN->GetSongGroupColor(pSong->m_sGroupName) : SECTION_COLORS.GetValue(iSectionColorIndex);
|
||||
iSectionColorIndex = (iSectionColorIndex+1) % NUM_SECTION_COLORS;
|
||||
arrayWheelItemDatas.push_back( WheelItemData(TYPE_SECTION, NULL, sThisSection, NULL, colorSection) );
|
||||
sLastSection = sThisSection;
|
||||
}
|
||||
|
||||
arrayWheelItemDatas.push_back( WheelItemData( TYPE_SONG, pSong, sThisSection, NULL, SONGMAN->GetSongColor(pSong)) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( unsigned i=0; i<arraySongs.size(); i++ )
|
||||
{
|
||||
Song* pSong = arraySongs[i];
|
||||
arrayWheelItemDatas.push_back( WheelItemData(TYPE_SONG, pSong, "", NULL, SONGMAN->GetSongColor(pSong)) );
|
||||
}
|
||||
}
|
||||
|
||||
if( so != SORT_ROULETTE )
|
||||
{
|
||||
if( SHOW_ROULETTE )
|
||||
arrayWheelItemDatas.push_back( WheelItemData(TYPE_ROULETTE, NULL, "", NULL, RageColor(1,0,0,1)) );
|
||||
/* Only add TYPE_PORTAL if there's at least one song on the list. */
|
||||
bool bFoundAnySong = false;
|
||||
for( unsigned i=0; !bFoundAnySong && i < arrayWheelItemDatas.size(); i++ )
|
||||
if( arrayWheelItemDatas[i].m_Type == TYPE_SONG )
|
||||
bFoundAnySong = true;
|
||||
|
||||
if( SHOW_RANDOM && bFoundAnySong )
|
||||
arrayWheelItemDatas.push_back( WheelItemData(TYPE_RANDOM, NULL, "", NULL, RageColor(1,0,0,1)) );
|
||||
|
||||
if( SHOW_PORTAL && bFoundAnySong )
|
||||
arrayWheelItemDatas.push_back( WheelItemData(TYPE_PORTAL, NULL, "", NULL, RageColor(1,0,0,1)) );
|
||||
}
|
||||
|
||||
if( GAMESTATE->IsExtraStage() || GAMESTATE->IsExtraStage2() )
|
||||
{
|
||||
Song* pSong;
|
||||
Steps* pSteps;
|
||||
PlayerOptions po;
|
||||
SongOptions so;
|
||||
SONGMAN->GetExtraStageInfo( GAMESTATE->IsExtraStage2(), GAMESTATE->GetCurrentStyle(), pSong, pSteps, po, so );
|
||||
|
||||
for( unsigned i=0; i<arrayWheelItemDatas.size(); i++ )
|
||||
{
|
||||
if( arrayWheelItemDatas[i].m_pSong == pSong )
|
||||
{
|
||||
/* Change the song color. */
|
||||
arrayWheelItemDatas[i].m_color = SONG_REAL_EXTRA_COLOR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SORT_ALL_COURSES:
|
||||
case SORT_NONSTOP_COURSES:
|
||||
case SORT_ONI_COURSES:
|
||||
case SORT_ENDLESS_COURSES:
|
||||
{
|
||||
vector<Course*> apCourses;
|
||||
switch( so )
|
||||
{
|
||||
case SORT_NONSTOP_COURSES:
|
||||
SONGMAN->GetCourses( COURSE_TYPE_NONSTOP, apCourses, PREFSMAN->m_bAutogenGroupCourses );
|
||||
break;
|
||||
case SORT_ONI_COURSES:
|
||||
SONGMAN->GetCourses( COURSE_TYPE_ONI, apCourses, PREFSMAN->m_bAutogenGroupCourses );
|
||||
SONGMAN->GetCourses( COURSE_TYPE_SURVIVAL, apCourses, PREFSMAN->m_bAutogenGroupCourses );
|
||||
break;
|
||||
case SORT_ENDLESS_COURSES:
|
||||
SONGMAN->GetCourses( COURSE_TYPE_ENDLESS, apCourses, PREFSMAN->m_bAutogenGroupCourses );
|
||||
break;
|
||||
case SORT_ALL_COURSES:
|
||||
SONGMAN->GetAllCourses( apCourses, PREFSMAN->m_bAutogenGroupCourses );
|
||||
break;
|
||||
default: ASSERT(0); break;
|
||||
}
|
||||
|
||||
if( PREFSMAN->m_CourseSortOrder == PrefsManager::COURSE_SORT_SONGS )
|
||||
{
|
||||
CourseUtil::SortCoursePointerArrayByDifficulty( apCourses );
|
||||
}
|
||||
else
|
||||
{
|
||||
switch( PREFSMAN->m_CourseSortOrder )
|
||||
vector<Course*> apCourses;
|
||||
switch( so )
|
||||
{
|
||||
case PrefsManager::COURSE_SORT_METER:
|
||||
CourseUtil::SortCoursePointerArrayByAvgDifficulty( apCourses );
|
||||
case SORT_NONSTOP_COURSES:
|
||||
SONGMAN->GetCourses( COURSE_TYPE_NONSTOP, apCourses, PREFSMAN->m_bAutogenGroupCourses );
|
||||
break;
|
||||
case PrefsManager::COURSE_SORT_METER_SUM:
|
||||
CourseUtil::SortCoursePointerArrayByTotalDifficulty( apCourses );
|
||||
case SORT_ONI_COURSES:
|
||||
SONGMAN->GetCourses( COURSE_TYPE_ONI, apCourses, PREFSMAN->m_bAutogenGroupCourses );
|
||||
SONGMAN->GetCourses( COURSE_TYPE_SURVIVAL, apCourses, PREFSMAN->m_bAutogenGroupCourses );
|
||||
break;
|
||||
case PrefsManager::COURSE_SORT_RANK:
|
||||
CourseUtil::SortCoursePointerArrayByRanking( apCourses );
|
||||
case SORT_ENDLESS_COURSES:
|
||||
SONGMAN->GetCourses( COURSE_TYPE_ENDLESS, apCourses, PREFSMAN->m_bAutogenGroupCourses );
|
||||
break;
|
||||
default: ASSERT(0);
|
||||
case SORT_ALL_COURSES:
|
||||
SONGMAN->GetAllCourses( apCourses, PREFSMAN->m_bAutogenGroupCourses );
|
||||
break;
|
||||
default: ASSERT(0); break;
|
||||
}
|
||||
|
||||
// since we can't agree, make it an option
|
||||
if( PREFSMAN->m_bMoveRandomToEnd )
|
||||
CourseUtil::MoveRandomToEnd( apCourses );
|
||||
}
|
||||
|
||||
if( so == SORT_ALL_COURSES )
|
||||
CourseUtil::SortCoursePointerArrayByType( apCourses );
|
||||
|
||||
arrayWheelItemDatas.clear(); // clear out the previous wheel items
|
||||
|
||||
CString sLastSection = "";
|
||||
int iSectionColorIndex = 0;
|
||||
for( unsigned c=0; c<apCourses.size(); c++ ) // foreach course
|
||||
{
|
||||
Course* pCourse = apCourses[c];
|
||||
|
||||
// if unlocks are on, make sure it is unlocked
|
||||
if ( UNLOCKMAN->CourseIsLocked(pCourse) )
|
||||
continue;
|
||||
|
||||
CString sThisSection = "";
|
||||
if( so == SORT_ALL_COURSES )
|
||||
if( PREFSMAN->m_CourseSortOrder == PrefsManager::COURSE_SORT_SONGS )
|
||||
{
|
||||
switch( pCourse->GetPlayMode() )
|
||||
CourseUtil::SortCoursePointerArrayByDifficulty( apCourses );
|
||||
}
|
||||
else
|
||||
{
|
||||
switch( PREFSMAN->m_CourseSortOrder )
|
||||
{
|
||||
case PLAY_MODE_ONI: sThisSection = "Oni"; break;
|
||||
case PLAY_MODE_NONSTOP: sThisSection = "Nonstop"; break;
|
||||
case PLAY_MODE_ENDLESS: sThisSection = "Endless"; break;
|
||||
case PrefsManager::COURSE_SORT_METER:
|
||||
CourseUtil::SortCoursePointerArrayByAvgDifficulty( apCourses );
|
||||
break;
|
||||
case PrefsManager::COURSE_SORT_METER_SUM:
|
||||
CourseUtil::SortCoursePointerArrayByTotalDifficulty( apCourses );
|
||||
break;
|
||||
case PrefsManager::COURSE_SORT_RANK:
|
||||
CourseUtil::SortCoursePointerArrayByRanking( apCourses );
|
||||
break;
|
||||
default: ASSERT(0);
|
||||
}
|
||||
|
||||
// since we can't agree, make it an option
|
||||
if( PREFSMAN->m_bMoveRandomToEnd )
|
||||
CourseUtil::MoveRandomToEnd( apCourses );
|
||||
}
|
||||
|
||||
// check that this course has at least one song playable in the current style
|
||||
if( !pCourse->IsPlayableIn(GAMESTATE->GetCurrentStyle()->m_StepsType) )
|
||||
continue;
|
||||
if( so == SORT_ALL_COURSES )
|
||||
CourseUtil::SortCoursePointerArrayByType( apCourses );
|
||||
|
||||
if( sThisSection != sLastSection ) // new section, make a section item
|
||||
arrayWheelItemDatas.clear(); // clear out the previous wheel items
|
||||
|
||||
CString sLastSection = "";
|
||||
int iSectionColorIndex = 0;
|
||||
for( unsigned c=0; c<apCourses.size(); c++ ) // foreach course
|
||||
{
|
||||
RageColor c = SECTION_COLORS.GetValue(iSectionColorIndex);
|
||||
iSectionColorIndex = (iSectionColorIndex+1) % NUM_SECTION_COLORS;
|
||||
arrayWheelItemDatas.push_back( WheelItemData(TYPE_SECTION, NULL, sThisSection, NULL, c) );
|
||||
sLastSection = sThisSection;
|
||||
}
|
||||
Course* pCourse = apCourses[c];
|
||||
|
||||
arrayWheelItemDatas.push_back( WheelItemData(TYPE_COURSE, NULL, sThisSection, pCourse, pCourse->GetColor()) );
|
||||
// if unlocks are on, make sure it is unlocked
|
||||
if ( UNLOCKMAN->CourseIsLocked(pCourse) )
|
||||
continue;
|
||||
|
||||
CString sThisSection = "";
|
||||
if( so == SORT_ALL_COURSES )
|
||||
{
|
||||
switch( pCourse->GetPlayMode() )
|
||||
{
|
||||
case PLAY_MODE_ONI: sThisSection = "Oni"; break;
|
||||
case PLAY_MODE_NONSTOP: sThisSection = "Nonstop"; break;
|
||||
case PLAY_MODE_ENDLESS: sThisSection = "Endless"; break;
|
||||
}
|
||||
}
|
||||
|
||||
// check that this course has at least one song playable in the current style
|
||||
if( !pCourse->IsPlayableIn(GAMESTATE->GetCurrentStyle()->m_StepsType) )
|
||||
continue;
|
||||
|
||||
if( sThisSection != sLastSection ) // new section, make a section item
|
||||
{
|
||||
RageColor c = SECTION_COLORS.GetValue(iSectionColorIndex);
|
||||
iSectionColorIndex = (iSectionColorIndex+1) % NUM_SECTION_COLORS;
|
||||
arrayWheelItemDatas.push_back( WheelItemData(TYPE_SECTION, NULL, sThisSection, NULL, c) );
|
||||
sLastSection = sThisSection;
|
||||
}
|
||||
|
||||
RageColor c = pCourse->GetColor() * SONGMAN->GetCourseColor(pCourse);
|
||||
arrayWheelItemDatas.push_back( WheelItemData(TYPE_COURSE, NULL, sThisSection, pCourse, c) );
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// init music status icons
|
||||
|
||||
@@ -606,7 +606,7 @@ void ScreenEz2SelectMusic::MusicChanged()
|
||||
GAMESTATE->m_pCurSong.Set( pSong );
|
||||
|
||||
m_CurrentGroup.SetText( SONGMAN->ShortenGroupName( pSong->m_sGroupName ) , "");
|
||||
m_CurrentGroup.SetDiffuse( SONGMAN->GetGroupColor(pSong->m_sGroupName) );
|
||||
m_CurrentGroup.SetDiffuse( SONGMAN->GetSongGroupColor(pSong->m_sGroupName) );
|
||||
|
||||
m_CurrentTitle.SetText( pSong->m_sMainTitle, "");
|
||||
m_CurrentSubTitle.SetText( pSong->m_sSubTitle, "");
|
||||
|
||||
@@ -146,7 +146,7 @@ void ScreenUnlock::Init()
|
||||
const Song *pSong = entry.m_pSong;
|
||||
RageColor color = RageColor(1,1,1,1);
|
||||
if( pSong )
|
||||
color = SONGMAN->GetGroupColor(pSong->m_sGroupName);
|
||||
color = SONGMAN->GetSongGroupColor(pSong->m_sGroupName);
|
||||
text->SetGlobalDiffuseColor(color);
|
||||
}
|
||||
|
||||
@@ -250,7 +250,7 @@ void ScreenUnlock::Init()
|
||||
NewText->SetMaxWidth( MaxWidth );
|
||||
NewText->SetText( title );
|
||||
|
||||
RageColor color = SONGMAN->GetGroupColor(pSong->m_sGroupName);
|
||||
RageColor color = SONGMAN->GetSongGroupColor(pSong->m_sGroupName);
|
||||
NewText->SetGlobalDiffuseColor(color);
|
||||
|
||||
NewText->SetXY(ScrollingTextX, ScrollingTextStartY);
|
||||
|
||||
@@ -207,7 +207,7 @@ bool Song::LoadFromSongDir( CString sDir )
|
||||
// save group name
|
||||
CStringArray sDirectoryParts;
|
||||
split( m_sSongDir, "/", sDirectoryParts, false );
|
||||
ASSERT( sDirectoryParts.size() >= 4 ); /* Songs/Slow/Taps/ */
|
||||
ASSERT( sDirectoryParts.size() >= 4 ); /* e.g. "/Songs/Slow/Taps/" */
|
||||
m_sGroupName = sDirectoryParts[sDirectoryParts.size()-3]; // second from last item
|
||||
ASSERT( m_sGroupName != "" );
|
||||
|
||||
|
||||
+101
-67
@@ -32,11 +32,11 @@
|
||||
|
||||
SongManager* SONGMAN = NULL; // global and accessable from anywhere in our program
|
||||
|
||||
#define SONGS_DIR "Songs/"
|
||||
#define COURSES_DIR "Courses/"
|
||||
const CString SONGS_DIR = "Songs/";
|
||||
const CString COURSES_DIR = "Courses/";
|
||||
|
||||
#define MAX_EDITS_PER_PROFILE 200
|
||||
#define MAX_EDIT_SIZE_BYTES 30*1024 // 30KB
|
||||
const int MAX_EDITS_PER_PROFILE = 200;
|
||||
const int MAX_EDIT_SIZE_BYTES = 30*1024; // 30KB
|
||||
|
||||
static const ThemeMetric<RageColor> BEGINNER_COLOR ("SongManager","BeginnerColor");
|
||||
static const ThemeMetric<RageColor> EASY_COLOR ("SongManager","EasyColor");
|
||||
@@ -47,13 +47,16 @@ static const ThemeMetric<RageColor> EDIT_COLOR ("SongManager","EditColor");
|
||||
static const ThemeMetric<RageColor> EXTRA_COLOR ("SongManager","ExtraColor");
|
||||
static const ThemeMetric<int> EXTRA_COLOR_METER ("SongManager","ExtraColorMeter");
|
||||
|
||||
CString GROUP_COLOR_NAME( size_t i ) { return ssprintf("GroupColor%i",(int) i+1); }
|
||||
CString SONG_GROUP_COLOR_NAME( size_t i ) { return ssprintf("SongGroupColor%i",(int) i+1); }
|
||||
CString COURSE_GROUP_COLOR_NAME( size_t i ) { return ssprintf("CourseGroupColor%i",(int) i+1); }
|
||||
|
||||
|
||||
SongManager::SongManager()
|
||||
{
|
||||
NUM_GROUP_COLORS.Load("SongManager","NumGroupColors");
|
||||
GROUP_COLOR .Load("SongManager",GROUP_COLOR_NAME,NUM_GROUP_COLORS);
|
||||
NUM_SONG_GROUP_COLORS .Load("SongManager","NumSongGroupColors");
|
||||
SONG_GROUP_COLOR .Load("SongManager",SONG_GROUP_COLOR_NAME,NUM_SONG_GROUP_COLORS);
|
||||
NUM_COURSE_GROUP_COLORS .Load("SongManager","NumCourseGroupColors");
|
||||
COURSE_GROUP_COLOR .Load("SongManager",COURSE_GROUP_COLOR_NAME,NUM_COURSE_GROUP_COLORS);
|
||||
}
|
||||
|
||||
SongManager::~SongManager()
|
||||
@@ -124,10 +127,10 @@ void SongManager::SanityCheckGroupDir( CString sDir ) const
|
||||
void SongManager::AddGroup( CString sDir, CString sGroupDirName )
|
||||
{
|
||||
unsigned j;
|
||||
for(j = 0; j < m_sGroupNames.size(); ++j)
|
||||
if( sGroupDirName == m_sGroupNames[j] ) break;
|
||||
for(j = 0; j < m_sSongGroupNames.size(); ++j)
|
||||
if( sGroupDirName == m_sSongGroupNames[j] ) break;
|
||||
|
||||
if( j != m_sGroupNames.size() )
|
||||
if( j != m_sSongGroupNames.size() )
|
||||
return; /* the group is already added */
|
||||
|
||||
// Look for a group banner in this group folder
|
||||
@@ -153,8 +156,8 @@ void SongManager::AddGroup( CString sDir, CString sGroupDirName )
|
||||
|
||||
LOG->Trace( "Group banner for '%s' is '%s'.", sGroupDirName.c_str(),
|
||||
sBannerPath != ""? sBannerPath.c_str():"(none)" );
|
||||
m_sGroupNames.push_back( sGroupDirName );
|
||||
m_sGroupBannerPaths.push_back(sBannerPath);
|
||||
m_sSongGroupNames.push_back( sGroupDirName );
|
||||
m_sSongGroupBannerPaths.push_back( sBannerPath );
|
||||
}
|
||||
|
||||
void SongManager::LoadStepManiaSongDir( CString sDir, LoadingWindow *ld )
|
||||
@@ -294,14 +297,14 @@ void SongManager::PreloadSongImages()
|
||||
|
||||
void SongManager::FreeSongs()
|
||||
{
|
||||
m_sGroupNames.clear();
|
||||
m_sGroupBannerPaths.clear();
|
||||
m_sSongGroupNames.clear();
|
||||
m_sSongGroupBannerPaths.clear();
|
||||
|
||||
for( unsigned i=0; i<m_pSongs.size(); i++ )
|
||||
SAFE_DELETE( m_pSongs[i] );
|
||||
m_pSongs.clear();
|
||||
|
||||
m_sGroupBannerPaths.clear();
|
||||
m_sSongGroupBannerPaths.clear();
|
||||
|
||||
for( int i = 0; i < NUM_PROFILE_SLOTS; ++i )
|
||||
m_pBestSongs[i].clear();
|
||||
@@ -311,41 +314,41 @@ void SongManager::FreeSongs()
|
||||
CString SongManager::GetGroupBannerPath( CString sGroupName )
|
||||
{
|
||||
unsigned i;
|
||||
for(i = 0; i < m_sGroupNames.size(); ++i)
|
||||
if( sGroupName == m_sGroupNames[i] ) break;
|
||||
for(i = 0; i < m_sSongGroupNames.size(); ++i)
|
||||
if( sGroupName == m_sSongGroupNames[i] ) break;
|
||||
|
||||
if( i == m_sGroupNames.size() )
|
||||
if( i == m_sSongGroupNames.size() )
|
||||
return "";
|
||||
|
||||
return m_sGroupBannerPaths[i];
|
||||
return m_sSongGroupBannerPaths[i];
|
||||
}
|
||||
|
||||
void SongManager::GetGroupNames( CStringArray &AddTo )
|
||||
{
|
||||
AddTo.insert(AddTo.end(), m_sGroupNames.begin(), m_sGroupNames.end() );
|
||||
AddTo.insert(AddTo.end(), m_sSongGroupNames.begin(), m_sSongGroupNames.end() );
|
||||
}
|
||||
|
||||
bool SongManager::DoesGroupExist( CString sGroupName )
|
||||
{
|
||||
for( unsigned i = 0; i < m_sGroupNames.size(); ++i )
|
||||
if( !m_sGroupNames[i].CompareNoCase(sGroupName) )
|
||||
for( unsigned i = 0; i < m_sSongGroupNames.size(); ++i )
|
||||
if( !m_sSongGroupNames[i].CompareNoCase(sGroupName) )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
RageColor SongManager::GetGroupColor( const CString &sGroupName )
|
||||
RageColor SongManager::GetSongGroupColor( const CString &sSongGroupName )
|
||||
{
|
||||
// search for the group index
|
||||
unsigned i;
|
||||
for( i=0; i<m_sGroupNames.size(); i++ )
|
||||
for( i=0; i<m_sSongGroupNames.size(); i++ )
|
||||
{
|
||||
if( m_sGroupNames[i] == sGroupName )
|
||||
if( m_sSongGroupNames[i] == sSongGroupName )
|
||||
break;
|
||||
}
|
||||
ASSERT_M( i != m_sGroupNames.size(), sGroupName ); // this is not a valid group
|
||||
ASSERT_M( i != m_sSongGroupNames.size(), sSongGroupName ); // this is not a valid group
|
||||
|
||||
return GROUP_COLOR.GetValue( i%NUM_GROUP_COLORS );
|
||||
return SONG_GROUP_COLOR.GetValue( i%NUM_SONG_GROUP_COLORS );
|
||||
}
|
||||
|
||||
RageColor SongManager::GetSongColor( const Song* pSong )
|
||||
@@ -376,14 +379,33 @@ RageColor SongManager::GetSongColor( const Song* pSong )
|
||||
continue;
|
||||
}
|
||||
|
||||
// if(pSteps->m_StepsType != nt)
|
||||
// if(pSteps->m_StepsType != st)
|
||||
// continue;
|
||||
|
||||
if( pSteps->GetMeter() >= EXTRA_COLOR_METER )
|
||||
return (RageColor)EXTRA_COLOR;
|
||||
}
|
||||
|
||||
return GetGroupColor( pSong->m_sGroupName );
|
||||
return GetSongGroupColor( pSong->m_sGroupName );
|
||||
}
|
||||
|
||||
RageColor SongManager::GetCourseGroupColor( const CString &sCourseGroupName )
|
||||
{
|
||||
// search for the group index
|
||||
unsigned i;
|
||||
for( i=0; i<m_sCourseGroupNames.size(); i++ )
|
||||
{
|
||||
if( m_sCourseGroupNames[i] == sCourseGroupName )
|
||||
break;
|
||||
}
|
||||
ASSERT_M( i != m_sCourseGroupNames.size(), sCourseGroupName ); // this is not a valid group
|
||||
|
||||
return COURSE_GROUP_COLOR.GetValue( i%NUM_COURSE_GROUP_COLORS );
|
||||
}
|
||||
|
||||
RageColor SongManager::GetCourseColor( const Course* pCourse )
|
||||
{
|
||||
return GetCourseGroupColor( pCourse->m_sGroupName );
|
||||
}
|
||||
|
||||
RageColor SongManager::GetDifficultyColor( Difficulty dc ) const
|
||||
@@ -427,7 +449,7 @@ int SongManager::GetNumSongs() const
|
||||
|
||||
int SongManager::GetNumGroups() const
|
||||
{
|
||||
return m_sGroupNames.size();
|
||||
return m_sSongGroupNames.size();
|
||||
}
|
||||
|
||||
int SongManager::GetNumCourses() const
|
||||
@@ -480,58 +502,68 @@ void SongManager::InitCoursesFromDisk( LoadingWindow *ld )
|
||||
{
|
||||
LOG->Trace( "Loading courses." );
|
||||
|
||||
m_sCourseGroupNames.clear();
|
||||
|
||||
//
|
||||
// Load courses from in Courses dir
|
||||
//
|
||||
CStringArray saCourseFiles;
|
||||
GetDirListing( COURSES_DIR "*.crs", saCourseFiles, false, true );
|
||||
for( unsigned i=0; i<saCourseFiles.size(); i++ )
|
||||
{
|
||||
Course* pCourse = new Course;
|
||||
pCourse->LoadFromCRSFile( saCourseFiles[i] );
|
||||
m_pCourses.push_back( pCourse );
|
||||
|
||||
if( ld )
|
||||
CStringArray saCourseFiles;
|
||||
GetDirListing( COURSES_DIR+"*.crs", saCourseFiles, false, true );
|
||||
for( unsigned i=0; i<saCourseFiles.size(); i++ )
|
||||
{
|
||||
ld->SetText( ssprintf("Loading courses...\n%s\n%s",
|
||||
"Courses",
|
||||
Basename(saCourseFiles[i]).c_str()));
|
||||
ld->Paint();
|
||||
}
|
||||
Course* pCourse = new Course;
|
||||
pCourse->LoadFromCRSFile( saCourseFiles[i] );
|
||||
m_pCourses.push_back( pCourse );
|
||||
|
||||
if( ld )
|
||||
{
|
||||
ld->SetText( ssprintf("Loading courses...\n%s\n%s",
|
||||
"Courses",
|
||||
Basename(saCourseFiles[i]).c_str()));
|
||||
ld->Paint();
|
||||
}
|
||||
|
||||
}
|
||||
if( !saCourseFiles.empty() )
|
||||
m_sCourseGroupNames.push_back( "" );
|
||||
}
|
||||
|
||||
|
||||
// Find all group directories in Courses dir
|
||||
CStringArray arrayGroupDirs;
|
||||
GetDirListing( COURSES_DIR "*", arrayGroupDirs, true );
|
||||
SortCStringArray( arrayGroupDirs );
|
||||
|
||||
for( unsigned i=0; i< arrayGroupDirs.size(); i++ ) // for each dir in /Courses/
|
||||
{
|
||||
CString sGroupDirName = arrayGroupDirs[i];
|
||||
|
||||
if( 0 == stricmp( sGroupDirName, "cvs" ) ) // the directory called "CVS"
|
||||
continue; // ignore it
|
||||
|
||||
// Find all CRS files in this group directory
|
||||
CStringArray arrayCoursePaths;
|
||||
GetDirListing( COURSES_DIR + sGroupDirName + "/*.crs", arrayCoursePaths, false, true );
|
||||
SortCStringArray( arrayCoursePaths );
|
||||
|
||||
for( unsigned j=0; j<arrayCoursePaths.size(); j++ )
|
||||
GetDirListing( COURSES_DIR+"*", m_sCourseGroupNames, true );
|
||||
SortCStringArray( m_sCourseGroupNames );
|
||||
|
||||
FOREACH( CString, m_sCourseGroupNames, sCourseGroup ) // for each dir in /Courses/
|
||||
{
|
||||
if( ld )
|
||||
if( 0 == stricmp( *sCourseGroup, "cvs" ) ) // the directory called "CVS"
|
||||
{
|
||||
ld->SetText( ssprintf("Loading courses...\n%s\n%s",
|
||||
Basename(arrayGroupDirs[i]).c_str(),
|
||||
Basename(arrayCoursePaths[j]).c_str()));
|
||||
ld->Paint();
|
||||
vector<CString>::iterator eraseme = sCourseGroup;
|
||||
sCourseGroup--;
|
||||
m_sCourseGroupNames.erase( eraseme );
|
||||
continue; // ignore it
|
||||
}
|
||||
|
||||
Course* pCourse = new Course;
|
||||
pCourse->LoadFromCRSFile( arrayCoursePaths[j] );
|
||||
m_pCourses.push_back( pCourse );
|
||||
// Find all CRS files in this group directory
|
||||
CStringArray vsCoursePaths;
|
||||
GetDirListing( COURSES_DIR + *sCourseGroup + "/*.crs", vsCoursePaths, false, true );
|
||||
SortCStringArray( vsCoursePaths );
|
||||
|
||||
FOREACH_CONST( CString, vsCoursePaths, sCoursePath )
|
||||
{
|
||||
if( ld )
|
||||
{
|
||||
ld->SetText( ssprintf("Loading courses...\n%s\n%s",
|
||||
Basename(*sCourseGroup).c_str(),
|
||||
Basename(*sCoursePath).c_str()));
|
||||
ld->Paint();
|
||||
}
|
||||
|
||||
Course* pCourse = new Course;
|
||||
pCourse->LoadFromCRSFile( *sCoursePath );
|
||||
m_pCourses.push_back( pCourse );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -627,6 +659,8 @@ void SongManager::FreeCourses()
|
||||
FOREACH_CourseType( ct )
|
||||
m_pBestCourses[i][ct].clear();
|
||||
m_pShuffledCourses.clear();
|
||||
|
||||
m_sCourseGroupNames.clear();
|
||||
}
|
||||
|
||||
/* Called periodically to wipe out cached NoteData. This is called when we change
|
||||
|
||||
@@ -54,9 +54,11 @@ public:
|
||||
void GetGroupNames( CStringArray &AddTo );
|
||||
bool DoesGroupExist( CString sGroupName );
|
||||
|
||||
RageColor GetGroupColor( const CString &sGroupName );
|
||||
RageColor GetSongGroupColor( const CString &sSongGroupName );
|
||||
RageColor GetSongColor( const Song* pSong );
|
||||
RageColor GetDifficultyColor( Difficulty dc ) const;
|
||||
RageColor GetCourseGroupColor( const CString &sCourseGroupName );
|
||||
RageColor GetCourseColor( const Course* pCourse );
|
||||
|
||||
static CString ShortenGroupName( CString sLongGroupName );
|
||||
static int GetNumStagesForSong( const Song* pSong ); // LongVer songs take 2 stages, MarathonVer take 3
|
||||
@@ -113,15 +115,19 @@ protected:
|
||||
vector<Song*> m_pSongs; // all songs that can be played
|
||||
vector<Song*> m_pBestSongs[NUM_PROFILE_SLOTS];
|
||||
vector<Song*> m_pShuffledSongs; // used by GetRandomSong
|
||||
CStringArray m_sGroupNames;
|
||||
CStringArray m_sGroupBannerPaths; // each song group may have a banner associated with it
|
||||
CStringArray m_sSongGroupNames;
|
||||
CStringArray m_sSongGroupBannerPaths; // each song group may have a banner associated with it
|
||||
|
||||
vector<Course*> m_pCourses;
|
||||
vector<Course*> m_pBestCourses[NUM_PROFILE_SLOTS][NUM_COURSE_TYPES];
|
||||
vector<Course*> m_pShuffledCourses; // used by GetRandomCourse
|
||||
CStringArray m_sCourseGroupNames;
|
||||
|
||||
|
||||
ThemeMetric<int> NUM_GROUP_COLORS;
|
||||
ThemeMetric1D<RageColor> GROUP_COLOR;
|
||||
ThemeMetric<int> NUM_SONG_GROUP_COLORS;
|
||||
ThemeMetric1D<RageColor> SONG_GROUP_COLOR;
|
||||
ThemeMetric<int> NUM_COURSE_GROUP_COLORS;
|
||||
ThemeMetric1D<RageColor> COURSE_GROUP_COLOR;
|
||||
};
|
||||
|
||||
static const CString EDIT_SUBDIR = "Edits/";
|
||||
|
||||
Reference in New Issue
Block a user