From e53de2188664ec44caeee3b8a35e15b1043e7ef9 Mon Sep 17 00:00:00 2001 From: Nicolas Date: Fri, 17 Nov 2017 22:12:25 +0200 Subject: [PATCH] MSD sort orders (#106) --- .../ScreenSelectMusic overlay/currentsort.lua | 10 +- .../_fallback/Graphics/Banner Chordjack.redir | 1 + .../_fallback/Graphics/Banner Favorites.redir | 1 + .../Graphics/Banner Handstream.redir | 1 + .../_fallback/Graphics/Banner JackSpeed.redir | 1 + .../Graphics/Banner Jumpstream.redir | 1 + .../_fallback/Graphics/Banner Overall.redir | 1 + .../_fallback/Graphics/Banner Stamina.redir | 1 + Themes/_fallback/Graphics/Banner Stream.redir | 1 + .../_fallback/Graphics/Banner Technical.redir | 1 + Themes/_fallback/Languages/en.ini | 8 + Themes/_fallback/metrics.ini | 10 +- src/GameConstantsAndTypes.cpp | 8 + src/GameConstantsAndTypes.h | 8 + src/MusicWheel.cpp | 345 +++++++++--------- src/Song.cpp | 2 +- src/Song.h | 2 +- src/SongUtil.cpp | 57 ++- src/SongUtil.h | 1 + 19 files changed, 279 insertions(+), 181 deletions(-) create mode 100644 Themes/_fallback/Graphics/Banner Chordjack.redir create mode 100644 Themes/_fallback/Graphics/Banner Favorites.redir create mode 100644 Themes/_fallback/Graphics/Banner Handstream.redir create mode 100644 Themes/_fallback/Graphics/Banner JackSpeed.redir create mode 100644 Themes/_fallback/Graphics/Banner Jumpstream.redir create mode 100644 Themes/_fallback/Graphics/Banner Overall.redir create mode 100644 Themes/_fallback/Graphics/Banner Stamina.redir create mode 100644 Themes/_fallback/Graphics/Banner Stream.redir create mode 100644 Themes/_fallback/Graphics/Banner Technical.redir diff --git a/Themes/Til Death/BGAnimations/ScreenSelectMusic overlay/currentsort.lua b/Themes/Til Death/BGAnimations/ScreenSelectMusic overlay/currentsort.lua index 83e2886f3c..820454c4b7 100644 --- a/Themes/Til Death/BGAnimations/ScreenSelectMusic overlay/currentsort.lua +++ b/Themes/Til Death/BGAnimations/ScreenSelectMusic overlay/currentsort.lua @@ -17,7 +17,15 @@ local sortTable = { SortOrder_ModeMenu = 'Mode Menu', SortOrder_Length = 'Song Length', SortOrder_Recent = 'Recently Played', - SortOrder_Favorites = 'Favorites' + SortOrder_Favorites = 'Favorites', + SortOrder_Overall = 'Overall', + SortOrder_Stream = 'Stream', + SortOrder_Jumpstream = 'Jumpstream', + SortOrder_Handstream = 'Handstream', + SortOrder_Stamina = 'Stamina', + SortOrder_JackSpeed = 'JackSpeed', + SortOrder_Chordjack = 'Chordjack', + SortOrder_Technical = 'Technical' } t[#t+1] = Def.Quad{ diff --git a/Themes/_fallback/Graphics/Banner Chordjack.redir b/Themes/_fallback/Graphics/Banner Chordjack.redir new file mode 100644 index 0000000000..507050cda9 --- /dev/null +++ b/Themes/_fallback/Graphics/Banner Chordjack.redir @@ -0,0 +1 @@ +Common fallback banner \ No newline at end of file diff --git a/Themes/_fallback/Graphics/Banner Favorites.redir b/Themes/_fallback/Graphics/Banner Favorites.redir new file mode 100644 index 0000000000..507050cda9 --- /dev/null +++ b/Themes/_fallback/Graphics/Banner Favorites.redir @@ -0,0 +1 @@ +Common fallback banner \ No newline at end of file diff --git a/Themes/_fallback/Graphics/Banner Handstream.redir b/Themes/_fallback/Graphics/Banner Handstream.redir new file mode 100644 index 0000000000..507050cda9 --- /dev/null +++ b/Themes/_fallback/Graphics/Banner Handstream.redir @@ -0,0 +1 @@ +Common fallback banner \ No newline at end of file diff --git a/Themes/_fallback/Graphics/Banner JackSpeed.redir b/Themes/_fallback/Graphics/Banner JackSpeed.redir new file mode 100644 index 0000000000..507050cda9 --- /dev/null +++ b/Themes/_fallback/Graphics/Banner JackSpeed.redir @@ -0,0 +1 @@ +Common fallback banner \ No newline at end of file diff --git a/Themes/_fallback/Graphics/Banner Jumpstream.redir b/Themes/_fallback/Graphics/Banner Jumpstream.redir new file mode 100644 index 0000000000..507050cda9 --- /dev/null +++ b/Themes/_fallback/Graphics/Banner Jumpstream.redir @@ -0,0 +1 @@ +Common fallback banner \ No newline at end of file diff --git a/Themes/_fallback/Graphics/Banner Overall.redir b/Themes/_fallback/Graphics/Banner Overall.redir new file mode 100644 index 0000000000..507050cda9 --- /dev/null +++ b/Themes/_fallback/Graphics/Banner Overall.redir @@ -0,0 +1 @@ +Common fallback banner \ No newline at end of file diff --git a/Themes/_fallback/Graphics/Banner Stamina.redir b/Themes/_fallback/Graphics/Banner Stamina.redir new file mode 100644 index 0000000000..507050cda9 --- /dev/null +++ b/Themes/_fallback/Graphics/Banner Stamina.redir @@ -0,0 +1 @@ +Common fallback banner \ No newline at end of file diff --git a/Themes/_fallback/Graphics/Banner Stream.redir b/Themes/_fallback/Graphics/Banner Stream.redir new file mode 100644 index 0000000000..507050cda9 --- /dev/null +++ b/Themes/_fallback/Graphics/Banner Stream.redir @@ -0,0 +1 @@ +Common fallback banner \ No newline at end of file diff --git a/Themes/_fallback/Graphics/Banner Technical.redir b/Themes/_fallback/Graphics/Banner Technical.redir new file mode 100644 index 0000000000..507050cda9 --- /dev/null +++ b/Themes/_fallback/Graphics/Banner Technical.redir @@ -0,0 +1 @@ +Common fallback banner \ No newline at end of file diff --git a/Themes/_fallback/Languages/en.ini b/Themes/_fallback/Languages/en.ini index a25b84b8f4..5f740fa0d1 100644 --- a/Themes/_fallback/Languages/en.ini +++ b/Themes/_fallback/Languages/en.ini @@ -298,6 +298,14 @@ PreferredText=Preferred TitleText=Title RecentText=Recent FavoritesText=Favorites +OverallText=Overall +StreamText=Stream +JumpstreamText=Jumpstream +HandstreamText=Handstream +StaminaText=Stamina +JackSpeedText=JackSpeed +ChordjackText=Chordjack +TechnicalText=Technical TopGradesText=Top Grades [NetworkSyncManager] diff --git a/Themes/_fallback/metrics.ini b/Themes/_fallback/metrics.ini index 02096400f7..4f51f20bb5 100644 --- a/Themes/_fallback/metrics.ini +++ b/Themes/_fallback/metrics.ini @@ -899,7 +899,7 @@ RecentSongsToShow=30 UseEasyMarkerFlag=false -ModeMenuChoiceNames="Preferred,Group,Title,Bpm,Popularity,TopGrades,Artist,Genre,Recent,Favorites" +ModeMenuChoiceNames="Preferred,Group,Title,Bpm,Popularity,TopGrades,Artist,Genre,Recent,Favorites,Overall,Stream,Jumpstream,Handstream,Stamina,JackSpeed,Chordjack,Technical" ChoicePreferred="sort,Preferred" ChoiceGroup="sort,Group" ChoiceTitle="sort,Title" @@ -910,6 +910,14 @@ ChoiceArtist="sort,Artist" ChoiceGenre="sort,Genre" ChoiceRecent="sort,Recent" ChoiceFavorites="sort,Favorites" +ChoiceOverall="sort,Overall" +ChoiceStream="sort,Stream" +ChoiceJumpstream="sort,Jumpstream" +ChoiceHandstream="sort,Handstream" +ChoiceStamina="sort,Stamina" +ChoiceJackSpeed="sort,JackSpeed" +ChoiceChordjack="sort,Chordjack" +ChoiceTechnical="sort,Technical" CustomWheelItemNames="" diff --git a/src/GameConstantsAndTypes.cpp b/src/GameConstantsAndTypes.cpp index cef5348bdc..0b7a6b58b3 100644 --- a/src/GameConstantsAndTypes.cpp +++ b/src/GameConstantsAndTypes.cpp @@ -136,6 +136,14 @@ static const char *SortOrderNames[] = { "ModeMenu", "Recent", "Favorites", + "Overall", + "Stream", + "Jumpstream", + "Handstream", + "Stamina", + "JackSpeed", + "Chordjack", + "Technical" }; XToString( SortOrder ); StringToX( SortOrder ); diff --git a/src/GameConstantsAndTypes.h b/src/GameConstantsAndTypes.h index dbb10b1cce..298fb34939 100644 --- a/src/GameConstantsAndTypes.h +++ b/src/GameConstantsAndTypes.h @@ -172,6 +172,14 @@ enum SortOrder SORT_MODE_MENU, /**< Have access to the menu for choosing the sort. */ SORT_RECENT, SORT_FAVORITES, + SORT_Overall, + SORT_Stream, + SORT_Jumpstream, + SORT_Handstream, + SORT_Stamina, + SORT_JackSpeed, + SORT_Chordjack, + SORT_Technical, NUM_SortOrder, SortOrder_Invalid }; diff --git a/src/MusicWheel.cpp b/src/MusicWheel.cpp index 0d20d87505..b17bd9bf92 100644 --- a/src/MusicWheel.cpp +++ b/src/MusicWheel.cpp @@ -603,212 +603,219 @@ void MusicWheel::BuildWheelItemDatas( vector &arrayWheelIt { map commanDZ; - switch( so ) + if(so==SORT_MODE_MENU) { - case SORT_MODE_MENU: + arrayWheelItemDatas.clear(); // clear out the previous wheel items + vector vsNames; + split( MODE_MENU_CHOICE_NAMES, ",", vsNames ); + for( unsigned i=0; i vsNames; - split( MODE_MENU_CHOICE_NAMES, ",", vsNames ); - for( unsigned i=0; i( new GameCommand ); - wid.m_pAction->m_sName = vsNames[i]; - wid.m_pAction->Load( i, ParseCommands(CHOICE.GetValue(vsNames[i])) ); - wid.m_sLabel = WHEEL_TEXT( vsNames[i] ); + MusicWheelItemData wid( WheelItemDataType_Sort, NULL, "", SORT_MENU_COLOR, 0 ); + wid.m_pAction = HiddenPtr( new GameCommand ); + wid.m_pAction->m_sName = vsNames[i]; + wid.m_pAction->Load( i, ParseCommands(CHOICE.GetValue(vsNames[i])) ); + wid.m_sLabel = WHEEL_TEXT( vsNames[i] ); - if( !wid.m_pAction->IsPlayable() ) - continue; + if( !wid.m_pAction->IsPlayable() ) + continue; - arrayWheelItemDatas.emplace_back( new MusicWheelItemData(wid) ); - } - break; + arrayWheelItemDatas.emplace_back( new MusicWheelItemData(wid) ); } - - case SORT_FAVORITES: - case SORT_PREFERRED: - case SORT_GROUP: - case SORT_TITLE: - case SORT_BPM: - case SORT_POPULARITY: - case SORT_TOP_GRADES: - case SORT_ARTIST: - case SORT_GENRE: - case SORT_RECENT: - { - // Make an array of Song*, then sort them - vector arraySongs; - GetSongList( arraySongs, so ); + } + else + { + // Make an array of Song*, then sort them + vector arraySongs; + GetSongList( arraySongs, so ); + + Message msg("FilterResults"); + msg.SetParam("Total", static_cast(arraySongs.size())); - Message msg("FilterResults"); - msg.SetParam("Total", static_cast(arraySongs.size())); + if (searching) + FilterBySearch(arraySongs, findme); - if (searching) - FilterBySearch(arraySongs, findme); + if (FILTERMAN->AnyActiveFilter()) + FilterBySkillsets(arraySongs); - if (FILTERMAN->AnyActiveFilter()) - FilterBySkillsets(arraySongs); + msg.SetParam("Matches", static_cast(arraySongs.size())); + MESSAGEMAN->Broadcast(msg); - msg.SetParam("Matches", static_cast(arraySongs.size())); - MESSAGEMAN->Broadcast(msg); + bool bUseSections = true; - bool bUseSections = true; + // sort the songs + switch( so ) + { + case SORT_FAVORITES: + case SORT_PREFERRED: + // obey order specified by the preferred sort list + break; + case SORT_GROUP: + SongUtil::SortSongPointerArrayByGroupAndTitle( arraySongs ); + + if(USE_SECTIONS_WITH_PREFERRED_GROUP) + bUseSections = true; + else + bUseSections = GAMESTATE->m_sPreferredSongGroup == GROUP_ALL; + break; + case SORT_TITLE: + SongUtil::SortSongPointerArrayByTitle( arraySongs ); + break; + case SORT_BPM: + SongUtil::SortSongPointerArrayByBPM( arraySongs ); + break; + case SORT_POPULARITY: + if(static_cast(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::SortSongPointerArrayByGrades( arraySongs, true ); + break; + case SORT_ARTIST: + SongUtil::SortSongPointerArrayByArtist( arraySongs ); + break; + case SORT_GENRE: + SongUtil::SortSongPointerArrayByGenre( arraySongs ); + break; + case SORT_RECENT: + if( static_cast(arraySongs.size()) > RECENT_SONGS_TO_SHOW ) + arraySongs.erase( arraySongs.begin()+RECENT_SONGS_TO_SHOW, arraySongs.end() ); + bUseSections = false; + break; + case SORT_Overall: + SongUtil::SortSongPointerArrayByGroupAndMSD(arraySongs, Skill_Overall); + break; + case SORT_Stream: + SongUtil::SortSongPointerArrayByGroupAndMSD(arraySongs, Skill_Stream); + break; + case SORT_Jumpstream: + SongUtil::SortSongPointerArrayByGroupAndMSD(arraySongs, Skill_Jumpstream); + break; + case SORT_Handstream: + SongUtil::SortSongPointerArrayByGroupAndMSD(arraySongs, Skill_Handstream); + break; + case SORT_Stamina: + SongUtil::SortSongPointerArrayByGroupAndMSD(arraySongs, Skill_Stamina); + break; + case SORT_JackSpeed: + SongUtil::SortSongPointerArrayByGroupAndMSD(arraySongs, Skill_JackSpeed); + break; + case SORT_Chordjack: + SongUtil::SortSongPointerArrayByGroupAndMSD(arraySongs, Skill_Chordjack); + break; + case SORT_Technical: + SongUtil::SortSongPointerArrayByGroupAndMSD(arraySongs, Skill_Technical); + break; + default: + FAIL_M("Unhandled sort order! Aborting..."); + } + + // 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 MusicWheelUsesSections_NEVER: + bUseSections = false; + break; + case MusicWheelUsesSections_ABC_ONLY: + if( so != SORT_TITLE && so != SORT_GROUP ) + bUseSections = false; + break; + default: + break; + } - // sort the songs + 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. */ switch( so ) { case SORT_FAVORITES: case SORT_PREFERRED: - // obey order specified by the preferred sort list - break; - case SORT_GROUP: - SongUtil::SortSongPointerArrayByGroupAndTitle( arraySongs ); - - if(USE_SECTIONS_WITH_PREFERRED_GROUP) - bUseSections = true; - else - bUseSections = GAMESTATE->m_sPreferredSongGroup == GROUP_ALL; - break; - case SORT_TITLE: - SongUtil::SortSongPointerArrayByTitle( arraySongs ); - break; - case SORT_BPM: - SongUtil::SortSongPointerArrayByBPM( arraySongs ); - break; - case SORT_POPULARITY: - if(static_cast(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::SortSongPointerArrayByGrades( arraySongs, true ); - break; - case SORT_ARTIST: - SongUtil::SortSongPointerArrayByArtist( arraySongs ); - break; - case SORT_GENRE: - SongUtil::SortSongPointerArrayByGenre( arraySongs ); - break; - case SORT_RECENT: - if( static_cast(arraySongs.size()) > RECENT_SONGS_TO_SHOW ) - arraySongs.erase( arraySongs.begin()+RECENT_SONGS_TO_SHOW, arraySongs.end() ); - bUseSections = false; - break; - default: - FAIL_M("Unhandled sort order! Aborting..."); - } - - // 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 MusicWheelUsesSections_NEVER: - bUseSections = false; - break; - case MusicWheelUsesSections_ABC_ONLY: - if( so != SORT_TITLE && so != SORT_GROUP ) - bUseSections = false; - break; + case SORT_BPM: + break; // don't sort by section default: + SongUtil::SortSongPointerArrayBySectionName(arraySongs, so); break; } + } - if( bUseSections ) + // make WheelItemDatas with sections + + if (so != SORT_GROUP) { + // the old code, to unbreak title sort etc -mina + RString sLastSection = ""; + int iSectionColorIndex = 0; + for (unsigned i = 0; i< arraySongs.size(); i++) { - // 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. */ - switch( so ) + Song* pSong = arraySongs[i]; + if (bUseSections) { - case SORT_FAVORITES: - case SORT_PREFERRED: - case SORT_TOP_GRADES: - case SORT_BPM: - break; // don't sort by section - default: - SongUtil::SortSongPointerArrayBySectionName(arraySongs, so); - break; - } - } - - // make WheelItemDatas with sections + RString sThisSection = SongUtil::GetSectionNameFromSongAndSort(pSong, so); - if (so != SORT_GROUP) { - // the old code, to unbreak title sort etc -mina - RString sLastSection = ""; - int iSectionColorIndex = 0; - for (unsigned i = 0; i< arraySongs.size(); i++) - { - Song* pSong = arraySongs[i]; - if (bUseSections) + if (sThisSection != sLastSection) { - RString sThisSection = SongUtil::GetSectionNameFromSongAndSort(pSong, so); - - if (sThisSection != sLastSection) + int iSectionCount = 0; + // Count songs in this section + unsigned j; + for (j = i; j < arraySongs.size(); j++) { - 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); - iSectionColorIndex = (iSectionColorIndex + 1) % NUM_SECTION_COLORS; - arrayWheelItemDatas.emplace_back(new MusicWheelItemData(WheelItemDataType_Section, NULL, sThisSection, colorSection, iSectionCount)); - sLastSection = sThisSection; + 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); + iSectionColorIndex = (iSectionColorIndex + 1) % NUM_SECTION_COLORS; + arrayWheelItemDatas.emplace_back(new MusicWheelItemData(WheelItemDataType_Section, NULL, sThisSection, colorSection, iSectionCount)); + sLastSection = sThisSection; } - arrayWheelItemDatas.emplace_back(new MusicWheelItemData(WheelItemDataType_Song, pSong, sLastSection, SONGMAN->GetSongColor(pSong), 0)); } - } else { + arrayWheelItemDatas.emplace_back(new MusicWheelItemData(WheelItemDataType_Song, pSong, sLastSection, SONGMAN->GetSongColor(pSong), 0)); + } + } else { - // forces sections for now because who doesnt use sections wtf -mina - RString sLastSection = ""; - int iSectionColorIndex = 0; + // forces sections for now because who doesnt use sections wtf -mina + RString sLastSection = ""; + int iSectionColorIndex = 0; - set hurp; - for (auto& a : arraySongs) - hurp.emplace(a); + set hurp; + for (auto& a : arraySongs) + hurp.emplace(a); - auto& groups = SONGMAN->groupderps; + auto& groups = SONGMAN->groupderps; - map shitterstrats; - for (auto& n : groups) { - shitterstrats[Rage::make_lower(n.first)] = n.first; - SongUtil::SortSongPointerArrayByTitle(groups[n.first]); - } + map shitterstrats; + for (auto& n : groups) { + shitterstrats[Rage::make_lower(n.first)] = n.first; + SongUtil::SortSongPointerArrayByTitle(groups[n.first]); + } - for (auto& n : shitterstrats) { - auto& gname = n.second; - auto& gsongs = groups[n.second]; + for (auto& n : shitterstrats) { + auto& gname = n.second; + auto& gsongs = groups[n.second]; - RageColor colorSection = (so == SORT_GROUP) ? SONGMAN->GetSongGroupColor(gname) : SECTION_COLORS.GetValue(iSectionColorIndex); - iSectionColorIndex = (iSectionColorIndex + 1) % NUM_SECTION_COLORS; - arrayWheelItemDatas.emplace_back(new MusicWheelItemData(WheelItemDataType_Section, NULL, gname, colorSection, gsongs.size())); + RageColor colorSection = (so == SORT_GROUP) ? SONGMAN->GetSongGroupColor(gname) : SECTION_COLORS.GetValue(iSectionColorIndex); + iSectionColorIndex = (iSectionColorIndex + 1) % NUM_SECTION_COLORS; + arrayWheelItemDatas.emplace_back(new MusicWheelItemData(WheelItemDataType_Section, NULL, gname, colorSection, gsongs.size())); - // need to interact with the filter/search system so check if the song is in the arraysongs set defined above -mina - for (auto& s : gsongs) - if (hurp.count(s)) - arrayWheelItemDatas.emplace_back(new MusicWheelItemData(WheelItemDataType_Song, s, gname, SONGMAN->GetSongColor(s), 0)); - } + // need to interact with the filter/search system so check if the song is in the arraysongs set defined above -mina + for (auto& s : gsongs) + if (hurp.count(s)) + arrayWheelItemDatas.emplace_back(new MusicWheelItemData(WheelItemDataType_Song, s, gname, SONGMAN->GetSongColor(s), 0)); } - break; } - default: - break; } // init music status icons diff --git a/src/Song.cpp b/src/Song.cpp index bf8164c19d..c0418f0372 100644 --- a/src/Song.cpp +++ b/src/Song.cpp @@ -1663,7 +1663,7 @@ float Song::GetPreviewStartSeconds() const return 0.0f; } -float Song::GetHighestOfSkillsetAllSteps(int x, float rate) { +float Song::GetHighestOfSkillsetAllSteps(int x, float rate) const { CLAMP(rate, 0.7f, 2.f); float o = 0.f; vector vsteps = GetAllSteps(); diff --git a/src/Song.h b/src/Song.h index 9869bc1b6c..720aab26fe 100644 --- a/src/Song.h +++ b/src/Song.h @@ -265,7 +265,7 @@ class Song // how have i not jammed anything here yet - mina // Get the highest value for a specific skillset across all the steps objects for the song at a given rate - float GetHighestOfSkillsetAllSteps(int x, float rate); + float GetHighestOfSkillsetAllSteps(int x, float rate) const; bool IsSkillsetHighestOfAnySteps(Skillset ss, float rate); // For loading only: diff --git a/src/SongUtil.cpp b/src/SongUtil.cpp index e0dd1f27cd..2756bfeebd 100644 --- a/src/SongUtil.cpp +++ b/src/SongUtil.cpp @@ -381,6 +381,19 @@ static bool CompareSongPointersByTitle( const Song *pSong1, const Song *pSong2 ) return pSong1->GetSongFilePath().CompareNoCase(pSong2->GetSongFilePath()) < 0; } +static bool CompareSongPointersByMSD(const Song *pSong1, const Song *pSong2, Skillset ss) +{ + // Prefer transliterations to full titles + float msd1 = pSong1->GetHighestOfSkillsetAllSteps(static_cast(ss), GAMESTATE->m_SongOptions.Get(ModsLevel_Current).m_fMusicRate); + float msd2 = pSong2->GetHighestOfSkillsetAllSteps(static_cast(ss), GAMESTATE->m_SongOptions.Get(ModsLevel_Current).m_fMusicRate); + + if (msd1 < msd2) return true; + if (msd1 > msd2) return false; + + /* The titles are the same. Ensure we get a consistent ordering + * by comparing the unique SongFilePaths. */ + return pSong1->GetSongFilePath().CompareNoCase(pSong2->GetSongFilePath()) < 0; +} void SongUtil::SortSongPointerArrayByTitle( vector &vpSongsInOut ) { sort( vpSongsInOut.begin(), vpSongsInOut.end(), CompareSongPointersByTitle ); @@ -506,23 +519,43 @@ int SongUtil::CompareSongPointersByGroup(const Song *pSong1, const Song *pSong2) } static int CompareSongPointersByGroupAndTitle( const Song *pSong1, const Song *pSong2 ) +{ + int g = SongUtil::CompareSongPointersByGroup(pSong1, pSong2); + if (g == 0) + /* Same group; compare by name. */ + return CompareSongPointersByTitle( pSong1, pSong2 ); + return g < 0; +} + +static int CompareSongPointersByGroup(const Song *pSong1, const Song *pSong2) { const RString &sGroup1 = pSong1->m_sGroupName; const RString &sGroup2 = pSong2->m_sGroupName; - if( sGroup1 < sGroup2 ) - return true; - if( sGroup1 > sGroup2 ) - return false; - - /* Same group; compare by name. */ - return CompareSongPointersByTitle( pSong1, pSong2 ); + if (sGroup1 < sGroup2) + return -1; + if (sGroup1 > sGroup2) + return 1; + return 0; +} +std::function CompareSongPointersByGroupAndMSD(Skillset ss) +{ + return [&ss](const Song *pSong1, const Song *pSong2) { + int g = CompareSongPointersByGroup(pSong1, pSong2); + if (g == 0) + /* Same group; compare by MSD. */ + return static_cast(CompareSongPointersByMSD(pSong1, pSong2, ss)); + return static_cast(g < 0); + }; } - void SongUtil::SortSongPointerArrayByGroupAndTitle( vector &vpSongsInOut ) { sort( vpSongsInOut.begin(), vpSongsInOut.end(), CompareSongPointersByGroupAndTitle ); } +void SongUtil::SortSongPointerArrayByGroupAndMSD(vector &vpSongsInOut, Skillset ss) +{ + sort(vpSongsInOut.begin(), vpSongsInOut.end(), CompareSongPointersByGroupAndMSD(ss)); +} void SongUtil::SortSongPointerArrayByNumPlays( vector &vpSongsInOut, ProfileSlot slot, bool bDescending ) { @@ -552,6 +585,14 @@ RString SongUtil::GetSectionNameFromSongAndSort( const Song* pSong, SortOrder so case SORT_PREFERRED: return SONGMAN->SongToPreferredSortSectionName( pSong ); case SORT_GROUP: + case SORT_Overall: + case SORT_Stream: + case SORT_Jumpstream: + case SORT_Handstream: + case SORT_Stamina: + case SORT_JackSpeed: + case SORT_Chordjack: + case SORT_Technical: // guaranteed not empty return pSong->m_sGroupName; case SORT_TITLE: diff --git a/src/SongUtil.h b/src/SongUtil.h index 28630b8ee1..e0a41143a3 100644 --- a/src/SongUtil.h +++ b/src/SongUtil.h @@ -138,6 +138,7 @@ namespace SongUtil void SortSongPointerArrayByDisplayArtist( vector &vpSongsInOut ); void SortSongPointerArrayByGenre( vector &vpSongsInOut ); void SortSongPointerArrayByGroupAndTitle( vector &vpSongsInOut ); + void SortSongPointerArrayByGroupAndMSD(vector &vpSongsInOut, Skillset ss); void SortSongPointerArrayByNumPlays( vector &vpSongsInOut, ProfileSlot slot, bool bDescending ); void SortSongPointerArrayByNumPlays( vector &vpSongsInOut, const Profile* pProfile, bool bDescending ); void SortSongPointerArrayByStepsTypeAndMeter( vector &vpSongsInOut, StepsType st, Difficulty dc );