diff --git a/stepmania/src/CatalogXml.cpp b/stepmania/src/CatalogXml.cpp index 8e32cd65ad..b70cdbe2b9 100644 --- a/stepmania/src/CatalogXml.cpp +++ b/stepmania/src/CatalogXml.cpp @@ -99,7 +99,7 @@ void CatalogXml::Save( LoadingWindow *loading_window ) iNumSongsInGroup++; FOREACH_CONST( Difficulty, CommonMetrics::DIFFICULTIES_TO_SHOW.GetValue(), dc ) { - Steps* pSteps = pSong->GetStepsByDifficulty( *st, *dc, false ); // no autogen + Steps* pSteps = SongUtil::GetStepsByDifficulty( pSong, *st, *dc, false ); // no autogen /* * There is no point in storing the steps if either there @@ -193,7 +193,7 @@ void CatalogXml::Save( LoadingWindow *loading_window ) { FOREACH_CONST( Difficulty, CommonMetrics::DIFFICULTIES_TO_SHOW.GetValue(), dc ) { - Steps* pSteps = pSong->GetStepsByDifficulty( *st, *dc, false ); // no autogen + Steps* pSteps = SongUtil::GetStepsByDifficulty( pSong, *st, *dc, false ); // no autogen if( pSteps == NULL ) continue; // skip if( UNLOCKMAN->StepsIsLocked(pSong,pSteps) ) diff --git a/stepmania/src/Course.h b/stepmania/src/Course.h index 26a6df8e11..710f2c5cf0 100644 --- a/stepmania/src/Course.h +++ b/stepmania/src/Course.h @@ -11,6 +11,8 @@ #include #include "EnumHelper.h" #include "RageTypes.h" +#include "SongUtil.h" +#include "StepsUtil.h" class PlayerOptions; class SongOptions; @@ -59,11 +61,9 @@ public: // filter criteria, applied from top to bottom // TODO: change this to be a SongID Song* pSong; // don't filter if NULL - RString sSongGroup; // don't filter if empty - Difficulty baseDifficulty; // don't filter if DIFFICULTY_INVALID + SongCriteria songCriteria; + StepsCriteria stepsCriteria; bool bNoDifficult; // if true, CourseDifficulty doesn't affect this entry - int iLowMeter; // don't filter if -1 - int iHighMeter; // don't filter if -1 SongSort songSort; // sort by this after filtering int iChooseIndex; // @@ -77,11 +77,7 @@ public: bSecret = false; pSong = NULL; - sSongGroup = ""; - baseDifficulty = DIFFICULTY_INVALID; bNoDifficult = false; - iLowMeter = -1; - iHighMeter = -1; songSort = SongSort_Randomize; iChooseIndex = 0; diff --git a/stepmania/src/CourseEntryDisplay.cpp b/stepmania/src/CourseEntryDisplay.cpp index a84b86d8f3..bea416d21a 100644 --- a/stepmania/src/CourseEntryDisplay.cpp +++ b/stepmania/src/CourseEntryDisplay.cpp @@ -129,8 +129,8 @@ void CourseEntryDisplay::SetFromGameState( int iCourseEntryIndex ) if( te == NULL || ce == NULL ) continue; - int iLow = ce->iLowMeter; - int iHigh = ce->iHighMeter; + int iLow = ce->stepsCriteria.m_iLowMeter; + int iHigh = ce->stepsCriteria.m_iHighMeter; bool bLowIsSet = iLow != -1; bool bHighIsSet = iHigh != -1; diff --git a/stepmania/src/CourseUtil.cpp b/stepmania/src/CourseUtil.cpp index d15bade5c8..9756f26bf0 100644 --- a/stepmania/src/CourseUtil.cpp +++ b/stepmania/src/CourseUtil.cpp @@ -192,7 +192,7 @@ void CourseUtil::SortByMostRecentlyPlayedForMachine( vector &vpCoursesI void CourseUtil::MakeDefaultEditCourseEntry( CourseEntry& out ) { out.pSong = GAMESTATE->GetDefaultSong(); - out.baseDifficulty = DIFFICULTY_MEDIUM; + out.stepsCriteria.m_difficulty = DIFFICULTY_MEDIUM; } ////////////////////////////////// @@ -223,12 +223,12 @@ void CourseUtil::AutogenEndlessFromGroup( const RString &sGroupName, Difficulty // gameplay. (We might still get a repeat at the repeat boundary, // but that'd be rare.) -glenn CourseEntry e; - e.sSongGroup = sGroupName; - e.baseDifficulty = diff; + e.songCriteria.m_sGroupName = sGroupName; + e.stepsCriteria.m_difficulty = diff; e.bSecret = true; vector vSongs; - SONGMAN->GetSongs( vSongs, e.sSongGroup ); + SONGMAN->GetSongs( vSongs, e.songCriteria.m_sGroupName ); for( unsigned i = 0; i < vSongs.size(); ++i) out.m_vEntries.push_back( e ); } @@ -283,7 +283,7 @@ void CourseUtil::AutogenOniFromArtist( const RString &sArtistName, RString sArti aSongs.erase( aSongs.begin()+4, aSongs.end() ); CourseEntry e; - e.baseDifficulty = dc; + e.stepsCriteria.m_difficulty = dc; for( unsigned i = 0; i < aSongs.size(); ++i ) { diff --git a/stepmania/src/CourseWriterCRS.cpp b/stepmania/src/CourseWriterCRS.cpp index 6ff45f2af8..7a4f1ae9bc 100644 --- a/stepmania/src/CourseWriterCRS.cpp +++ b/stepmania/src/CourseWriterCRS.cpp @@ -105,13 +105,13 @@ bool CourseWriterCRS::Write( const Course &course, RageFileBasic &f, bool bSavin const RString &sSong = Basename( entry.pSong->GetSongDir() ); f.Write( "#SONG:" ); - if( !entry.sSongGroup.empty() ) - f.Write( entry.sSongGroup + '/' ); + if( !entry.songCriteria.m_sGroupName.empty() ) + f.Write( entry.songCriteria.m_sGroupName + '/' ); f.Write( sSong ); } - else if( !entry.sSongGroup.empty() ) + else if( !entry.songCriteria.m_sGroupName.empty() ) { - f.Write( ssprintf( "#SONG:%s/*", entry.sSongGroup.c_str() ) ); + f.Write( ssprintf( "#SONG:%s/*", entry.songCriteria.m_sGroupName.c_str() ) ); } else { @@ -119,10 +119,10 @@ bool CourseWriterCRS::Write( const Course &course, RageFileBasic &f, bool bSavin } f.Write( ":" ); - if( entry.baseDifficulty != DIFFICULTY_INVALID ) - f.Write( DifficultyToString(entry.baseDifficulty) ); - else if( entry.iLowMeter != -1 && entry.iHighMeter != -1 ) - f.Write( ssprintf( "%d..%d", entry.iLowMeter, entry.iHighMeter ) ); + if( entry.stepsCriteria.m_difficulty != DIFFICULTY_INVALID ) + f.Write( DifficultyToString(entry.stepsCriteria.m_difficulty) ); + else if( entry.stepsCriteria.m_iLowMeter != -1 && entry.stepsCriteria.m_iHighMeter != -1 ) + f.Write( ssprintf( "%d..%d", entry.stepsCriteria.m_iLowMeter, entry.stepsCriteria.m_iHighMeter ) ); f.Write( ":" ); RString sModifiers = entry.sModifiers; diff --git a/stepmania/src/DifficultyList.cpp b/stepmania/src/DifficultyList.cpp index b6a48fb565..f22be27fc8 100644 --- a/stepmania/src/DifficultyList.cpp +++ b/stepmania/src/DifficultyList.cpp @@ -13,6 +13,7 @@ #include "CommonMetrics.h" #include "Command.h" #include "Foreach.h" +#include "SongUtil.h" #define MAX_METERS NUM_Difficulty + MAX_EDITS_PER_SONG @@ -276,7 +277,7 @@ void DifficultyList::SetFromGameState() else { vector CurSteps; - pSong->GetSteps( CurSteps, GAMESTATE->GetCurrentStyle()->m_StepsType ); + SongUtil::GetSteps( pSong, CurSteps, GAMESTATE->GetCurrentStyle()->m_StepsType ); /* Should match the sort in ScreenSelectMusic::AfterMusicChange. */ StepsUtil::RemoveLockedSteps( pSong, CurSteps ); diff --git a/stepmania/src/EditMenu.cpp b/stepmania/src/EditMenu.cpp index d462effb64..ae342de2f5 100644 --- a/stepmania/src/EditMenu.cpp +++ b/stepmania/src/EditMenu.cpp @@ -409,7 +409,7 @@ void EditMenu::OnRowValueChanged( EditMenuRow row ) case EditMode_Practice: { vector v; - GetSelectedSong()->GetSteps( v, GetSelectedStepsType(), DIFFICULTY_EDIT ); + SongUtil::GetSteps( GetSelectedSong(), v, GetSelectedStepsType(), DIFFICULTY_EDIT ); StepsUtil::SortStepsByDescription( v ); FOREACH_CONST( Steps*, v, p ) m_vpSteps.push_back( StepsAndDifficulty(*p,dc) ); @@ -437,7 +437,7 @@ void EditMenu::OnRowValueChanged( EditMenuRow row ) } else { - Steps *pSteps = GetSelectedSong()->GetStepsByDifficulty( GetSelectedStepsType(), dc ); + Steps *pSteps = SongUtil::GetStepsByDifficulty( GetSelectedSong(), GetSelectedStepsType(), dc ); if( pSteps && UNLOCKMAN->StepsIsLocked( GetSelectedSong(), pSteps ) ) pSteps = NULL; @@ -512,14 +512,14 @@ void EditMenu::OnRowValueChanged( EditMenuRow row ) // fill in m_vpSourceSteps if( dc != DIFFICULTY_EDIT ) { - Steps *pSteps = GetSelectedSong()->GetStepsByDifficulty( GetSelectedSourceStepsType(), dc ); + Steps *pSteps = SongUtil::GetStepsByDifficulty( GetSelectedSong(), GetSelectedSourceStepsType(), dc ); if( pSteps != NULL ) m_vpSourceSteps.push_back( StepsAndDifficulty(pSteps,dc) ); } else { vector v; - GetSelectedSong()->GetSteps( v, GetSelectedSourceStepsType(), dc ); + SongUtil::GetSteps( GetSelectedSong(), v, GetSelectedSourceStepsType(), dc ); StepsUtil::SortStepsByDescription( v ); FOREACH_CONST( Steps*, v, pSteps ) m_vpSourceSteps.push_back( StepsAndDifficulty(*pSteps,dc) ); diff --git a/stepmania/src/GameCommand.cpp b/stepmania/src/GameCommand.cpp index d864ed9c63..89014ceb5d 100644 --- a/stepmania/src/GameCommand.cpp +++ b/stepmania/src/GameCommand.cpp @@ -254,9 +254,9 @@ void GameCommand::LoadOne( const Command& cmd ) Difficulty dc = StringToDifficulty( sSteps ); if( dc != DIFFICULTY_EDIT ) - m_pSteps = pSong->GetStepsByDifficulty( pStyle->m_StepsType, dc ); + m_pSteps = SongUtil::GetStepsByDifficulty( pSong, pStyle->m_StepsType, dc ); else - m_pSteps = pSong->GetStepsByDescription( pStyle->m_StepsType, sSteps ); + m_pSteps = SongUtil::GetStepsByDescription( pSong, pStyle->m_StepsType, sSteps ); if( m_pSteps == NULL ) { m_sInvalidReason = "steps not found"; diff --git a/stepmania/src/GameSoundManager.cpp b/stepmania/src/GameSoundManager.cpp index 2d63858801..2440fa9ba4 100644 --- a/stepmania/src/GameSoundManager.cpp +++ b/stepmania/src/GameSoundManager.cpp @@ -14,6 +14,7 @@ #include "song.h" #include "Steps.h" #include "LightsManager.h" +#include "SongUtil.h" GameSoundManager *SOUND = NULL; @@ -142,7 +143,7 @@ static void StartMusic( MusicToPlay &ToPlay ) ToPlay.HasTiming = true; ToPlay.timing_data = song.m_Timing; // get cabinet lights if any - Steps *pStepsCabinetLights = song.GetOneSteps( STEPS_TYPE_LIGHTS_CABINET ); + Steps *pStepsCabinetLights = SongUtil::GetOneSteps( &song, STEPS_TYPE_LIGHTS_CABINET ); if( pStepsCabinetLights ) pStepsCabinetLights->GetNoteData( ToPlay.lights_data ); } diff --git a/stepmania/src/GameState.cpp b/stepmania/src/GameState.cpp index 676db8cd9c..811dbdb50c 100644 --- a/stepmania/src/GameState.cpp +++ b/stepmania/src/GameState.cpp @@ -1222,14 +1222,6 @@ bool GameState::ShowW1() const } } -struct SongAndSteps -{ - Song* pSong; - Steps* pSteps; - bool operator==( const SongAndSteps& other ) const { return pSong==other.pSong && pSteps==other.pSteps; } - bool operator<( const SongAndSteps& other ) const { return pSong<=other.pSong && pSteps<=other.pSteps; } -}; - void GameState::GetRankingFeats( PlayerNumber pn, vector &asFeatsOut ) const { if( !IsHumanPlayer(pn) ) diff --git a/stepmania/src/MusicBannerWheel.cpp b/stepmania/src/MusicBannerWheel.cpp index e15d20e0cc..4359e7d4a9 100644 --- a/stepmania/src/MusicBannerWheel.cpp +++ b/stepmania/src/MusicBannerWheel.cpp @@ -21,6 +21,7 @@ TODO: #include "song.h" #include "Steps.h" #include "ActorUtil.h" +#include "SongUtil.h" #define BANNERSPACING THEME->GetMetricI("ScreenEz2SelectMusic","BannerSpacing") #define MAXSONGSINBUFFER 5 @@ -68,7 +69,7 @@ MusicBannerWheel::MusicBannerWheel() for ( unsigned i = 0; i < arraySongs.size(); i++) { //ONLY get non-autogenned steps - Steps* pSteps = arraySongs[i]->GetStepsByDifficulty( GAMESTATE->GetCurrentStyle()->m_StepsType, DIFFICULTY_INVALID, false ); + Steps* pSteps = SongUtil::GetStepsByDifficulty( arraySongs[i], GAMESTATE->GetCurrentStyle()->m_StepsType, DIFFICULTY_INVALID, false ); if ( pSteps != NULL ) pNotAutogen.push_back( arraySongs[i] ); } diff --git a/stepmania/src/NotesLoaderBMS.cpp b/stepmania/src/NotesLoaderBMS.cpp index 56eebe764a..44724108b8 100644 --- a/stepmania/src/NotesLoaderBMS.cpp +++ b/stepmania/src/NotesLoaderBMS.cpp @@ -6,6 +6,7 @@ #include "GameManager.h" #include "RageException.h" #include "RageFile.h" +#include "SongUtil.h" #include "StepsUtil.h" #include "song.h" #include "Steps.h" @@ -997,7 +998,7 @@ void BMSLoader::SlideDuplicateDifficulties( Song &p ) continue; vector vSteps; - p.GetSteps( vSteps, st, dc ); + SongUtil::GetSteps( &p, vSteps, st, dc ); StepsUtil::SortNotesArrayByDifficulty( vSteps ); for( unsigned k=1; k aNotes; - s->GetSteps( aNotes, st->m_StepsType ); + SongUtil::GetSteps( s, aNotes, st->m_StepsType ); StepsUtil::SortNotesArrayByDifficulty( aNotes ); - const Steps* pSteps = s->GetStepsByDifficulty( st->m_StepsType, dc ); + const Steps* pSteps = SongUtil::GetStepsByDifficulty( s, st->m_StepsType, dc ); if( pSteps && PROFILEMAN->IsPersistentProfile(slot) ) hsOut = PROFILEMAN->GetProfile(slot)->GetStepsHighScoreList(s,pSteps).GetTopScore(); diff --git a/stepmania/src/ScreenEdit.cpp b/stepmania/src/ScreenEdit.cpp index dee8594144..38720e16fc 100644 --- a/stepmania/src/ScreenEdit.cpp +++ b/stepmania/src/ScreenEdit.cpp @@ -978,7 +978,7 @@ void ScreenEdit::UpdateTextInfo() m_bTextInfoNeedsUpdate = false; - RString sNoteType = NoteTypeToLocalizedString(m_SnapDisplay.GetNoteType()) + " notes"; + RString sNoteType = NoteTypeToLocalizedString(m_SnapDisplay.GetNoteType()); RString sText; sText += ssprintf( "%s:\n %.3f\n", CURRENT_BEAT.GetValue().c_str(), GAMESTATE->m_fSongBeat ); @@ -1379,7 +1379,7 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) // Get all Steps of this StepsType StepsType st = pSteps->m_StepsType; vector vSteps; - GAMESTATE->m_pCurSong->GetSteps( vSteps, st ); + SongUtil::GetSteps( GAMESTATE->m_pCurSong, vSteps, st ); // Sort them by difficulty. StepsUtil::SortStepsByTypeAndDifficulty( vSteps ); diff --git a/stepmania/src/ScreenEz2SelectMusic.cpp b/stepmania/src/ScreenEz2SelectMusic.cpp index 8a712e03a8..894aaf1fdd 100644 --- a/stepmania/src/ScreenEz2SelectMusic.cpp +++ b/stepmania/src/ScreenEz2SelectMusic.cpp @@ -14,6 +14,7 @@ #include "ActorUtil.h" #include "AnnouncerManager.h" #include "MenuTimer.h" +#include "SongUtil.h" #include "StepsUtil.h" #include "ScreenDimensions.h" #include "ScreenPrompt.h" @@ -640,7 +641,7 @@ void ScreenEz2SelectMusic::MusicChanged() for( pn = 0; pn < NUM_PLAYERS; ++pn) { - pSong->GetSteps( m_arrayNotes[pn], GAMESTATE->GetCurrentStyle()->m_StepsType ); + SongUtil::GetSteps( pSong, m_arrayNotes[pn], GAMESTATE->GetCurrentStyle()->m_StepsType ); StepsUtil::SortNotesArrayByDifficulty( m_arrayNotes[pn] ); } diff --git a/stepmania/src/ScreenGameplay.cpp b/stepmania/src/ScreenGameplay.cpp index e91db87f1c..4ded36113a 100644 --- a/stepmania/src/ScreenGameplay.cpp +++ b/stepmania/src/ScreenGameplay.cpp @@ -53,6 +53,7 @@ #include "Foreground.h" #include "ScreenSaveSync.h" #include "AdjustSync.h" +#include "SongUtil.h" // // Defines @@ -1295,7 +1296,7 @@ void ScreenGameplay::LoadLights() m_CabinetLightsNoteData.Init(); ASSERT( GAMESTATE->m_pCurSong ); - const Steps *pSteps = GAMESTATE->m_pCurSong->GetClosestNotes( STEPS_TYPE_LIGHTS_CABINET, DIFFICULTY_MEDIUM ); + const Steps *pSteps = SongUtil::GetClosestNotes( GAMESTATE->m_pCurSong, STEPS_TYPE_LIGHTS_CABINET, DIFFICULTY_MEDIUM ); if( pSteps != NULL ) { pSteps->GetNoteData( m_CabinetLightsNoteData ); @@ -1312,7 +1313,7 @@ void ScreenGameplay::LoadLights() Difficulty d1 = DIFFICULTY_INVALID; if( asDifficulties.size() > 0 ) d1 = StringToDifficulty( asDifficulties[0] ); - pSteps = GAMESTATE->m_pCurSong->GetClosestNotes( GAMESTATE->GetCurrentStyle()->m_StepsType, d1 ); + pSteps = SongUtil::GetClosestNotes( GAMESTATE->m_pCurSong, GAMESTATE->GetCurrentStyle()->m_StepsType, d1 ); // If we can't find anything at all, stop. if( pSteps == NULL ) @@ -1324,7 +1325,7 @@ void ScreenGameplay::LoadLights() if( asDifficulties.size() > 1 ) { Difficulty d2 = StringToDifficulty( asDifficulties[1] ); - const Steps *pSteps2 = GAMESTATE->m_pCurSong->GetClosestNotes( GAMESTATE->GetCurrentStyle()->m_StepsType, d2 ); + const Steps *pSteps2 = SongUtil::GetClosestNotes( GAMESTATE->m_pCurSong, GAMESTATE->GetCurrentStyle()->m_StepsType, d2 ); if( pSteps != NULL && pSteps2 != NULL && pSteps != pSteps2 ) { NoteData TapNoteData2; diff --git a/stepmania/src/ScreenGameplaySyncMachine.cpp b/stepmania/src/ScreenGameplaySyncMachine.cpp index af3a7c88a7..86ae1210f4 100644 --- a/stepmania/src/ScreenGameplaySyncMachine.cpp +++ b/stepmania/src/ScreenGameplaySyncMachine.cpp @@ -7,6 +7,7 @@ #include "AdjustSync.h" #include "ScreenDimensions.h" #include "InputEventPlus.h" +#include "SongUtil.h" REGISTER_SCREEN_CLASS( ScreenGameplaySyncMachine ); @@ -23,7 +24,7 @@ void ScreenGameplaySyncMachine::Init() m_Song.TidyUpData(); GAMESTATE->m_pCurSong.Set( &m_Song ); - Steps *pSteps = m_Song.GetOneSteps(); + Steps *pSteps = SongUtil::GetOneSteps( &m_Song ); ASSERT( pSteps ); GAMESTATE->m_pCurSteps[0].Set( pSteps ); diff --git a/stepmania/src/ScreenHowToPlay.cpp b/stepmania/src/ScreenHowToPlay.cpp index b4ea533b28..7bb0723453 100644 --- a/stepmania/src/ScreenHowToPlay.cpp +++ b/stepmania/src/ScreenHowToPlay.cpp @@ -19,6 +19,7 @@ #include "PrefsManager.h" #include "CharacterManager.h" #include "StatsManager.h" +#include "SongUtil.h" static const ThemeMetric STEPFILE ("ScreenHowToPlay","Stepfile"); static const ThemeMetric NUM_W2S ("ScreenHowToPlay","NumW2s"); @@ -142,7 +143,7 @@ void ScreenHowToPlay::Init() const Style* pStyle = GAMESTATE->GetCurrentStyle(); - Steps *pSteps = m_Song.GetStepsByDescription( pStyle->m_StepsType, "" ); + Steps *pSteps = SongUtil::GetStepsByDescription( &m_Song, pStyle->m_StepsType, "" ); ASSERT_M( pSteps != NULL, ssprintf("%i", pStyle->m_StepsType) ); NoteData tempNoteData; diff --git a/stepmania/src/ScreenJukebox.cpp b/stepmania/src/ScreenJukebox.cpp index 707c2f5564..d97d9d12fb 100644 --- a/stepmania/src/ScreenJukebox.cpp +++ b/stepmania/src/ScreenJukebox.cpp @@ -20,6 +20,7 @@ #include "PrefsManager.h" #include "InputEventPlus.h" #include "AdjustSync.h" +#include "SongUtil.h" #define SHOW_COURSE_MODIFIERS_PROBABILITY THEME->GetMetricF(m_sName,"ShowCourseModifiersProbability") @@ -85,7 +86,7 @@ void ScreenJukebox::SetSong() continue; // skip Difficulty dc = vDifficultiesToShow[ rand()%vDifficultiesToShow.size() ]; - Steps* pSteps = pSong->GetStepsByDifficulty( GAMESTATE->GetCurrentStyle()->m_StepsType, dc ); + Steps* pSteps = SongUtil::GetStepsByDifficulty( pSong, GAMESTATE->GetCurrentStyle()->m_StepsType, dc ); if( pSteps == NULL ) continue; // skip diff --git a/stepmania/src/ScreenOptionsEditCourseEntry.cpp b/stepmania/src/ScreenOptionsEditCourseEntry.cpp index 330bbf2934..0493fcd1d1 100644 --- a/stepmania/src/ScreenOptionsEditCourseEntry.cpp +++ b/stepmania/src/ScreenOptionsEditCourseEntry.cpp @@ -10,6 +10,7 @@ #include "Steps.h" #include "OptionRowHandler.h" #include "PlayerState.h" +#include "SongUtil.h" enum EditCourseEntryRow { @@ -208,7 +209,7 @@ void ScreenOptionsEditCourseEntry::BeginScreen() const CourseEntry &ce = pCourse->m_vEntries[ GAMESTATE->m_iEditCourseEntryIndex ]; m_Original = ce; - m_pSongHandler->m_sSongGroup = ce.sSongGroup; + m_pSongHandler->m_sSongGroup = ce.songCriteria.m_sGroupName; if( SHOW_MODS_ROW ) m_pModChangesHandler->m_Def.m_vsChoices[0] = ssprintf( "%d mod changes", ce.GetNumModChanges() ); @@ -241,8 +242,8 @@ void ScreenOptionsEditCourseEntry::HandleScreenMessage( const ScreenMessage SM ) Song *pSong = ce.pSong; Steps *pSteps; StepsType st = GAMESTATE->m_stEdit; - CourseDifficulty cd = ( ce.baseDifficulty == DIFFICULTY_INVALID ? - GAMESTATE->m_cdEdit : ce.baseDifficulty ); + CourseDifficulty cd = ( ce.stepsCriteria.m_difficulty == DIFFICULTY_INVALID ? + GAMESTATE->m_cdEdit : ce.stepsCriteria.m_difficulty ); if( pSong == NULL ) pSong = m_pLongSong; @@ -273,13 +274,13 @@ void ScreenOptionsEditCourseEntry::HandleScreenMessage( const ScreenMessage SM ) } // Try to find steps first using st and cd, then st, then cd, then any. - pSteps = pSong->GetStepsByDifficulty( st, cd, false ); + pSteps = SongUtil::GetStepsByDifficulty( pSong, st, cd, false ); if( !pSteps ) - pSteps = pSong->GetStepsByDifficulty( st, DIFFICULTY_INVALID, false ); + pSteps = SongUtil::GetStepsByDifficulty( pSong, st, DIFFICULTY_INVALID, false ); if( !pSteps ) - pSteps = pSong->GetStepsByDifficulty( STEPS_TYPE_INVALID, cd, false ); + pSteps = SongUtil::GetStepsByDifficulty( pSong, STEPS_TYPE_INVALID, cd, false ); if( !pSteps ) - pSteps = pSong->GetStepsByDifficulty( STEPS_TYPE_INVALID, DIFFICULTY_INVALID, false ); + pSteps = SongUtil::GetStepsByDifficulty( pSong, STEPS_TYPE_INVALID, DIFFICULTY_INVALID, false ); ASSERT( pSteps ); // Set up for ScreenEdit @@ -340,7 +341,7 @@ void ScreenOptionsEditCourseEntry::AfterChangeValueInRow( int iRow, PlayerNumber vpns.push_back( pn ); ExportOptions( ROW_SONG_GROUP, vpns ); - m_pSongHandler->m_sSongGroup = ce.sSongGroup; + m_pSongHandler->m_sSongGroup = ce.songCriteria.m_sGroupName; OptionRow &row = *m_pRows[ROW_SONG]; row.Reload(); @@ -371,7 +372,7 @@ void ScreenOptionsEditCourseEntry::ImportOptions( int iRow, const vector::const_iterator iter = find( CommonMetrics::DIFFICULTIES_TO_SHOW.GetValue().begin(), CommonMetrics::DIFFICULTIES_TO_SHOW.GetValue().end(), ce.baseDifficulty ); + vector::const_iterator iter = find( CommonMetrics::DIFFICULTIES_TO_SHOW.GetValue().begin(), CommonMetrics::DIFFICULTIES_TO_SHOW.GetValue().end(), ce.stepsCriteria.m_difficulty ); int iChoice = 0; if( iter != CommonMetrics::DIFFICULTIES_TO_SHOW.GetValue().end() ) iChoice = iter - CommonMetrics::DIFFICULTIES_TO_SHOW.GetValue().begin() + 1; @@ -404,8 +405,8 @@ void ScreenOptionsEditCourseEntry::ImportOptions( int iRow, const vectorGetStepsByDifficulty( m_StepsType, *iter, false ); + const Steps* pSteps = SongUtil::GetStepsByDifficulty( pSong, m_StepsType, *iter, false ); if( pSteps && UNLOCKMAN->StepsIsLocked(pSong, pSteps) ) pSteps = NULL; BitmapText* pTextStepsScore = &item.m_textScore[*iter]; diff --git a/stepmania/src/ScreenSelectMusic.cpp b/stepmania/src/ScreenSelectMusic.cpp index dc828225ac..582a4cf5a0 100644 --- a/stepmania/src/ScreenSelectMusic.cpp +++ b/stepmania/src/ScreenSelectMusic.cpp @@ -1521,7 +1521,7 @@ void ScreenSelectMusic::AfterMusicChange() m_textNumSongs.SetText( ssprintf("%d", SongManager::GetNumStagesForSong(pSong) ) ); m_textTotalTime.SetText( SecondsToMMSSMsMs(pSong->m_fMusicLengthSeconds) ); - pSong->GetSteps( m_vpSteps, GAMESTATE->GetCurrentStyle()->m_StepsType ); + SongUtil::GetSteps( pSong, m_vpSteps, GAMESTATE->GetCurrentStyle()->m_StepsType ); StepsUtil::RemoveLockedSteps( pSong, m_vpSteps ); StepsUtil::SortNotesArrayByDifficulty( m_vpSteps ); diff --git a/stepmania/src/Song.cpp b/stepmania/src/Song.cpp index aa66641179..0b544e6e97 100644 --- a/stepmania/src/Song.cpp +++ b/stepmania/src/Song.cpp @@ -19,9 +19,9 @@ #include "RageFileManager.h" #include "RageSurface.h" #include "NoteDataUtil.h" +#include "SongUtil.h" #include "StepsUtil.h" #include "Foreach.h" -#include "UnlockManager.h" #include "BackgroundUtil.h" #include "SpecialFiles.h" @@ -319,114 +319,6 @@ static void GetImageDirListing( RString sPath, vector &AddTo, bool bRet GetDirListing( sPath + ".gif", AddTo, false, bReturnPathToo ); } -static RString RemoveInitialWhitespace( RString s ) -{ - size_t i = s.find_first_not_of(" \t\r\n"); - if( i != s.npos ) - s.erase( 0, i ); - return s; -} - -/* This is called within TidyUpData, before autogen notes are added. */ -void Song::DeleteDuplicateSteps( vector &vSteps ) -{ - /* vSteps have the same StepsType and Difficulty. Delete them if they have the - * same m_sDescription, m_iMeter and SMNoteData. */ - CHECKPOINT; - for( unsigned i=0; iGetDescription() != s2->GetDescription() ) - continue; - if( s1->GetMeter() != s2->GetMeter() ) - continue; - /* Compare, ignoring whitespace. */ - RString sSMNoteData1; - s1->GetSMNoteData( sSMNoteData1 ); - RString sSMNoteData2; - s2->GetSMNoteData( sSMNoteData2 ); - if( RemoveInitialWhitespace(sSMNoteData1) != RemoveInitialWhitespace(sSMNoteData2) ) - continue; - - LOG->Trace("Removed %p duplicate steps in song \"%s\" with description \"%s\" and meter \"%i\"", - s2, this->GetSongDir().c_str(), s1->GetDescription().c_str(), s1->GetMeter() ); - - /* Don't use RemoveSteps; autogen notes havn't yet been created and it'll - * create them. */ - FOREACH_StepsType( st ) - { - for( int k=this->m_vpStepsByType[st].size()-1; k>=0; k-- ) - { - if( this->m_vpStepsByType[st][k] == s2 ) - { - // delete this->m_vpStepsByType[k]; // delete below - this->m_vpStepsByType[st].erase( this->m_vpStepsByType[st].begin()+k ); - break; - } - } - } - - for( int k=this->m_vpSteps.size()-1; k>=0; k-- ) - { - if( this->m_vpSteps[k] == s2 ) - { - delete this->m_vpSteps[k]; - this->m_vpSteps.erase( this->m_vpSteps.begin()+k ); - break; - } - } - - vSteps.erase(vSteps.begin()+j); - --j; - } - } -} - -/* Make any duplicate difficulties edits. (Note that BMS files do a first pass - * on this; see BMSLoader::SlideDuplicateDifficulties.) */ -void Song::AdjustDuplicateSteps() -{ - FOREACH_StepsType( st ) - { - FOREACH_Difficulty( dc ) - { - if( dc == DIFFICULTY_EDIT ) - continue; - - vector vSteps; - this->GetSteps( vSteps, st, dc ); - - /* Delete steps that are completely identical. This happened due to a - * bug in an earlier version. */ - DeleteDuplicateSteps( vSteps ); - - CHECKPOINT; - StepsUtil::SortNotesArrayByDifficulty( vSteps ); - CHECKPOINT; - for( unsigned k=1; kSetDifficulty( DIFFICULTY_EDIT ); - if( vSteps[k]->GetDescription() == "" ) - { - /* "Hard Edit" */ - RString EditName = Capitalize( DifficultyToString(dc) ) + " Edit"; - vSteps[k]->SetDescription( EditName ); - } - } - } - - /* XXX: Don't allow edits to have descriptions that look like regular difficulties. - * These are confusing, and they're ambiguous when passed to GetStepsByID. */ - } -} - /* Fix up song paths. If there's a leading "./", be sure to keep it: it's * a signal that the path is from the root directory, not the song directory. * Other than a leading "./", song paths must never contain "." or "..". */ @@ -738,7 +630,7 @@ void Song::TidyUpData() /* Don't allow multiple Steps of the same StepsType and Difficulty (except for edits). * We should be able to use difficulty names as unique identifiers for steps. */ - AdjustDuplicateSteps(); + SongUtil::AdjustDuplicateSteps( this ); { /* Generated filename; this doesn't always point to a loadable file, @@ -835,142 +727,6 @@ void Song::ReCalculateRadarValuesAndLastBeat() m_fLastBeat = fLastBeat; } -void Song::GetSteps( - vector& arrayAddTo, - StepsType st, - Difficulty dc, - int iMeterLow, - int iMeterHigh, - const RString &sDescription, - bool bIncludeAutoGen, - unsigned uHash, - int iMaxToGet - ) const -{ - if( !iMaxToGet ) - return; - - const vector &vpSteps = st == STEPS_TYPE_INVALID ? GetAllSteps() : GetStepsByStepsType(st); - for( unsigned i=0; iGetDifficulty() ) - continue; - if( iMeterLow != -1 && iMeterLow > pSteps->GetMeter() ) - continue; - if( iMeterHigh != -1 && iMeterHigh < pSteps->GetMeter() ) - continue; - if( sDescription.size() && sDescription != pSteps->GetDescription() ) - continue; - if( uHash != 0 && uHash != pSteps->GetHash() ) - continue; - if( !bIncludeAutoGen && pSteps->IsAutogen() ) - continue; - - arrayAddTo.push_back( pSteps ); - - if( iMaxToGet != -1 ) - { - --iMaxToGet; - if( !iMaxToGet ) - break; - } - } -} - -Steps* Song::GetOneSteps( - StepsType st, - Difficulty dc, - int iMeterLow, - int iMeterHigh, - const RString &sDescription, - unsigned uHash, - bool bIncludeAutoGen - ) const -{ - vector vpSteps; - GetSteps( vpSteps, st, dc, iMeterLow, iMeterHigh, sDescription, bIncludeAutoGen, uHash, 1 ); // get max 1 - if( vpSteps.empty() ) - return NULL; - else - return vpSteps[0]; -} - -Steps* Song::GetStepsByDifficulty( StepsType st, Difficulty dc, bool bIncludeAutoGen ) const -{ - const vector& vpSteps = (st == STEPS_TYPE_INVALID)? GetAllSteps():GetStepsByStepsType(st); - for( unsigned i=0; iGetDifficulty() ) - continue; - if( !bIncludeAutoGen && pSteps->IsAutogen() ) - continue; - - return pSteps; - } - - return NULL; -} - -Steps* Song::GetStepsByMeter( StepsType st, int iMeterLow, int iMeterHigh ) const -{ - const vector& vpSteps = (st == STEPS_TYPE_INVALID)? GetAllSteps():GetStepsByStepsType(st); - for( unsigned i=0; i pSteps->GetMeter() ) - continue; - if( iMeterHigh < pSteps->GetMeter() ) - continue; - - return pSteps; - } - - return NULL; -} - -Steps* Song::GetStepsByDescription( StepsType st, RString sDescription ) const -{ - vector vNotes; - GetSteps( vNotes, st, DIFFICULTY_INVALID, -1, -1, sDescription ); - if( vNotes.size() == 0 ) - return NULL; - else - return vNotes[0]; -} - - -Steps* Song::GetClosestNotes( StepsType st, Difficulty dc, bool bIgnoreLocked ) const -{ - ASSERT( dc != DIFFICULTY_INVALID ); - - const vector& vpSteps = (st == STEPS_TYPE_INVALID)? GetAllSteps():GetStepsByStepsType(st); - Steps *pClosest = NULL; - int iClosestDistance = 999; - for( unsigned i=0; iGetDifficulty() == DIFFICULTY_EDIT && dc != DIFFICULTY_EDIT ) - continue; - if( bIgnoreLocked && UNLOCKMAN->StepsIsLocked(this, pSteps) ) - continue; - - int iDistance = abs(dc - pSteps->GetDifficulty()); - if( iDistance < iClosestDistance ) - { - pClosest = pSteps; - iClosestDistance = iDistance; - } - } - - return pClosest; -} - /* Return whether the song is playable in the given style. */ bool Song::SongCompleteForStyle( const Style *st ) const { @@ -979,12 +735,12 @@ bool Song::SongCompleteForStyle( const Style *st ) const bool Song::HasStepsType( StepsType st ) const { - return GetOneSteps( st ) != NULL; + return SongUtil::GetOneSteps( this, st ) != NULL; } bool Song::HasStepsTypeAndDifficulty( StepsType st, Difficulty dc ) const { - return GetOneSteps( st, dc ) != NULL; + return SongUtil::GetOneSteps( this, st, dc ) != NULL; } void Song::Save() @@ -1156,11 +912,11 @@ bool Song::IsEasy( StepsType st ) const /* The easy marker indicates which songs a beginner, having selected "beginner", * can play and actually get a very easy song: if there are actual beginner * steps, or if the light steps are 1- or 2-foot. */ - const Steps* pBeginnerNotes = GetStepsByDifficulty( st, DIFFICULTY_BEGINNER ); + const Steps* pBeginnerNotes = SongUtil::GetStepsByDifficulty( this, st, DIFFICULTY_BEGINNER ); if( pBeginnerNotes ) return true; - const Steps* pEasyNotes = GetStepsByDifficulty( st, DIFFICULTY_EASY ); + const Steps* pEasyNotes = SongUtil::GetStepsByDifficulty( this, st, DIFFICULTY_EASY ); if( pEasyNotes && pEasyNotes->GetMeter() == 1 ) return true; @@ -1349,12 +1105,13 @@ void Song::AddSteps( Steps* pSteps ) m_vpStepsByType[pSteps->m_StepsType].push_back( pSteps ); } -void Song::DeleteSteps( const Steps* pSteps ) +void Song::DeleteSteps( const Steps* pSteps, bool bReAutoGen ) { // Avoid any stale Note::parent pointers by removing all AutoGen'd Steps, // then adding them again. - RemoveAutoGenNotes(); + if( bReAutoGen ) + RemoveAutoGenNotes(); vector &vpSteps = m_vpStepsByType[pSteps->m_StepsType]; @@ -1378,7 +1135,8 @@ void Song::DeleteSteps( const Steps* pSteps ) } } - AddAutoGenNotes(); + if( bReAutoGen ) + AddAutoGenNotes(); } bool Song::Matches(RString sGroup, RString sSong) const @@ -1404,7 +1162,7 @@ bool Song::Matches(RString sGroup, RString sSong) const void Song::FreeAllLoadedFromProfile( ProfileSlot slot ) { - /* RemoveSteps will remove and recreate autogen notes, which may reorder + /* DeleteSteps will remove and recreate autogen notes, which may reorder * m_vpSteps, so be careful not to skip over entries. */ vector apToRemove; for( int s=m_vpSteps.size()-1; s>=0; s-- ) diff --git a/stepmania/src/SongManager.cpp b/stepmania/src/SongManager.cpp index 8c9026ba51..39d2f7d5b8 100644 --- a/stepmania/src/SongManager.cpp +++ b/stepmania/src/SongManager.cpp @@ -1033,7 +1033,7 @@ Song *SongManager::GetSongFromSteps( Steps *pSteps ) FOREACH_CONST( Song*, vSongs, song ) { vector vSteps; - (*song)->GetSteps( vSteps ); + SongUtil::GetSteps( *song, vSteps ); FOREACH_CONST( Steps*, vSteps, steps ) { @@ -1171,7 +1171,7 @@ void SongManager::GetExtraStageInfo( bool bExtra2, const Style *sd, Song*& pSong Song* pSong = apSongs[s]; vector apSteps; - pSong->GetSteps( apSteps, sd->m_StepsType ); + SongUtil::GetSteps( pSong, apSteps, sd->m_StepsType ); for( unsigned n=0; n apSteps; - pSong->GetSteps( apSteps ); + SongUtil::GetSteps( pSong, apSteps ); for( unsigned i = 0; i < apSteps.size(); ++i ) { diff --git a/stepmania/src/SongUtil.cpp b/stepmania/src/SongUtil.cpp index c9c5b3f294..d8fdf72366 100644 --- a/stepmania/src/SongUtil.cpp +++ b/stepmania/src/SongUtil.cpp @@ -13,14 +13,249 @@ #include "UnlockManager.h" #include "ThemeMetric.h" #include "LocalizedString.h" +#include "RageLog.h" + +bool SongCriteria::Matches( const Song *p ) const +{ + if( !m_sGroupName.empty() && m_sGroupName != p->m_sGroupName ) + return false; + if( !m_sGenre.empty() && m_sGenre != p->m_sGenre ) + return false; + return true; +} + +void SongUtil::GetSteps( + const Song *pSong, + vector& arrayAddTo, + StepsType st, + Difficulty dc, + int iMeterLow, + int iMeterHigh, + const RString &sDescription, + bool bIncludeAutoGen, + unsigned uHash, + int iMaxToGet + ) +{ + if( !iMaxToGet ) + return; + + const vector &vpSteps = st == STEPS_TYPE_INVALID ? pSong->GetAllSteps() : pSong->GetStepsByStepsType(st); + for( unsigned i=0; iGetDifficulty() ) + continue; + if( iMeterLow != -1 && iMeterLow > pSteps->GetMeter() ) + continue; + if( iMeterHigh != -1 && iMeterHigh < pSteps->GetMeter() ) + continue; + if( sDescription.size() && sDescription != pSteps->GetDescription() ) + continue; + if( uHash != 0 && uHash != pSteps->GetHash() ) + continue; + if( !bIncludeAutoGen && pSteps->IsAutogen() ) + continue; + + arrayAddTo.push_back( pSteps ); + + if( iMaxToGet != -1 ) + { + --iMaxToGet; + if( !iMaxToGet ) + break; + } + } +} + +Steps* SongUtil::GetOneSteps( + const Song *pSong, + StepsType st, + Difficulty dc, + int iMeterLow, + int iMeterHigh, + const RString &sDescription, + unsigned uHash, + bool bIncludeAutoGen + ) +{ + vector vpSteps; + GetSteps( pSong, vpSteps, st, dc, iMeterLow, iMeterHigh, sDescription, bIncludeAutoGen, uHash, 1 ); // get max 1 + if( vpSteps.empty() ) + return NULL; + else + return vpSteps[0]; +} + +Steps* SongUtil::GetStepsByDifficulty( const Song *pSong, StepsType st, Difficulty dc, bool bIncludeAutoGen ) +{ + const vector& vpSteps = (st == STEPS_TYPE_INVALID)? pSong->GetAllSteps() : pSong->GetStepsByStepsType(st); + for( unsigned i=0; iGetDifficulty() ) + continue; + if( !bIncludeAutoGen && pSteps->IsAutogen() ) + continue; + + return pSteps; + } + + return NULL; +} + +Steps* SongUtil::GetStepsByMeter( const Song *pSong, StepsType st, int iMeterLow, int iMeterHigh ) +{ + const vector& vpSteps = (st == STEPS_TYPE_INVALID)? pSong->GetAllSteps() : pSong->GetStepsByStepsType(st); + for( unsigned i=0; i pSteps->GetMeter() ) + continue; + if( iMeterHigh < pSteps->GetMeter() ) + continue; + + return pSteps; + } + + return NULL; +} + +Steps* SongUtil::GetStepsByDescription( const Song *pSong, StepsType st, RString sDescription ) +{ + vector vNotes; + GetSteps( pSong, vNotes, st, DIFFICULTY_INVALID, -1, -1, sDescription ); + if( vNotes.size() == 0 ) + return NULL; + else + return vNotes[0]; +} + + +Steps* SongUtil::GetClosestNotes( const Song *pSong, StepsType st, Difficulty dc, bool bIgnoreLocked ) +{ + ASSERT( dc != DIFFICULTY_INVALID ); + + const vector& vpSteps = (st == STEPS_TYPE_INVALID)? pSong->GetAllSteps() : pSong->GetStepsByStepsType(st); + Steps *pClosest = NULL; + int iClosestDistance = 999; + for( unsigned i=0; iGetDifficulty() == DIFFICULTY_EDIT && dc != DIFFICULTY_EDIT ) + continue; + if( bIgnoreLocked && UNLOCKMAN->StepsIsLocked(pSong,pSteps) ) + continue; + + int iDistance = abs(dc - pSteps->GetDifficulty()); + if( iDistance < iClosestDistance ) + { + pClosest = pSteps; + iClosestDistance = iDistance; + } + } + + return pClosest; +} + + +/* Make any duplicate difficulties edits. (Note that BMS files do a first pass + * on this; see BMSLoader::SlideDuplicateDifficulties.) */ +void SongUtil::AdjustDuplicateSteps( Song *pSong ) +{ + FOREACH_StepsType( st ) + { + FOREACH_Difficulty( dc ) + { + if( dc == DIFFICULTY_EDIT ) + continue; + + vector vSteps; + SongUtil::GetSteps( pSong, vSteps, st, dc ); + + /* Delete steps that are completely identical. This happened due to a + * bug in an earlier version. */ + DeleteDuplicateSteps( pSong, vSteps ); + + CHECKPOINT; + StepsUtil::SortNotesArrayByDifficulty( vSteps ); + CHECKPOINT; + for( unsigned k=1; kSetDifficulty( DIFFICULTY_EDIT ); + if( vSteps[k]->GetDescription() == "" ) + { + /* "Hard Edit" */ + RString EditName = Capitalize( DifficultyToString(dc) ) + " Edit"; + vSteps[k]->SetDescription( EditName ); + } + } + } + + /* XXX: Don't allow edits to have descriptions that look like regular difficulties. + * These are confusing, and they're ambiguous when passed to GetStepsByID. */ + } +} + +static RString RemoveInitialWhitespace( RString s ) +{ + size_t i = s.find_first_not_of(" \t\r\n"); + if( i != s.npos ) + s.erase( 0, i ); + return s; +} + +/* This is called within TidyUpData, before autogen notes are added. */ +void SongUtil::DeleteDuplicateSteps( Song *pSong, vector &vSteps ) +{ + /* vSteps have the same StepsType and Difficulty. Delete them if they have the + * same m_sDescription, m_iMeter and SMNoteData. */ + CHECKPOINT; + for( unsigned i=0; iGetDescription() != s2->GetDescription() ) + continue; + if( s1->GetMeter() != s2->GetMeter() ) + continue; + /* Compare, ignoring whitespace. */ + RString sSMNoteData1; + s1->GetSMNoteData( sSMNoteData1 ); + RString sSMNoteData2; + s2->GetSMNoteData( sSMNoteData2 ); + if( RemoveInitialWhitespace(sSMNoteData1) != RemoveInitialWhitespace(sSMNoteData2) ) + continue; + + LOG->Trace("Removed %p duplicate steps in song \"%s\" with description \"%s\" and meter \"%i\"", + s2, pSong->GetSongDir().c_str(), s1->GetDescription().c_str(), s1->GetMeter() ); + + pSong->DeleteSteps( s2, false ); + + vSteps.erase(vSteps.begin()+j); + --j; + } + } +} -static LocalizedString SORT_NOT_AVAILABLE( "Sort", "NotAvailable" ); -static LocalizedString SORT_OTHER ( "Sort", "Other" ); ///////////////////////////////////// // Sorting ///////////////////////////////////// +static LocalizedString SORT_NOT_AVAILABLE( "Sort", "NotAvailable" ); +static LocalizedString SORT_OTHER ( "Sort", "Other" ); + /* Just calculating GetNumTimesPlayed within the sort is pretty slow, so let's precompute * it. (This could be generalized with a template.) */ static map g_mapSongSortVal; @@ -280,28 +515,28 @@ RString SongUtil::GetSectionNameFromSongAndSort( const Song* pSong, SortOrder so } case SORT_EASY_METER: { - Steps* pSteps = pSong->GetStepsByDifficulty(GAMESTATE->GetCurrentStyle()->m_StepsType,DIFFICULTY_EASY); + Steps* pSteps = GetStepsByDifficulty(pSong, GAMESTATE->GetCurrentStyle()->m_StepsType,DIFFICULTY_EASY); if( pSteps && !UNLOCKMAN->StepsIsLocked(pSong,pSteps) ) return ssprintf("%02d", pSteps->GetMeter() ); return SORT_NOT_AVAILABLE.GetValue(); } case SORT_MEDIUM_METER: { - Steps* pSteps = pSong->GetStepsByDifficulty(GAMESTATE->GetCurrentStyle()->m_StepsType,DIFFICULTY_MEDIUM); + Steps* pSteps = GetStepsByDifficulty(pSong, GAMESTATE->GetCurrentStyle()->m_StepsType,DIFFICULTY_MEDIUM); if( pSteps && !UNLOCKMAN->StepsIsLocked(pSong,pSteps) ) return ssprintf("%02d", pSteps->GetMeter() ); return SORT_NOT_AVAILABLE.GetValue(); } case SORT_HARD_METER: { - Steps* pSteps = pSong->GetStepsByDifficulty(GAMESTATE->GetCurrentStyle()->m_StepsType,DIFFICULTY_HARD); + Steps* pSteps = GetStepsByDifficulty(pSong, GAMESTATE->GetCurrentStyle()->m_StepsType,DIFFICULTY_HARD); if( pSteps && !UNLOCKMAN->StepsIsLocked(pSong,pSteps) ) return ssprintf("%02d", pSteps->GetMeter() ); return SORT_NOT_AVAILABLE.GetValue(); } case SORT_CHALLENGE_METER: { - Steps* pSteps = pSong->GetStepsByDifficulty(GAMESTATE->GetCurrentStyle()->m_StepsType,DIFFICULTY_CHALLENGE); + Steps* pSteps = GetStepsByDifficulty(pSong, GAMESTATE->GetCurrentStyle()->m_StepsType,DIFFICULTY_CHALLENGE); if( pSteps && !UNLOCKMAN->StepsIsLocked(pSong,pSteps) ) return ssprintf("%02d", pSteps->GetMeter() ); return SORT_NOT_AVAILABLE.GetValue(); @@ -343,7 +578,7 @@ void SongUtil::SortSongPointerArrayByMeter( vector &vpSongsInOut, Difficu for(unsigned i = 0; i < vpSongsInOut.size(); ++i) { /* Ignore locked steps. */ - const Steps* pSteps = vpSongsInOut[i]->GetClosestNotes( GAMESTATE->GetCurrentStyle()->m_StepsType, dc, true ); + const Steps* pSteps = GetClosestNotes( vpSongsInOut[i], GAMESTATE->GetCurrentStyle()->m_StepsType, dc, true ); RString &s = g_mapSongSortVal[vpSongsInOut[i]]; s = ssprintf("%03d", pSteps ? pSteps->GetMeter() : 0); @@ -448,7 +683,7 @@ bool SongUtil::ValidateCurrentEditStepsDescription( const RString &sAnswer, RStr // Steps name must be unique for this song. vector v; - pSong->GetSteps( v, STEPS_TYPE_INVALID, DIFFICULTY_EDIT ); + GetSteps( pSong, v, STEPS_TYPE_INVALID, DIFFICULTY_EDIT ); FOREACH_CONST( Steps*, v, s ) { if( pSteps == *s ) @@ -486,6 +721,20 @@ bool SongUtil::ValidateCurrentStepsDescription( const RString &sAnswer, RString return true; } +void SongUtil::GetAllSongGenres( vector &vsOut ) +{ + set genres; + FOREACH_CONST( Song*, SONGMAN->GetAllSongs(), song ) + { + if( !(*song)->m_sGenre.empty() ) + genres.insert( (*song)->m_sGenre ); + } + + FOREACHS_CONST( RString, genres, s ) + { + vsOut.push_back( *s ); + } +} ////////////////////////////////// diff --git a/stepmania/src/SongUtil.h b/stepmania/src/SongUtil.h index 44daa02c38..2b3bfaeab9 100644 --- a/stepmania/src/SongUtil.h +++ b/stepmania/src/SongUtil.h @@ -11,8 +11,52 @@ class Steps; class Profile; class XNode; + +class SongCriteria +{ +public: + RString m_sGroupName; // "" means don't match + RString m_sGenre; // "" means don't match + + SongCriteria() + { + + } + bool Matches( const Song *p ) const; +}; + namespace SongUtil { + void GetSteps( + const Song *pSong, + vector& arrayAddTo, + StepsType st = STEPS_TYPE_INVALID, + Difficulty dc = DIFFICULTY_INVALID, + int iMeterLow = -1, + int iMeterHigh = -1, + const RString &sDescription = "", + bool bIncludeAutoGen = true, + unsigned uHash = 0, + int iMaxToGet = -1 + ); + Steps* GetOneSteps( + const Song *pSong, + StepsType st = STEPS_TYPE_INVALID, + Difficulty dc = DIFFICULTY_INVALID, + int iMeterLow = -1, + int iMeterHigh = -1, + const RString &sDescription = "", + unsigned uHash = 0, + bool bIncludeAutoGen = true + ); + Steps* GetStepsByDifficulty( const Song *pSong, StepsType st, Difficulty dc, bool bIncludeAutoGen = true ); + Steps* GetStepsByMeter( const Song *pSong, StepsType st, int iMeterLow, int iMeterHigh ); + Steps* GetStepsByDescription( const Song *pSong, StepsType st, RString sDescription ); + Steps* GetClosestNotes( const Song *pSong, StepsType st, Difficulty dc, bool bIgnoreLocked=false ); + + void AdjustDuplicateSteps( Song *pSong ); // part of TidyUpData + void DeleteDuplicateSteps( Song *pSong, vector &vSteps ); + RString MakeSortString( RString s ); void SortSongPointerArrayByTitle( vector &vpSongsInOut ); void SortSongPointerArrayByBPM( vector &vpSongsInOut ); @@ -24,7 +68,7 @@ namespace SongUtil void SortSongPointerArrayByNumPlays( vector &vpSongsInOut, ProfileSlot slot, bool bDescending ); void SortSongPointerArrayByNumPlays( vector &vpSongsInOut, const Profile* pProfile, bool bDescending ); void SortSongPointerArrayByMeter( vector &vpSongsInOut, Difficulty dc ); - RString GetSectionNameFromSongAndSort( const Song* pSong, SortOrder so ); + RString GetSectionNameFromSongAndSort( const Song *pSong, SortOrder so ); void SortSongPointerArrayBySectionName( vector &vpSongsInOut, SortOrder so ); void SortByMostRecentlyPlayedForMachine( vector &vpSongsInOut ); @@ -34,6 +78,9 @@ namespace SongUtil RString MakeUniqueEditDescription( const Song* pSong, StepsType st, const RString &sPreferredDescription ); bool ValidateCurrentEditStepsDescription( const RString &sAnswer, RString &sErrorOut ); bool ValidateCurrentStepsDescription( const RString &sAnswer, RString &sErrorOut ); + + void GetAllSongGenres( vector &vsOut ); + void FilterSongs( const SongCriteria &sc, const vector &in, vector &out ); } class SongID diff --git a/stepmania/src/StepsUtil.cpp b/stepmania/src/StepsUtil.cpp index 7da5fd86c5..caf327509e 100644 --- a/stepmania/src/StepsUtil.cpp +++ b/stepmania/src/StepsUtil.cpp @@ -8,18 +8,47 @@ #include "GameManager.h" #include "XmlFile.h" #include "UnlockManager.h" +#include "SongUtil.h" + + +bool StepsCriteria::Matches( const Steps *p ) const +{ + if( m_difficulty != DIFFICULTY_INVALID && p->GetDifficulty() != m_difficulty ) + return false; + if( m_iLowMeter != -1 && p->GetMeter() < m_iLowMeter ) + return false; + if( m_iHighMeter != -1 && p->GetMeter() > m_iHighMeter ) + return false; + return true; +} + +void StepsUtil::GetAllMatching( const SongCriteria &soc, const StepsCriteria &stc, vector &out ) +{ + FOREACH_CONST( Song*, SONGMAN->GetAllSongs(), so ) + { + if( !soc.Matches(*so) ) + continue; + FOREACH_CONST( Steps*, (*so)->GetAllSteps(), st ) + { + if( !stc.Matches(*st) ) + continue; + + } + } +} + // // Sorting stuff // map steps_sort_val; -bool CompareStepsPointersBySortValueAscending(const Steps *pSteps1, const Steps *pSteps2) +static bool CompareStepsPointersBySortValueAscending(const Steps *pSteps1, const Steps *pSteps2) { return steps_sort_val[pSteps1] < steps_sort_val[pSteps2]; } -bool CompareStepsPointersBySortValueDescending(const Steps *pSteps1, const Steps *pSteps2) +static bool CompareStepsPointersBySortValueDescending(const Steps *pSteps1, const Steps *pSteps2) { return steps_sort_val[pSteps1] > steps_sort_val[pSteps2]; } @@ -191,11 +220,11 @@ Steps *StepsID::ToSteps( const Song *p, bool bAllowNull, bool bUseCache ) const Steps *ret = NULL; if( dc == DIFFICULTY_EDIT ) { - ret = p->GetOneSteps( st, dc, -1, -1, sDescription, uHash, true ); + ret = SongUtil::GetOneSteps( p, st, dc, -1, -1, sDescription, uHash, true ); } else { - ret = p->GetOneSteps( st, dc, -1, -1, "", 0, true ); + ret = SongUtil::GetOneSteps( p, st, dc, -1, -1, "", 0, true ); } if( !bAllowNull && ret == NULL ) diff --git a/stepmania/src/StepsUtil.h b/stepmania/src/StepsUtil.h index 97c4c44ce9..1692693cad 100644 --- a/stepmania/src/StepsUtil.h +++ b/stepmania/src/StepsUtil.h @@ -8,9 +8,39 @@ class Steps; class Song; class Profile; class XNode; +class SongCriteria; + +class StepsCriteria +{ +public: + Difficulty m_difficulty; // don't filter if DIFFICULTY_INVALID + int m_iLowMeter; // don't filter if -1 + int m_iHighMeter; // don't filter if -1 + + StepsCriteria() + { + m_difficulty = DIFFICULTY_INVALID; + m_iLowMeter = -1; + m_iHighMeter = -1; + } + + bool Matches( const Steps *p ) const; +}; + +class SongAndSteps +{ +public: + Song* pSong; + Steps* pSteps; + bool operator==( const SongAndSteps& other ) const { return pSong==other.pSong && pSteps==other.pSteps; } + bool operator<( const SongAndSteps& other ) const { return pSong<=other.pSong && pSteps<=other.pSteps; } +}; namespace StepsUtil { + + void GetAllMatching( const SongCriteria &soc, const StepsCriteria &stc, vector &out ); // look up in SONGMAN + bool CompareNotesPointersByRadarValues(const Steps* pSteps1, const Steps* pSteps2); bool CompareNotesPointersByMeter(const Steps *pSteps1, const Steps* pSteps2); bool CompareNotesPointersByDifficulty(const Steps *pSteps1, const Steps *pSteps2); diff --git a/stepmania/src/UnlockManager.cpp b/stepmania/src/UnlockManager.cpp index bbbb8ce378..8d372d0521 100644 --- a/stepmania/src/UnlockManager.cpp +++ b/stepmania/src/UnlockManager.cpp @@ -307,7 +307,8 @@ UnlockEntryStatus UnlockEntry::GetUnlockEntryStatus() const if( m_bRequirePassHardSteps && m_pSong ) { vector vp; - m_pSong->GetSteps( + SongUtil::GetSteps( + m_pSong, vp, STEPS_TYPE_INVALID, DIFFICULTY_HARD @@ -454,11 +455,11 @@ void UnlockManager::Load() FOREACH_CONST( Song*, SONGMAN->GetAllSongs(), s ) { // If no hard steps to play to unlock, skip - if( (*s)->GetOneSteps(STEPS_TYPE_INVALID, DIFFICULTY_HARD) == NULL ) + if( SongUtil::GetOneSteps(*s, STEPS_TYPE_INVALID, DIFFICULTY_HARD) == NULL ) continue; // If no challenge steps to unlock, skip - if( (*s)->GetOneSteps(STEPS_TYPE_INVALID, DIFFICULTY_CHALLENGE) == NULL ) + if( SongUtil::GetOneSteps(*s, STEPS_TYPE_INVALID, DIFFICULTY_CHALLENGE) == NULL ) continue; if( SONGMAN->WasLoadedFromAdditionalSongs(*s) ) diff --git a/stepmania/src/song.h b/stepmania/src/song.h index 1b7825b785..cbd06ec908 100644 --- a/stepmania/src/song.h +++ b/stepmania/src/song.h @@ -186,30 +186,6 @@ public: bool HasStepsTypeAndDifficulty( StepsType st, Difficulty dc ) const; const vector& GetAllSteps() const { return m_vpSteps; } const vector& GetStepsByStepsType( StepsType st ) const { return m_vpStepsByType[st]; } - void GetSteps( - vector& arrayAddTo, - StepsType st = STEPS_TYPE_INVALID, - Difficulty dc = DIFFICULTY_INVALID, - int iMeterLow = -1, - int iMeterHigh = -1, - const RString &sDescription = "", - bool bIncludeAutoGen = true, - unsigned uHash = 0, - int iMaxToGet = -1 - ) const; - Steps* GetOneSteps( - StepsType st = STEPS_TYPE_INVALID, - Difficulty dc = DIFFICULTY_INVALID, - int iMeterLow = -1, - int iMeterHigh = -1, - const RString &sDescription = "", - unsigned uHash = 0, - bool bIncludeAutoGen = true - ) const; - Steps* GetStepsByDifficulty( StepsType st, Difficulty dc, bool bIncludeAutoGen = true ) const; - Steps* GetStepsByMeter( StepsType st, int iMeterLow, int iMeterHigh ) const; - Steps* GetStepsByDescription( StepsType st, RString sDescription ) const; - Steps* GetClosestNotes( StepsType st, Difficulty dc, bool bIgnoreLocked=false ) const; bool IsEasy( StepsType st ) const; bool IsTutorial() const; bool HasEdits( StepsType st ) const; @@ -220,7 +196,7 @@ public: bool ShowInDemonstrationAndRanking() const; void AddSteps( Steps* pSteps ); // we are responsible for deleting the memory pointed to by pSteps! - void DeleteSteps( const Steps* pSteps ); + void DeleteSteps( const Steps* pSteps, bool bReAutoGen = true ); void FreeAllLoadedFromProfile( ProfileSlot slot = ProfileSlot_INVALID ); bool WasLoadedFromProfile() const { return m_LoadedFromProfile != ProfileSlot_INVALID; } @@ -239,8 +215,6 @@ public: void PushSelf( lua_State *L ); private: - void AdjustDuplicateSteps(); // part of TidyUpData - void DeleteDuplicateSteps( vector &vSteps ); vector m_vpSteps; vector m_vpStepsByType[NUM_STEPS_TYPES];