diff --git a/stepmania/src/CommonMetrics.cpp b/stepmania/src/CommonMetrics.cpp index 5a300d91fd..f92d9047e8 100644 --- a/stepmania/src/CommonMetrics.cpp +++ b/stepmania/src/CommonMetrics.cpp @@ -23,6 +23,7 @@ ThemeMetric CommonMetrics::DEFAULT_NOTESKIN_NAME ("Common","DefaultN ThemeMetricDifficultiesToShow CommonMetrics::DIFFICULTIES_TO_SHOW ("Common","DifficultiesToShow"); ThemeMetricCourseDifficultiesToShow CommonMetrics::COURSE_DIFFICULTIES_TO_SHOW ("Common","CourseDifficultiesToShow"); ThemeMetricStepsTypesToShow CommonMetrics::STEPS_TYPES_TO_SHOW ("Common","StepsTypesToHide"); +ThemeMetric CommonMetrics::ALL_STEPS_TYPES_IN_ONE_LIST ("Common","AllStepsTypeInOneList"); ThemeMetricDifficultiesToShow::ThemeMetricDifficultiesToShow( const RString& sGroup, const RString& sName ) : diff --git a/stepmania/src/CommonMetrics.h b/stepmania/src/CommonMetrics.h index 3d435c1bc0..71bdd29d48 100644 --- a/stepmania/src/CommonMetrics.h +++ b/stepmania/src/CommonMetrics.h @@ -62,6 +62,7 @@ namespace CommonMetrics extern ThemeMetricDifficultiesToShow DIFFICULTIES_TO_SHOW; extern ThemeMetricCourseDifficultiesToShow COURSE_DIFFICULTIES_TO_SHOW; extern ThemeMetricStepsTypesToShow STEPS_TYPES_TO_SHOW; + extern ThemeMetric ALL_STEPS_TYPES_IN_ONE_LIST; RString LocalizeOptionItem( const RString &s, bool bOptional ); }; diff --git a/stepmania/src/Course.cpp b/stepmania/src/Course.cpp index 6708f6a58b..f8bc1c83b5 100644 --- a/stepmania/src/Course.cpp +++ b/stepmania/src/Course.cpp @@ -462,7 +462,7 @@ bool Course::GetTrailUnsorted( StepsType st, CourseDifficulty cd, Trail &trail ) soc.m_Tutorial = SongCriteria::Tutorial_No; soc.m_Locked = SongCriteria::Locked_Unlocked; if( !soc.m_bUseSongAllowedList ) - soc.m_iStagesForSong = 1; + soc.m_iMaxStagesForSong = 1; StepsCriteria stc = e->stepsCriteria; stc.m_st = st; diff --git a/stepmania/src/DifficultyList.cpp b/stepmania/src/DifficultyList.cpp index f1a7367252..0d1d98b594 100644 --- a/stepmania/src/DifficultyList.cpp +++ b/stepmania/src/DifficultyList.cpp @@ -282,19 +282,16 @@ void DifficultyList::SetFromGameState() } else { - vector CurSteps; - SongUtil::GetSteps( pSong, CurSteps, GAMESTATE->GetCurrentStyle()->m_StepsType ); - + vector vpSteps; + SongUtil::GetPossibleSteps( pSong, vpSteps ); /* Should match the sort in ScreenSelectMusic::AfterMusicChange. */ - StepsUtil::RemoveLockedSteps( pSong, CurSteps ); - StepsUtil::SortNotesArrayByDifficulty( CurSteps ); - m_Rows.resize( CurSteps.size() ); - for( unsigned i = 0; i < CurSteps.size(); ++i ) + m_Rows.resize( vpSteps.size() ); + for( unsigned i = 0; i < vpSteps.size(); ++i ) { Row &row = m_Rows[i]; - row.m_Steps = CurSteps[i]; + row.m_Steps = vpSteps[i]; m_Lines[i].m_Meter.SetFromSteps( m_Rows[i].m_Steps ); diff --git a/stepmania/src/GameManager.cpp b/stepmania/src/GameManager.cpp index 5c902d8929..e3de12dfe5 100644 --- a/stepmania/src/GameManager.cpp +++ b/stepmania/src/GameManager.cpp @@ -10,6 +10,7 @@ #include "LightsManager.h" // for NUM_CabinetLight #include "Game.h" #include "Style.h" +#include "Foreach.h" GameManager* GAMEMAN = NULL; // global and accessable from anywhere in our program @@ -2335,6 +2336,52 @@ const Style* GameManager::GetHowToPlayStyleForGame( const Game *pGame ) const return NULL; } +void GameManager::GetCompatibleStyles( const Game *pGame, int iNumPlayers, vector &vpStylesOut ) const +{ + FOREACH_ENUM( StyleType, styleType ) + { + switch( styleType ) + { + DEFAULT_FAIL( styleType ); + case StyleType_OnePlayerOneSide: + case StyleType_OnePlayerTwoSides: + if( iNumPlayers != 1 ) + continue; + break; + case StyleType_TwoPlayersTwoSides: + case StyleType_TwoPlayersSharedSides: + if( iNumPlayers != 2 ) + continue; + break; + } + + for( unsigned s=0; sm_pGame != pGame ) + continue; + if( style->m_StyleType != styleType ) + continue; + if( !style->m_bUsedForGameplay ) + continue; + + vpStylesOut.push_back( style ); + } + } +} + +const Style *GameManager::GetFirstCompatibleStyle( const Game *pGame, int iNumPlayers, StepsType st ) const +{ + vector vpStyles; + GetCompatibleStyles( pGame, iNumPlayers, vpStyles ); + FOREACH_CONST( const Style*, vpStyles, s ) + if( (*s)->m_StepsType == st ) + return *s; + FAIL_M(""); + return NULL; +} + + void GameManager::GetEnabledGames( vector& aGamesOut ) const { for( size_t g=0; g& aStylesAddTo, bool editor=false ) const; - void GetStepsTypesForGame( const Game* pGame, vector& aStepsTypeAddTo ) const; - const Style* GetEditorStyleForStepsType( StepsType st ) const; + void GetStylesForGame( const Game* pGame, vector& aStylesAddTo, bool editor=false ) const; + void GetStepsTypesForGame( const Game* pGame, vector& aStepsTypeAddTo ) const; + const Style *GetEditorStyleForStepsType( StepsType st ) const; void GetDemonstrationStylesForGame( const Game *pGame, vector &vpStylesOut ) const; - const Style* GetHowToPlayStyleForGame( const Game* pGame ) const; + const Style *GetHowToPlayStyleForGame( const Game* pGame ) const; + void GameManager::GetCompatibleStyles( const Game *pGame, int iNumPlayers, vector &vpStylesOut ) const; + const Style *GameManager::GetFirstCompatibleStyle( const Game *pGame, int iNumPlayers, StepsType st ) const; void GetEnabledGames( vector& aGamesOut ) const; const Game* GetDefaultGame() const; diff --git a/stepmania/src/GameState.cpp b/stepmania/src/GameState.cpp index b89f853c33..2f570040bb 100644 --- a/stepmania/src/GameState.cpp +++ b/stepmania/src/GameState.cpp @@ -505,11 +505,44 @@ void GameState::EndGame() m_timeGameStarted.SetZero(); } -static int GetNumStagesForCurrentSong() +int GameState::GetNumStagesForSong( const Song* pSong ) +{ + int iNumStages = 1; + + ASSERT( pSong ); + if( pSong->IsMarathon() ) + iNumStages *= 3; + if( pSong->IsLong() ) + iNumStages *= 2; + + return iNumStages; +} + +int GameState::GetNumStagesForSongAndStyle( const Song* pSong, const Style *pStyle ) +{ + int iNumStages = GetNumStagesForSong( pSong ); + + // One player, two-sides styles cost extra + switch( pStyle->m_StyleType ) + { + DEFAULT_FAIL( pStyle->m_StyleType ); + case StyleType_OnePlayerOneSide: + iNumStages *= 2; + break; + case StyleType_TwoPlayersTwoSides: + case StyleType_OnePlayerTwoSides: + case StyleType_TwoPlayersSharedSides: + break; + } + + return iNumStages; +} + +static int GetNumStagesForCurrentSongOrCourse() { int iNumStagesOfThisSong = 1; if( GAMESTATE->m_pCurSong ) - iNumStagesOfThisSong = SongManager::GetNumStagesForSong( GAMESTATE->m_pCurSong ); + iNumStagesOfThisSong = GameState::GetNumStagesForSong( GAMESTATE->m_pCurSong ); else if( GAMESTATE->m_pCurCourse ) iNumStagesOfThisSong = 1; else @@ -553,7 +586,7 @@ void GameState::BeginStage() m_SongOptions.Assign( ModsLevel_Stage, m_SongOptions.GetPreferred() ); STATSMAN->m_CurStageStats.m_fMusicRate = m_SongOptions.GetSong().m_fMusicRate; - m_iNumStagesOfThisSong = GetNumStagesForCurrentSong(); + m_iNumStagesOfThisSong = GetNumStagesForCurrentSongOrCourse(); ASSERT( m_iNumStagesOfThisSong != -1 ); } @@ -771,7 +804,7 @@ bool GameState::IsFinalStage() const return true; /* This changes dynamically on ScreenSelectMusic as the wheel turns. */ - int iPredictedStageForCurSong = GetNumStagesForCurrentSong(); + int iPredictedStageForCurSong = GetNumStagesForCurrentSongOrCourse(); if( iPredictedStageForCurSong == -1 ) iPredictedStageForCurSong = 1; return m_iCurrentStageIndex + iPredictedStageForCurSong == PREFSMAN->m_iSongsPerPlay; diff --git a/stepmania/src/GameState.h b/stepmania/src/GameState.h index 53aaef40de..77cbab5653 100644 --- a/stepmania/src/GameState.h +++ b/stepmania/src/GameState.h @@ -118,6 +118,9 @@ public: int m_iNumStagesOfThisSong; int m_iCurrentStageIndex; + static int GetNumStagesForSong( const Song* pSong ); + static int GetNumStagesForSongAndStyle( const Song* pSong, const Style *pStyle ); + int GetStageIndex() const; void BeginStage(); void CancelStage(); diff --git a/stepmania/src/MusicBannerWheel.cpp b/stepmania/src/MusicBannerWheel.cpp index f00d092741..89df6b1ba6 100644 --- a/stepmania/src/MusicBannerWheel.cpp +++ b/stepmania/src/MusicBannerWheel.cpp @@ -57,9 +57,18 @@ MusicBannerWheel::MusicBannerWheel() this->AddChild( &m_ScrollingList ); if( GAMESTATE->m_sPreferredSongGroup == GROUP_ALL ) - SONGMAN->GetSongs( arraySongs, GAMESTATE->GetNumStagesLeft() ); + SONGMAN->GetSongs( arraySongs ); else // Get the Group They Want - SONGMAN->GetSongs( arraySongs, GAMESTATE->m_sPreferredSongGroup, GAMESTATE->GetNumStagesLeft() ); + SONGMAN->GetSongs( arraySongs, GAMESTATE->m_sPreferredSongGroup ); + + // filter songs that we don't have enough stages to play + { + vector vTempSongs; + SongCriteria sc; + sc.m_iMaxStagesForSong = GAMESTATE->GetNumStagesLeft(); + SongUtil::FilterSongs( sc, arraySongs, vTempSongs ); + arraySongs = vTempSongs; + } //Detect autogenned songs if ( !PREFSMAN->m_bAutogenSteps ) diff --git a/stepmania/src/MusicWheel.cpp b/stepmania/src/MusicWheel.cpp index 54c552d5a1..ce89dbb022 100644 --- a/stepmania/src/MusicWheel.cpp +++ b/stepmania/src/MusicWheel.cpp @@ -155,18 +155,28 @@ void MusicWheel::BeginScreen() if( GAMESTATE->m_PreferredSortOrder == SortOrder_Invalid ) GAMESTATE->m_PreferredSortOrder = GAMESTATE->m_SortOrder; - // HACK: invalidate currently selected song in the case that it - // cannot be played due to lack of stages remaining - // checking for event mode shouldn't be necessary here - // but someone mentioned it does it sometimes. + /* Invalidate current Song if it can't be played + * because there are not enough stages remaining. */ if( GAMESTATE->m_pCurSong != NULL && - SongManager::GetNumStagesForSong( GAMESTATE->m_pCurSong ) + GAMESTATE->m_iCurrentStageIndex > PREFSMAN->m_iSongsPerPlay - && !GAMESTATE->IsEventMode() - && !GAMESTATE->IsAnExtraStage() ) + GameState::GetNumStagesForSong( GAMESTATE->m_pCurSong ) > GAMESTATE->GetNumStagesLeft() ) { GAMESTATE->m_pCurSong.Set( NULL ); } + /* Invalidate current Steps if it can't be played + * because there are not enough stages remaining. */ + FOREACH_ENUM( PlayerNumber, p ) + { + if( GAMESTATE->m_pCurSteps[p] != NULL ) + { + vector vpPossibleSteps; + SongUtil::GetPossibleSteps( GAMESTATE->m_pCurSong, vpPossibleSteps ); + bool bStepsIsPossible = find( vpPossibleSteps.begin(), vpPossibleSteps.end(), GAMESTATE->m_pCurSteps[p] ) == vpPossibleSteps.end(); + if( !bStepsIsPossible ) + GAMESTATE->m_pCurSteps[p].Set( NULL ); + } + } + // Select the the previously selected song (if any) if( !SelectSongOrCourse() ) SetOpenGroup(""); @@ -316,16 +326,25 @@ void MusicWheel::GetSongList( vector &arraySongs, SortOrder so, const RSt switch( so ) { case SORT_PREFERRED: - SONGMAN->GetPreferredSortSongs( apAllSongs, GAMESTATE->GetNumStagesLeft() ); + SONGMAN->GetPreferredSortSongs( apAllSongs ); break; case SORT_POPULARITY: - SONGMAN->GetPopularSongs( apAllSongs, GAMESTATE->m_sPreferredSongGroup, GAMESTATE->GetNumStagesLeft() ); + SONGMAN->GetPopularSongs( apAllSongs, GAMESTATE->m_sPreferredSongGroup ); break; default: - SONGMAN->GetSongs( apAllSongs, GAMESTATE->m_sPreferredSongGroup, GAMESTATE->GetNumStagesLeft() ); + SONGMAN->GetSongs( apAllSongs, GAMESTATE->m_sPreferredSongGroup ); break; } + // filter songs that we don't have enough stages to play + { + vector vTempSongs; + SongCriteria sc; + sc.m_iMaxStagesForSong = GAMESTATE->GetNumStagesLeft(); + 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 &arrayWheelItemDat { WID.m_Flags.bHasBeginnerOr1Meter = WID.m_pSong->IsEasy( GAMESTATE->GetCurrentStyle()->m_StepsType ); WID.m_Flags.bEdits = WID.m_pSong->HasEdits( GAMESTATE->GetCurrentStyle()->m_StepsType ); - WID.m_Flags.iStagesForSong = SongManager::GetNumStagesForSong( WID.m_pSong ); + WID.m_Flags.iStagesForSong = GameState::GetNumStagesForSong( WID.m_pSong ); } else if( WID.m_pCourse != NULL ) { diff --git a/stepmania/src/ScoreKeeperNormal.cpp b/stepmania/src/ScoreKeeperNormal.cpp index cc04909d4d..82ed2a1ae0 100644 --- a/stepmania/src/ScoreKeeperNormal.cpp +++ b/stepmania/src/ScoreKeeperNormal.cpp @@ -206,7 +206,7 @@ void ScoreKeeperNormal::OnNextSong( int iSongInCourseIndex, const Steps* pSteps, const int iMeter = clamp( pSteps->GetMeter(), 1, 10 ); // long ver and marathon ver songs have higher max possible scores - int iLengthMultiplier = SongManager::GetNumStagesForSong( GAMESTATE->m_pCurSong ); + int iLengthMultiplier = GameState::GetNumStagesForSong( GAMESTATE->m_pCurSong ); switch( PREFSMAN->m_ScoringType ) { case SCORING_NEW: diff --git a/stepmania/src/ScreenSelectMusic.cpp b/stepmania/src/ScreenSelectMusic.cpp index b823edbfd6..c048dfd601 100644 --- a/stepmania/src/ScreenSelectMusic.cpp +++ b/stepmania/src/ScreenSelectMusic.cpp @@ -273,6 +273,14 @@ void ScreenSelectMusic::Input( const InputEventPlus &input ) { // LOG->Trace( "ScreenSelectMusic::Input()" ); + // temp Chris debug + if( input.DeviceI.device == DEVICE_KEYBOARD && input.DeviceI.button == KEY_F8 ) + { + if( input.type != IET_FIRST_PRESS ) + return; + MESSAGEMAN->Broadcast("SongChosen"); + } + // debugging? // I just like being able to see untransliterated titles occasionally. if( input.DeviceI.device == DEVICE_KEYBOARD && input.DeviceI.button == KEY_F9 ) @@ -932,9 +940,7 @@ void ScreenSelectMusic::AfterMusicChange() m_fSampleStartSeconds = pSong->m_fMusicSampleStartSeconds; m_fSampleLengthSeconds = pSong->m_fMusicSampleLengthSeconds; - SongUtil::GetSteps( pSong, m_vpSteps, GAMESTATE->GetCurrentStyle()->m_StepsType ); - StepsUtil::RemoveLockedSteps( pSong, m_vpSteps ); - StepsUtil::SortNotesArrayByDifficulty( m_vpSteps ); + SongUtil::GetPossibleSteps( pSong, m_vpSteps ); if ( PREFSMAN->m_bShowBanners ) g_sBannerPath = pSong->GetBannerPath(); diff --git a/stepmania/src/SongManager.cpp b/stepmania/src/SongManager.cpp index 650fc1fe23..2871cb7663 100644 --- a/stepmania/src/SongManager.cpp +++ b/stepmania/src/SongManager.cpp @@ -514,31 +514,30 @@ RageColor SongManager::GetCourseColor( const Course* pCourse ) } } -static void GetSongsFromVector( const vector &Songs, vector &AddTo, RString sGroupName, int iMaxStages ) +static void GetSongsFromVector( const vector &Songs, vector &vOut, RString sGroupName ) { - AddTo.clear(); + vOut.clear(); for( unsigned i=0; im_sGroupName ) - if( SongManager::GetNumStagesForSong(Songs[i]) <= iMaxStages ) - AddTo.push_back( Songs[i] ); + vOut.push_back( Songs[i] ); } -void SongManager::GetSongs( vector &AddTo, RString sGroupName, int iMaxStages ) const +void SongManager::GetSongs( vector &AddTo, RString sGroupName ) const { - GetSongsFromVector( m_pSongs, AddTo, sGroupName, iMaxStages ); + GetSongsFromVector( m_pSongs, AddTo, sGroupName ); } -void SongManager::GetPopularSongs( vector &AddTo, RString sGroupName, int iMaxStages, ProfileSlot slot ) const +void SongManager::GetPopularSongs( vector &AddTo, RString sGroupName, ProfileSlot slot ) const { - GetSongsFromVector( m_pPopularSongs[slot], AddTo, sGroupName, iMaxStages ); + GetSongsFromVector( m_pPopularSongs[slot], AddTo, sGroupName ); } -void SongManager::GetPreferredSortSongs( vector &AddTo, int iMaxStages ) const +void SongManager::GetPreferredSortSongs( vector &AddTo ) const { if( m_vPreferredSongSort.empty() ) { - GetSongs( AddTo, iMaxStages ); + GetSongs( AddTo ); return; } @@ -661,17 +660,6 @@ RString SongManager::ShortenGroupName( RString sLongGroupName ) return title.Title; } -int SongManager::GetNumStagesForSong( const Song* pSong ) -{ - ASSERT( pSong ); - if( pSong->IsMarathon() ) - return 3; - if( pSong->IsLong() ) - return 2; - else - return 1; -} - static LocalizedString LOADING_COURSES ( "SongManager", "Loading courses..." ); void SongManager::InitCoursesFromDisk( LoadingWindow *ld ) { diff --git a/stepmania/src/SongManager.h b/stepmania/src/SongManager.h index b89b0ad53e..f74c8b66cf 100644 --- a/stepmania/src/SongManager.h +++ b/stepmania/src/SongManager.h @@ -69,18 +69,16 @@ public: RageColor GetCourseColor( const Course* pCourse ); static RString ShortenGroupName( RString sLongGroupName ); - static int GetNumStagesForSong( const Song* pSong ); // LongVer songs take 2 stages, MarathonVer take 3 // Lookup const vector &GetAllSongs() const { return m_pSongs; } - void GetPopularSongs( vector &AddTo, RString sGroupName, int iMaxStages = INT_MAX, ProfileSlot slot=ProfileSlot_Machine ) const; - void GetPreferredSortSongs( vector &AddTo, int iMaxStages = INT_MAX ) const; + void GetPopularSongs( vector &AddTo, RString sGroupName, ProfileSlot slot=ProfileSlot_Machine ) const; + void GetPreferredSortSongs( vector &AddTo ) const; const vector &GetPopularSongs( ProfileSlot slot=ProfileSlot_Machine ) const { return m_pPopularSongs[slot]; } const vector &GetPopularCourses( CourseType ct, ProfileSlot slot=ProfileSlot_Machine ) const { return m_pPopularCourses[slot][ct]; } - void GetSongs( vector &AddTo, RString sGroupName, int iMaxStages = INT_MAX ) const; - void GetSongs( vector &AddTo, int iMaxStages ) const { GetSongs(AddTo,GROUP_ALL,iMaxStages); } - void GetSongs( vector &AddTo ) const { GetSongs(AddTo,GROUP_ALL,INT_MAX); } + void GetSongs( vector &AddTo, RString sGroupName ) const; + void GetSongs( vector &AddTo ) const { GetSongs(AddTo,GROUP_ALL); } Song *FindSong( RString sPath ); Song *FindSong( RString sGroup, RString sSong ); Course *FindCourse( RString sPath ); diff --git a/stepmania/src/SongUtil.cpp b/stepmania/src/SongUtil.cpp index 09d77574d2..5827d5b5ec 100644 --- a/stepmania/src/SongUtil.cpp +++ b/stepmania/src/SongUtil.cpp @@ -14,6 +14,8 @@ #include "ThemeMetric.h" #include "LocalizedString.h" #include "RageLog.h" +#include "GameManager.h" +#include "CommonMetrics.h" bool SongCriteria::Matches( const Song *pSong ) const { @@ -808,6 +810,35 @@ void SongUtil::FilterSongs( const SongCriteria &sc, const vector &in, vec } } +void SongUtil::GetPossibleSteps( const Song *pSong, vector &vOut ) +{ + vector vpPossibleStyles; + if( CommonMetrics::ALL_STEPS_TYPES_IN_ONE_LIST ) + GAMEMAN->GetCompatibleStyles( GAMESTATE->m_pCurGame, GAMESTATE->GetNumPlayersEnabled(), vpPossibleStyles ); + else + vpPossibleStyles.push_back( GAMESTATE->m_pCurStyle ); + + set vStepsType; + FOREACH( const Style*, vpPossibleStyles, s ) + vStepsType.insert( (*s)->m_StepsType ); + + FOREACHS( StepsType, vStepsType, st ) + SongUtil::GetSteps( pSong, vOut, *st ); + + StepsUtil::RemoveLockedSteps( pSong, vOut ); + StepsUtil::SortNotesArrayByDifficulty( vOut ); + StepsUtil::SortStepsByTypeAndDifficulty( vOut ); + + // remove steps that we don't have enough stages left to play + for( int i=vOut.size()-1; i>=0; i-- ) + { + Steps *pSteps = vOut[i]; + StepsType st = pSteps->m_StepsType; + const Style *pStyle = GAMEMAN->GetFirstCompatibleStyle( GAMESTATE->m_pCurGame, GAMESTATE->GetNumPlayersEnabled(), st ); + if( GAMESTATE->GetNumStagesForSongAndStyle(pSong,pStyle) > GAMESTATE->GetNumStagesLeft() ) + vOut.erase( vOut.begin() + i ); + } +} ////////////////////////////////// // SongID diff --git a/stepmania/src/SongUtil.h b/stepmania/src/SongUtil.h index b4141be3fa..1216f568cd 100644 --- a/stepmania/src/SongUtil.h +++ b/stepmania/src/SongUtil.h @@ -109,6 +109,8 @@ namespace SongUtil void GetAllSongGenres( vector &vsOut ); void FilterSongs( const SongCriteria &sc, const vector &in, vector &out ); + + void GetPossibleSteps( const Song *pSong, vector &vOut ); } class SongID