sm5svn 0dc297b [Glenn Maynard]
"Previously, we didn't create MusicWheel sorts when the screen loads; it was delayed until the screen begins. This allowed preloading before the style is set. However, it caused a major skip when the screen starts, because creating the sorts is fairly expensive. Refactor this. Load the sorts when the screen is loaded, and then go through them and quickly filter out unplayable data and handle other initialization on begin. This is much faster, so we can more easily transition seamlessly from the previous menu. One known limitation: the sorts are created before we know the style, so we have to guess. This means if you're in a style like dance-solo or pump-halfdouble, sorts will still be based on regular mode. This affects the difficulty, top grade and roulette sorts."
This commit is contained in:
@@ -21,6 +21,20 @@ sm-ssc v1.2.3 | 201103??
|
||||
* [MeterDisplay] Add Lua binding. "Allow setting and changing the width
|
||||
dynamically. Phase out the "StreamWidth" node property; set it with
|
||||
SetStreamWidth instead." [Glenn Maynard]
|
||||
* sm5svn r28280: "Previously, we didn't create MusicWheel sorts when the screen
|
||||
loads; it was delayed until the screen begins. This allowed preloading before
|
||||
the style is set. However, it caused a major skip when the screen starts,
|
||||
because creating the sorts is fairly expensive.
|
||||
|
||||
Refactor this. Load the sorts when the screen is loaded, and then go through
|
||||
them and quickly filter out unplayable data and handle other initialization
|
||||
on begin. This is much faster, so we can more easily transition seamlessly
|
||||
from the previous menu.
|
||||
|
||||
One known limitation: the sorts are created before we know the style, so we
|
||||
have to guess. This means if you're in a style like dance-solo or
|
||||
pump-halfdouble, sorts will still be based on regular mode. This affects the
|
||||
difficulty, top grade and roulette sorts." [Glenn Maynard]
|
||||
|
||||
20110305
|
||||
--------
|
||||
|
||||
+197
-159
@@ -113,25 +113,31 @@ void MusicWheel::Load( RString sType )
|
||||
* stable_sort) from its output, and title will be the secondary sort, without having
|
||||
* to re-sort by title each time. */
|
||||
SONGMAN->SortSongs();
|
||||
}
|
||||
|
||||
void MusicWheel::BeginScreen()
|
||||
{
|
||||
RageTimer timer;
|
||||
RString times;
|
||||
/* Build all of the wheel item data. Do this after selecting the extra stage,
|
||||
* so it knows to always display it. */
|
||||
FOREACH_ENUM( SortOrder, so )
|
||||
{
|
||||
BuildWheelItemDatas( m_WheelItemDatas[so], so );
|
||||
BuildWheelItemDatas( m_UnfilteredWheelItemDatas[so], so );
|
||||
times += ssprintf( "%i:%.3f ", so, timer.GetDeltaTime() );
|
||||
}
|
||||
LOG->Trace( "MusicWheel sorting took: %s", times.c_str() );
|
||||
}
|
||||
|
||||
void MusicWheel::BeginScreen()
|
||||
{
|
||||
FOREACH_ENUM( SortOrder, so )
|
||||
{
|
||||
m_UnfilteredWheelItemDatas[so] = m_UnfilteredWheelItemDatas[so];
|
||||
UpdateWheelItemDatas( so );
|
||||
}
|
||||
|
||||
/* Set m_LastModeMenuItem to the first item that matches the current mode. (Do this
|
||||
* after building wheel item data.) */
|
||||
{
|
||||
const vector<MusicWheelItemData *> &from = m_WheelItemDatas[SORT_MODE_MENU];
|
||||
const vector<MusicWheelItemData *> &from = m_UnfilteredWheelItemDatas[SORT_MODE_MENU];
|
||||
for( unsigned i=0; i<from.size(); i++ )
|
||||
{
|
||||
ASSERT( &*from[i]->m_pAction );
|
||||
@@ -228,7 +234,7 @@ void MusicWheel::BeginScreen()
|
||||
MusicWheel::~MusicWheel()
|
||||
{
|
||||
FOREACH_ENUM( SortOrder, so )
|
||||
FOREACH( MusicWheelItemData*, m_WheelItemDatas[so], i )
|
||||
FOREACH( MusicWheelItemData*, m_UnfilteredWheelItemDatas[so], i )
|
||||
delete *i;
|
||||
}
|
||||
|
||||
@@ -247,7 +253,7 @@ bool MusicWheel::SelectSongOrCourse()
|
||||
return true;
|
||||
|
||||
// Select the first selectable song based on the sort order...
|
||||
vector<MusicWheelItemData *> &wiWheelItems = m_WheelItemDatas[GAMESTATE->m_SortOrder];
|
||||
vector<MusicWheelItemData *> &wiWheelItems = m_UnfilteredWheelItemDatas[GAMESTATE->m_SortOrder];
|
||||
for( unsigned i = 0; i < wiWheelItems.size(); i++ )
|
||||
{
|
||||
if( wiWheelItems[i]->m_pSong )
|
||||
@@ -280,7 +286,7 @@ bool MusicWheel::SelectSong( const Song *p )
|
||||
return false;
|
||||
|
||||
unsigned i;
|
||||
vector<MusicWheelItemData *> &from = m_WheelItemDatas[GAMESTATE->m_SortOrder];
|
||||
vector<MusicWheelItemData *> &from = m_UnfilteredWheelItemDatas[GAMESTATE->m_SortOrder];
|
||||
for( i=0; i<from.size(); i++ )
|
||||
{
|
||||
if( from[i]->m_pSong == p )
|
||||
@@ -308,7 +314,7 @@ bool MusicWheel::SelectCourse( const Course *p )
|
||||
return false;
|
||||
|
||||
unsigned i;
|
||||
vector<MusicWheelItemData *> &from = m_WheelItemDatas[GAMESTATE->m_SortOrder];
|
||||
vector<MusicWheelItemData *> &from = m_UnfilteredWheelItemDatas[GAMESTATE->m_SortOrder];
|
||||
for( i=0; i<from.size(); i++ )
|
||||
{
|
||||
if( from[i]->m_pCourse == p )
|
||||
@@ -335,7 +341,7 @@ bool MusicWheel::SelectModeMenuItem()
|
||||
{
|
||||
/* Select the last-chosen option. */
|
||||
ASSERT( GAMESTATE->m_SortOrder == SORT_MODE_MENU );
|
||||
const vector<MusicWheelItemData *> &from = m_WheelItemDatas[GAMESTATE->m_SortOrder];
|
||||
const vector<MusicWheelItemData *> &from = m_UnfilteredWheelItemDatas[GAMESTATE->m_SortOrder];
|
||||
unsigned i;
|
||||
for( i=0; i<from.size(); i++ )
|
||||
{
|
||||
@@ -360,120 +366,12 @@ bool MusicWheel::SelectModeMenuItem()
|
||||
return true;
|
||||
}
|
||||
|
||||
void MusicWheel::GetSongList( vector<Song*> &arraySongs, SortOrder so )
|
||||
{
|
||||
vector<Song*> apAllSongs;
|
||||
switch( so )
|
||||
{
|
||||
case SORT_PREFERRED:
|
||||
SONGMAN->GetPreferredSortSongs( apAllSongs );
|
||||
break;
|
||||
case SORT_POPULARITY:
|
||||
SONGMAN->GetPopularSongs();
|
||||
break;
|
||||
case SORT_GROUP:
|
||||
// if we're not using sections with a preferred song group, and there
|
||||
// is a group to load, only load those songs. -aj
|
||||
if(GAMESTATE->m_sPreferredSongGroup != GROUP_ALL && !USE_SECTIONS_WITH_PREFERRED_GROUP )
|
||||
{
|
||||
apAllSongs = SONGMAN->GetSongs(GAMESTATE->m_sPreferredSongGroup);
|
||||
break;
|
||||
}
|
||||
// otherwise fall through
|
||||
default:
|
||||
apAllSongs = SONGMAN->GetAllSongs();
|
||||
break;
|
||||
}
|
||||
|
||||
// filter songs that we don't have enough stages to play
|
||||
{
|
||||
vector<Song*> vTempSongs;
|
||||
SongCriteria sc;
|
||||
sc.m_iMaxStagesForSong = GAMESTATE->GetSmallestNumStagesLeftForAnyHumanPlayer();
|
||||
SongUtil::FilterSongs( sc, apAllSongs, vTempSongs );
|
||||
apAllSongs = vTempSongs;
|
||||
}
|
||||
|
||||
// copy only songs that have at least one Steps for the current GameMode
|
||||
for( unsigned i=0; i<apAllSongs.size(); i++ )
|
||||
{
|
||||
Song* pSong = apAllSongs[i];
|
||||
|
||||
int iLocked = UNLOCKMAN->SongIsLocked( pSong );
|
||||
if( iLocked & LOCKED_DISABLED )
|
||||
continue;
|
||||
|
||||
// If we're on an extra stage, and this song is selected, ignore #SELECTABLE.
|
||||
if( pSong != GAMESTATE->m_pCurSong || !GAMESTATE->IsAnExtraStage() )
|
||||
{
|
||||
// Hide songs that asked to be hidden via #SELECTABLE.
|
||||
if( iLocked & LOCKED_SELECTABLE )
|
||||
continue;
|
||||
if( so != SORT_ROULETTE && iLocked & LOCKED_ROULETTE )
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Hide locked songs. If RANDOM_PICKS_LOCKED_SONGS, hide in Roulette
|
||||
* and Random, too. */
|
||||
if( (so!=SORT_ROULETTE || !RANDOM_PICKS_LOCKED_SONGS) && iLocked )
|
||||
continue;
|
||||
|
||||
if( PREFSMAN->m_bOnlyPreferredDifficulties )
|
||||
{
|
||||
// if the song has steps that fit the preferred difficulty of the default player
|
||||
if( pSong->HasStepsTypeAndDifficulty( GAMESTATE->GetCurrentStyle()->m_StepsType,GAMESTATE->m_PreferredDifficulty[GAMESTATE->GetFirstHumanPlayer()] ) )
|
||||
arraySongs.push_back( pSong );
|
||||
}
|
||||
else
|
||||
{
|
||||
if(CommonMetrics::AUTO_SET_STYLE)
|
||||
{
|
||||
// with AUTO_SET_STYLE on and Autogen off, some songs may get
|
||||
// hidden. Search through every playable StepsType until you
|
||||
// find one, then add the song.
|
||||
// see Issue 147 for more information. -aj
|
||||
// http://ssc.ajworld.net/sm-ssc/bugtracker/view.php?id=147
|
||||
set<StepsType> vStepsType;
|
||||
SongUtil::GetPlayableStepsTypes( pSong, vStepsType );
|
||||
|
||||
FOREACHS( StepsType, vStepsType, st )
|
||||
{
|
||||
if(pSong->HasStepsType(*st))
|
||||
{
|
||||
arraySongs.push_back( pSong );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the song has at least one steps, add it.
|
||||
if( pSong->HasStepsType(GAMESTATE->GetCurrentStyle()->m_StepsType) )
|
||||
arraySongs.push_back( pSong );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Hack: Add extra stage item if it was eliminated for any reason
|
||||
* (eg. it's a long song). */
|
||||
if( GAMESTATE->IsAnExtraStage() )
|
||||
{
|
||||
Song* pSong;
|
||||
Steps* pSteps;
|
||||
SONGMAN->GetExtraStageInfo( GAMESTATE->IsExtraStage2(), GAMESTATE->GetCurrentStyle(), pSong, pSteps );
|
||||
|
||||
if( find( arraySongs.begin(), arraySongs.end(), pSong ) == arraySongs.end() )
|
||||
arraySongs.push_back( pSong );
|
||||
}
|
||||
}
|
||||
|
||||
void MusicWheel::BuildWheelItemDatas( vector<MusicWheelItemData *> &arrayWheelItemDatas, SortOrder so )
|
||||
{
|
||||
switch( so )
|
||||
{
|
||||
case SORT_MODE_MENU:
|
||||
{
|
||||
arrayWheelItemDatas.clear(); // clear out the previous wheel items
|
||||
vector<RString> vsNames;
|
||||
split( MODE_MENU_CHOICE_NAMES, ",", vsNames );
|
||||
for( unsigned i=0; i<vsNames.size(); ++i )
|
||||
@@ -508,10 +406,21 @@ void MusicWheel::BuildWheelItemDatas( vector<MusicWheelItemData *> &arrayWheelIt
|
||||
case SORT_LENGTH:
|
||||
case SORT_RECENT:
|
||||
{
|
||||
// Make an array of Song*, then sort them
|
||||
// Get all songs that can be shown in this sort. Filtering songs
|
||||
// that can't be played will happen later, in UpdateWheelItemDatas.
|
||||
vector<Song*> arraySongs;
|
||||
|
||||
GetSongList( arraySongs, so );
|
||||
switch( so )
|
||||
{
|
||||
case SORT_PREFERRED:
|
||||
SONGMAN->GetPreferredSortSongs( arraySongs );
|
||||
break;
|
||||
case SORT_POPULARITY:
|
||||
arraySongs = SONGMAN->GetPopularSongs();
|
||||
break;
|
||||
default:
|
||||
arraySongs = SONGMAN->GetAllSongs();
|
||||
break;
|
||||
}
|
||||
|
||||
bool bUseSections = true;
|
||||
|
||||
@@ -522,11 +431,16 @@ void MusicWheel::BuildWheelItemDatas( vector<MusicWheelItemData *> &arrayWheelIt
|
||||
// obey order specified by the preferred sort list
|
||||
break;
|
||||
case SORT_ROULETTE:
|
||||
SongUtil::SortSongPointerArrayByStepsTypeAndMeter( arraySongs, GAMESTATE->m_pCurStyle->m_StepsType, Difficulty_Easy );
|
||||
{
|
||||
StepsType st;
|
||||
Difficulty dc;
|
||||
SongUtil::GetStepsTypeAndDifficultyFromSortOrder( SORT_EASY_METER, st, dc );
|
||||
SongUtil::SortSongPointerArrayByStepsTypeAndMeter( arraySongs, st, dc );
|
||||
if( (bool)PREFSMAN->m_bPreferredSortUsesGroups )
|
||||
stable_sort( arraySongs.begin(), arraySongs.end(), SongUtil::CompareSongPointersByGroup );
|
||||
bUseSections = false;
|
||||
break;
|
||||
}
|
||||
case SORT_GROUP:
|
||||
SongUtil::SortSongPointerArrayByGroupAndTitle( arraySongs );
|
||||
if(USE_SECTIONS_WITH_PREFERRED_GROUP)
|
||||
@@ -631,15 +545,6 @@ void MusicWheel::BuildWheelItemDatas( vector<MusicWheelItemData *> &arrayWheelIt
|
||||
{
|
||||
int iSectionCount = 0;
|
||||
|
||||
// Count songs in this section
|
||||
unsigned j;
|
||||
for( j=i; j < arraySongs.size(); j++ )
|
||||
{
|
||||
if( SongUtil::GetSectionNameFromSongAndSort( arraySongs[j], so ) != sThisSection )
|
||||
break;
|
||||
}
|
||||
iSectionCount = j-i;
|
||||
|
||||
// new section, make a section item
|
||||
// todo: preferred sort section color handling? -aj
|
||||
RageColor colorSection = (so==SORT_GROUP) ? SONGMAN->GetSongGroupColor(pSong->m_sGroupName) : SECTION_COLORS.GetValue(iSectionColorIndex);
|
||||
@@ -647,7 +552,7 @@ void MusicWheel::BuildWheelItemDatas( vector<MusicWheelItemData *> &arrayWheelIt
|
||||
// In certain situations (e.g. simulating Pump it Up), themes may
|
||||
// want to only show one group at a time.
|
||||
if( !HIDE_INACTIVE_SECTIONS )
|
||||
arrayWheelItemDatas.push_back( new MusicWheelItemData(TYPE_SECTION, NULL, sThisSection, NULL, colorSection, iSectionCount) );
|
||||
arrayWheelItemDatas.push_back( new MusicWheelItemData(TYPE_SECTION, NULL, sThisSection, NULL, colorSection, 0) );
|
||||
sLastSection = sThisSection;
|
||||
}
|
||||
}
|
||||
@@ -659,16 +564,10 @@ void MusicWheel::BuildWheelItemDatas( vector<MusicWheelItemData *> &arrayWheelIt
|
||||
if( SHOW_ROULETTE )
|
||||
arrayWheelItemDatas.push_back( new MusicWheelItemData(TYPE_ROULETTE, NULL, "", NULL, ROULETTE_COLOR, 0) );
|
||||
|
||||
// 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 )
|
||||
if( SHOW_RANDOM )
|
||||
arrayWheelItemDatas.push_back( new MusicWheelItemData(TYPE_RANDOM, NULL, "", NULL, RANDOM_COLOR, 0) );
|
||||
|
||||
if( SHOW_PORTAL && bFoundAnySong )
|
||||
if( SHOW_PORTAL )
|
||||
arrayWheelItemDatas.push_back( new MusicWheelItemData(TYPE_PORTAL, NULL, "", NULL, PORTAL_COLOR, 0) );
|
||||
|
||||
// add custom wheel items
|
||||
@@ -769,8 +668,6 @@ void MusicWheel::BuildWheelItemDatas( vector<MusicWheelItemData *> &arrayWheelIt
|
||||
if( so == SORT_ALL_COURSES )
|
||||
CourseUtil::SortCoursePointerArrayByType( apCourses );
|
||||
|
||||
arrayWheelItemDatas.clear(); // clear out the previous wheel items
|
||||
|
||||
RString sLastSection = "";
|
||||
int iSectionColorIndex = 0;
|
||||
for( unsigned i=0; i<apCourses.size(); i++ ) // foreach course
|
||||
@@ -792,10 +689,6 @@ void MusicWheel::BuildWheelItemDatas( vector<MusicWheelItemData *> &arrayWheelIt
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
@@ -817,7 +710,6 @@ void MusicWheel::BuildWheelItemDatas( vector<MusicWheelItemData *> &arrayWheelIt
|
||||
MusicWheelItemData& WID = *arrayWheelItemDatas[i];
|
||||
if( WID.m_pSong != NULL )
|
||||
{
|
||||
WID.m_Flags.bHasBeginnerOr1Meter = WID.m_pSong->IsEasy( GAMESTATE->GetCurrentStyle()->m_StepsType ) && SHOW_EASY_FLAG;
|
||||
WID.m_Flags.bEdits = false;
|
||||
set<StepsType> vStepsType;
|
||||
SongUtil::GetPlayableStepsTypes( WID.m_pSong, vStepsType );
|
||||
@@ -827,25 +719,171 @@ void MusicWheel::BuildWheelItemDatas( vector<MusicWheelItemData *> &arrayWheelIt
|
||||
}
|
||||
else if( WID.m_pCourse != NULL )
|
||||
{
|
||||
WID.m_Flags.bHasBeginnerOr1Meter = false;
|
||||
WID.m_Flags.bEdits = WID.m_pCourse->IsAnEdit();
|
||||
WID.m_Flags.iStagesForSong = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// init crowns
|
||||
/* The screen is starting. Take m_UnfilteredWheelItemDatas created on load by
|
||||
* BuildWheelItemDatas and update them for the current state. Output the
|
||||
* results into m_WheelItemDatas. */
|
||||
void MusicWheel::UpdateWheelItemDatas( SortOrder so )
|
||||
{
|
||||
vector<MusicWheelItemData *> &aWheelItemDatas = m_UnfilteredWheelItemDatas[so];
|
||||
|
||||
// Only add TYPE_PORTAL if there's at least one song on the list.
|
||||
bool bFoundAnySong = false;
|
||||
for( unsigned i=0; !bFoundAnySong && i < aWheelItemDatas.size(); i++ )
|
||||
if( aWheelItemDatas[i]->m_Type == TYPE_SONG )
|
||||
bFoundAnySong = true;
|
||||
|
||||
vector<bool> aiRemove;
|
||||
aiRemove.insert( aiRemove.begin(), aWheelItemDatas.size(), false );
|
||||
|
||||
SongCriteria sc;
|
||||
sc.m_iMaxStagesForSong = GAMESTATE->GetSmallestNumStagesLeftForAnyHumanPlayer();
|
||||
|
||||
Song *pExtraStageSong = NULL;
|
||||
if( GAMESTATE->IsAnExtraStage() )
|
||||
{
|
||||
Steps *pSteps;
|
||||
SONGMAN->GetExtraStageInfo( GAMESTATE->IsExtraStage2(), GAMESTATE->GetCurrentStyle(), pExtraStageSong, pSteps );
|
||||
}
|
||||
|
||||
// Mark any songs that aren't playable in aiRemove.
|
||||
for( unsigned i=0; i< aWheelItemDatas.size(); i++ )
|
||||
{
|
||||
MusicWheelItemData& WID = *aWheelItemDatas[i];
|
||||
|
||||
// If we have no songs, remove Random and Portal.
|
||||
if( WID.m_Type == TYPE_RANDOM || WID.m_Type == TYPE_PORTAL )
|
||||
{
|
||||
if( !bFoundAnySong )
|
||||
aiRemove[i] = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Filter songs that we don't have enough stages to play.
|
||||
if( WID.m_Type == TYPE_SONG )
|
||||
{
|
||||
Song* pSong = WID.m_pSong;
|
||||
|
||||
// Never remove the extra stage song.
|
||||
if( pExtraStageSong && WID.m_pSong == pExtraStageSong )
|
||||
continue;
|
||||
|
||||
// Check that we have enough stages to play this song, and that it's not disabled.
|
||||
if( !sc.Matches(WID.m_pSong) )
|
||||
{
|
||||
aiRemove[i] = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
int iLocked = UNLOCKMAN->SongIsLocked( pSong );
|
||||
|
||||
// If we're on an extra stage, and this song is selected, ignore #SELECTABLE.
|
||||
if( pSong != GAMESTATE->m_pCurSong || !GAMESTATE->IsAnExtraStage() )
|
||||
{
|
||||
// Hide songs that asked to be hidden via #SELECTABLE.
|
||||
if( iLocked & LOCKED_SELECTABLE )
|
||||
{
|
||||
aiRemove[i] = true;
|
||||
continue;
|
||||
}
|
||||
if( so != SORT_ROULETTE && iLocked & LOCKED_ROULETTE )
|
||||
{
|
||||
aiRemove[i] = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Hide locked songs. If RANDOM_PICKS_LOCKED_SONGS, hide in Roulette
|
||||
* and Random, too. */
|
||||
if( (so!=SORT_ROULETTE || !RANDOM_PICKS_LOCKED_SONGS) && iLocked )
|
||||
{
|
||||
aiRemove[i] = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the song has no steps for the current style, remove it.
|
||||
if( !pSong->HasStepsType(GAMESTATE->GetCurrentStyle()->m_StepsType) )
|
||||
{
|
||||
aiRemove[i] = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if( WID.m_Type == TYPE_COURSE )
|
||||
{
|
||||
if( !WID.m_pCourse->IsPlayableIn(GAMESTATE->GetCurrentStyle()->m_StepsType) )
|
||||
aiRemove[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Filter out the songs we're removing.
|
||||
vector<MusicWheelItemData *> &aFilteredData = m_WheelItemDatas[so];
|
||||
aFilteredData.reserve( aWheelItemDatas.size() );
|
||||
for( unsigned i=0; i< aWheelItemDatas.size(); i++ )
|
||||
{
|
||||
if( aiRemove[i] )
|
||||
continue;
|
||||
aFilteredData.push_back( aWheelItemDatas[i] );
|
||||
}
|
||||
|
||||
// Update the song count in each section header.
|
||||
for( unsigned i=0; i < aFilteredData.size(); )
|
||||
{
|
||||
MusicWheelItemData& WID = *aFilteredData[i];
|
||||
++i;
|
||||
if( WID.m_Type != TYPE_SECTION )
|
||||
continue;
|
||||
|
||||
// Count songs in this section
|
||||
WID.m_iSectionCount = 0;
|
||||
for( ; i < aFilteredData.size() && aFilteredData[i]->m_sText == WID.m_sText; ++i )
|
||||
++WID.m_iSectionCount;
|
||||
}
|
||||
|
||||
// If we have any section headers with no songs, then we filtered all of
|
||||
// the songs in that group, so remove it. This isn't optimized like the
|
||||
// above since this is a rare case.
|
||||
for( unsigned i=0; i < aFilteredData.size(); ++i )
|
||||
{
|
||||
MusicWheelItemData& WID = *aFilteredData[i];
|
||||
if( WID.m_Type != TYPE_SECTION )
|
||||
continue;
|
||||
if( WID.m_iSectionCount > 0 )
|
||||
continue;
|
||||
aFilteredData.erase( aFilteredData.begin()+i, aFilteredData.begin()+i+1 );
|
||||
--i;
|
||||
}
|
||||
|
||||
// Update the popularity. This is affected by filtering.
|
||||
if( so == SORT_POPULARITY )
|
||||
{
|
||||
// init crown icons
|
||||
for( unsigned i=0; i< min(3u,arrayWheelItemDatas.size()); i++ )
|
||||
for( unsigned i=0; i< min(3u,aFilteredData.size()); i++ )
|
||||
{
|
||||
MusicWheelItemData& WID = *arrayWheelItemDatas[i];
|
||||
MusicWheelItemData& WID = *aFilteredData[i];
|
||||
WID.m_Flags.iPlayersBestNumber = i+1;
|
||||
}
|
||||
}
|
||||
|
||||
if( arrayWheelItemDatas.empty() )
|
||||
arrayWheelItemDatas.push_back( new MusicWheelItemData(TYPE_SECTION, NULL, "- EMPTY -", NULL, RageColor(1,0,0,1), 0) );
|
||||
// Update the easy status. This is affected by the steps type.
|
||||
if( SHOW_EASY_FLAG )
|
||||
{
|
||||
for( unsigned i=0; i<aFilteredData.size(); i++ )
|
||||
{
|
||||
MusicWheelItemData& WID = *aFilteredData[i];
|
||||
if( WID.m_pSong == NULL )
|
||||
continue;
|
||||
WID.m_Flags.bHasBeginnerOr1Meter = WID.m_pSong->IsEasy( GAMESTATE->GetCurrentStyle()->m_StepsType );
|
||||
}
|
||||
}
|
||||
|
||||
// If we've filtered all items, insert a dummy.
|
||||
if( aFilteredData.empty() )
|
||||
aFilteredData.push_back( new MusicWheelItemData(TYPE_SECTION, NULL, "- EMPTY -", NULL, RageColor(1,0,0,1), 0) );
|
||||
}
|
||||
|
||||
void MusicWheel::UpdateSwitch()
|
||||
@@ -973,7 +1011,7 @@ bool MusicWheel::ChangeSort( SortOrder new_so ) // return true if change success
|
||||
return false;
|
||||
|
||||
// Don't change to SORT_MODE_MENU if it doesn't have at least two choices.
|
||||
if( new_so == SORT_MODE_MENU && m_WheelItemDatas[new_so].size() < 2 )
|
||||
if( new_so == SORT_MODE_MENU && m_UnfilteredWheelItemDatas[new_so].size() < 2 )
|
||||
return false;
|
||||
|
||||
switch( m_WheelState )
|
||||
@@ -1109,7 +1147,7 @@ void MusicWheel::StartRandom()
|
||||
{
|
||||
// Shuffle and use the roulette wheel.
|
||||
RandomGen rnd;
|
||||
random_shuffle( m_WheelItemDatas[SORT_ROULETTE].begin(), m_WheelItemDatas[SORT_ROULETTE].end(), rnd );
|
||||
random_shuffle( m_UnfilteredWheelItemDatas[SORT_ROULETTE].begin(), m_UnfilteredWheelItemDatas[SORT_ROULETTE].end(), rnd );
|
||||
GAMESTATE->m_SortOrder.Set( SORT_ROULETTE );
|
||||
}
|
||||
else
|
||||
@@ -1147,7 +1185,7 @@ void MusicWheel::SetOpenSection( RString group )
|
||||
GAMEMAN->GetCompatibleStyles( GAMESTATE->m_pCurGame, GAMESTATE->GetNumPlayersEnabled(), vpPossibleStyles );
|
||||
|
||||
m_CurWheelItemData.clear();
|
||||
vector<MusicWheelItemData *> &from = m_WheelItemDatas[GAMESTATE->m_SortOrder];
|
||||
vector<MusicWheelItemData *> &from = m_UnfilteredWheelItemDatas[GAMESTATE->m_SortOrder];
|
||||
m_CurWheelItemData.reserve( from.size() );
|
||||
for( unsigned i = 0; i < from.size(); ++i )
|
||||
{
|
||||
@@ -1309,7 +1347,7 @@ void MusicWheel::PlayerJoined()
|
||||
// We need to rebuild the wheel item data in this situation. -aj
|
||||
if( !GAMESTATE->IsCourseMode() && !PREFSMAN->m_bAutogenSteps )
|
||||
{
|
||||
BuildWheelItemDatas( m_WheelItemDatas[GAMESTATE->m_SortOrder], GAMESTATE->m_SortOrder );
|
||||
BuildWheelItemDatas( m_UnfilteredWheelItemDatas[GAMESTATE->m_SortOrder], GAMESTATE->m_SortOrder );
|
||||
}
|
||||
|
||||
SetOpenSection( m_sExpandedSectionName );
|
||||
@@ -1359,7 +1397,7 @@ Song *MusicWheel::GetPreferredSelectionForRandomOrPortal()
|
||||
}
|
||||
|
||||
RString sPreferredGroup = m_sExpandedSectionName;
|
||||
vector<MusicWheelItemData *> &wid = m_WheelItemDatas[GAMESTATE->m_SortOrder];
|
||||
vector<MusicWheelItemData *> &wid = m_UnfilteredWheelItemDatas[GAMESTATE->m_SortOrder];
|
||||
|
||||
StepsType st = GAMESTATE->GetCurrentStyle()->m_StepsType;
|
||||
|
||||
|
||||
+3
-2
@@ -52,15 +52,16 @@ public:
|
||||
protected:
|
||||
MusicWheelItem *MakeItem();
|
||||
|
||||
void GetSongList( vector<Song*> &arraySongs, SortOrder so );
|
||||
void BuildWheelItemDatas( vector<MusicWheelItemData *> &arrayWheelItems, SortOrder so );
|
||||
void UpdateWheelItemDatas( SortOrder so );
|
||||
bool SelectSongOrCourse();
|
||||
bool SelectCourse( const Course *p );
|
||||
bool SelectModeMenuItem();
|
||||
|
||||
virtual void UpdateSwitch();
|
||||
|
||||
vector<MusicWheelItemData *> m_WheelItemDatas[NUM_SortOrder];
|
||||
vector<MusicWheelItemData *> m_UnfilteredWheelItemDatas[NUM_SortOrder];
|
||||
vector<MusicWheelItemData *> m_WheelItemDatas[NUM_SortOrder]; // aliases into m_UnfilteredWheelItemDatas
|
||||
|
||||
RString m_sLastModeMenuItem;
|
||||
SortOrder m_SortOrder;
|
||||
|
||||
+38
-23
@@ -460,8 +460,12 @@ static bool CompAscending( const pair<Song *, RString> &a, const pair<Song *, RS
|
||||
|
||||
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. */
|
||||
StepsType st;
|
||||
Difficulty dc;
|
||||
SongUtil::GetStepsTypeAndDifficultyFromSortOrder( SORT_EASY_METER, st, dc );
|
||||
|
||||
/* Optimize by pre-writing a string to compare, since doing
|
||||
* GetNumNotesWithGrade inside the sort is too slow. */
|
||||
typedef pair< Song *, RString > val;
|
||||
vector<val> vals;
|
||||
vals.reserve( vpSongsInOut.size() );
|
||||
@@ -472,10 +476,7 @@ void SongUtil::SortSongPointerArrayByGrades( vector<Song*> &vpSongsInOut, bool b
|
||||
|
||||
int iCounts[NUM_Grade];
|
||||
const Profile *pProfile = PROFILEMAN->GetMachineProfile();
|
||||
ASSERT( pProfile ); // XXX: Debugging.
|
||||
const Style *pStyle = GAMESTATE->GetCurrentStyle();
|
||||
ASSERT( pStyle ); // XXX: Debugging.
|
||||
StepsType st = pStyle->m_StepsType;
|
||||
ASSERT( pProfile );
|
||||
pProfile->GetGrades( pSong, st, iCounts );
|
||||
|
||||
RString foo;
|
||||
@@ -620,8 +621,12 @@ RString SongUtil::GetSectionNameFromSongAndSort( const Song* pSong, SortOrder so
|
||||
return RString();
|
||||
case SORT_TOP_GRADES:
|
||||
{
|
||||
StepsType st;
|
||||
Difficulty dc;
|
||||
SongUtil::GetStepsTypeAndDifficultyFromSortOrder( so, st, dc );
|
||||
|
||||
int iCounts[NUM_Grade];
|
||||
PROFILEMAN->GetMachineProfile()->GetGrades( pSong, GAMESTATE->GetCurrentStyle()->m_StepsType, iCounts );
|
||||
PROFILEMAN->GetMachineProfile()->GetGrades( pSong, st, iCounts );
|
||||
|
||||
for( int i=Grade_Tier01; i<NUM_Grade; ++i )
|
||||
{
|
||||
@@ -968,6 +973,7 @@ bool SongUtil::GetStepsTypeAndDifficultyFromSortOrder( SortOrder so, StepsType &
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bDoubles = false;
|
||||
switch( so )
|
||||
{
|
||||
DEFAULT_FAIL( so );
|
||||
@@ -976,27 +982,36 @@ bool SongUtil::GetStepsTypeAndDifficultyFromSortOrder( SortOrder so, StepsType &
|
||||
case SORT_MEDIUM_METER:
|
||||
case SORT_HARD_METER:
|
||||
case SORT_CHALLENGE_METER:
|
||||
stOut = GAMESTATE->GetCurrentStyle()->m_StepsType;
|
||||
bDoubles = false;
|
||||
break;
|
||||
case SORT_DOUBLE_EASY_METER:
|
||||
case SORT_DOUBLE_MEDIUM_METER:
|
||||
case SORT_DOUBLE_HARD_METER:
|
||||
case SORT_DOUBLE_CHALLENGE_METER:
|
||||
stOut = GAMESTATE->GetCurrentStyle()->m_StepsType; // in case we don't find any matches below
|
||||
vector<const Style*> vpStyles;
|
||||
GAMEMAN->GetStylesForGame(GAMESTATE->m_pCurGame,vpStyles);
|
||||
FOREACH_CONST( const Style*, vpStyles, i )
|
||||
{
|
||||
if( (*i)->m_StyleType == StyleType_OnePlayerTwoSides )
|
||||
{
|
||||
// Ugly hack to ignore pump's half-double.
|
||||
bool bContainsHalf = ((RString)(*i)->m_szName).find("half") != RString::npos;
|
||||
if( bContainsHalf )
|
||||
continue;
|
||||
stOut = (*i)->m_StepsType;
|
||||
break;
|
||||
}
|
||||
}
|
||||
bDoubles = true;
|
||||
break;
|
||||
}
|
||||
|
||||
stOut = StepsType_Invalid;
|
||||
|
||||
vector<const Style*> vpStyles;
|
||||
GAMEMAN->GetStylesForGame(GAMESTATE->m_pCurGame,vpStyles);
|
||||
FOREACH_CONST( const Style*, vpStyles, i )
|
||||
{
|
||||
if( !(*i)->m_bUsedForGameplay )
|
||||
continue;
|
||||
|
||||
if( bDoubles && (*i)->m_StyleType != StyleType_OnePlayerTwoSides )
|
||||
continue;
|
||||
if( !bDoubles && (*i)->m_StyleType != StyleType_OnePlayerOneSide && (*i)->m_StyleType != StyleType_TwoPlayersTwoSides )
|
||||
continue;
|
||||
|
||||
// Ugly hack to ignore pump's half-double.
|
||||
bool bContainsHalf = ((RString)(*i)->m_szName).find("half") != RString::npos;
|
||||
if( bContainsHalf )
|
||||
continue;
|
||||
|
||||
stOut = (*i)->m_StepsType;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user