From abfc956e4fb59af31aeaf65e61b8708dc2647a03 Mon Sep 17 00:00:00 2001 From: Chris Danford Date: Sun, 23 May 2004 00:53:20 +0000 Subject: [PATCH] refactor Course: move some responsibilities to Trail --- stepmania/src/BPMDisplay.cpp | 60 ++---- stepmania/src/BPMDisplay.h | 2 +- stepmania/src/Course.cpp | 265 +++++++----------------- stepmania/src/Course.h | 44 ++-- stepmania/src/CourseContentsList.cpp | 22 +- stepmania/src/CourseEntryDisplay.cpp | 35 ++-- stepmania/src/CourseEntryDisplay.h | 2 +- stepmania/src/CourseUtil.cpp | 16 +- stepmania/src/DifficultyMeter.cpp | 5 +- stepmania/src/EnumHelper.h | 54 ----- stepmania/src/Foreach.h | 9 + stepmania/src/GameConstantsAndTypes.cpp | 47 +++++ stepmania/src/GameConstantsAndTypes.h | 10 + stepmania/src/Makefile.am | 3 +- stepmania/src/PaneDisplay.cpp | 3 +- stepmania/src/PlayerOptions.cpp | 9 +- stepmania/src/Profile.cpp | 4 +- stepmania/src/ProfileHtml.cpp | 9 +- stepmania/src/ScreenGameplay.cpp | 32 +-- stepmania/src/ScreenOptions.cpp | 59 ++---- stepmania/src/ScreenSelectCourse.cpp | 4 +- stepmania/src/ScreenSelectMusic.cpp | 20 +- stepmania/src/Song.cpp | 11 +- stepmania/src/SongManager.cpp | 19 +- stepmania/src/SongUtil.cpp | 16 +- stepmania/src/StepMania.dsp | 25 ++- stepmania/src/StepMania.vcproj | 8 +- stepmania/src/Trail.cpp | 105 ++++++++++ stepmania/src/Trail.h | 51 +++++ stepmania/src/song.h | 2 +- 30 files changed, 479 insertions(+), 472 deletions(-) create mode 100644 stepmania/src/Foreach.h create mode 100644 stepmania/src/Trail.cpp create mode 100644 stepmania/src/Trail.h diff --git a/stepmania/src/BPMDisplay.cpp b/stepmania/src/BPMDisplay.cpp index 384566bdd0..e09625423b 100644 --- a/stepmania/src/BPMDisplay.cpp +++ b/stepmania/src/BPMDisplay.cpp @@ -91,9 +91,11 @@ void BPMDisplay::Update( float fDeltaTime ) } -void BPMDisplay::SetBPMRange( const vector &BPMS ) +void BPMDisplay::SetBPMRange( const DisplayBpms &bpms ) { - ASSERT( BPMS.size() ); + ASSERT( !bpms.vfBpms.empty() ); + + const vector &BPMS = bpms.vfBpms; unsigned i; bool AllIdentical = true; @@ -159,9 +161,9 @@ void BPMDisplay::SetBPMRange( const vector &BPMS ) void BPMDisplay::CycleRandomly() { - vector BPMS; - BPMS.push_back(-1); - SetBPMRange( BPMS ); + DisplayBpms bpms; + bpms.Add(-1); + SetBPMRange( bpms ); m_fCycleTime = 0.2f; } @@ -183,12 +185,9 @@ void BPMDisplay::SetBPM( const Song* pSong ) case Song::DISPLAY_ACTUAL: case Song::DISPLAY_SPECIFIED: { - float fMinBPM, fMaxBPM; - pSong->GetDisplayBPM( fMinBPM, fMaxBPM ); - vector BPMS; - BPMS.push_back(fMinBPM); - BPMS.push_back(fMaxBPM); - SetBPMRange( BPMS ); + DisplayBpms bpms; + pSong->GetDisplayBpms( bpms ); + SetBPMRange( bpms ); m_fCycleTime = 1.0f; } break; @@ -204,43 +203,14 @@ void BPMDisplay::SetBPM( const Course* pCourse ) { ASSERT( pCourse ); - vector ci; - pCourse->GetCourseInfo( GAMESTATE->GetCurrentStyleDef()->m_StepsType, ci ); + Trail *pTrail = pCourse->GetTrail( GAMESTATE->GetCurrentStyleDef()->m_StepsType, COURSE_DIFFICULTY_REGULAR ); - ASSERT( ci.size() ); + ASSERT( pTrail->m_vEntries.size() ); - vector BPMS; - for( unsigned i = 0; i < ci.size(); ++i ) - { - if( ci[i].Mystery ) - { - BPMS.push_back( -1 ); - continue; - } - - Song *pSong = ci[i].pSong; - ASSERT( pSong ); - switch( pSong->m_DisplayBPMType ) - { - case Song::DISPLAY_ACTUAL: - case Song::DISPLAY_SPECIFIED: - { - float fMinBPM, fMaxBPM; - pSong->GetDisplayBPM( fMinBPM, fMaxBPM ); - BPMS.push_back( fMinBPM ); - if( fMinBPM != fMaxBPM ) - BPMS.push_back( fMaxBPM ); - } - break; - case Song::DISPLAY_RANDOM: - BPMS.push_back( -1 ); - break; - default: - ASSERT(0); - } - } + DisplayBpms bpms; + pTrail->GetDisplayBpms( bpms ); - SetBPMRange( BPMS ); + SetBPMRange( bpms ); m_fCycleTime = 0.2f; } diff --git a/stepmania/src/BPMDisplay.h b/stepmania/src/BPMDisplay.h index cda29c9542..4b2c7da47a 100644 --- a/stepmania/src/BPMDisplay.h +++ b/stepmania/src/BPMDisplay.h @@ -34,7 +34,7 @@ public: protected: float GetActiveBPM() const; - void SetBPMRange( const vector &m_BPMS ); + void SetBPMRange( const DisplayBpms &bpms ); BitmapText m_textBPM; AutoActor m_sprLabel; diff --git a/stepmania/src/Course.cpp b/stepmania/src/Course.cpp index f9aa716c73..a24101f636 100644 --- a/stepmania/src/Course.cpp +++ b/stepmania/src/Course.cpp @@ -15,6 +15,7 @@ #include "song.h" #include "GameManager.h" #include "SongManager.h" +#include "GameState.h" #include "RageException.h" #include "RageLog.h" #include "MsdFile.h" @@ -23,7 +24,6 @@ #include "RageUtil.h" #include "TitleSubstitution.h" #include "Steps.h" -#include "GameState.h" #include "BannerCache.h" #include "RageFile.h" #include "arch/arch.h" @@ -40,7 +40,7 @@ const int MAX_BOTTOM_RANGE = 10; Course::Course() { - Unload(); + Init(); } PlayMode Course::GetPlayMode() const @@ -50,60 +50,11 @@ PlayMode Course::GetPlayMode() const return m_iLives > 0? PLAY_MODE_ONI:PLAY_MODE_NONSTOP; } -float Course::GetMeterForPlayer( PlayerNumber pn ) const -{ - return GetMeter( GAMESTATE->m_PreferredCourseDifficulty[pn] ); -} - -float Course::GetMeter( CourseDifficulty cd ) const -{ - /* If we have a meter for this difficulty, use it. */ - if( m_iMeter[cd] != -1 ) - return float( m_iMeter[cd] ); - - /*LOG->Trace( "Course file '%s' contains a song '%s%s%s' that is not present", - m_sPath.c_str(), sGroup.c_str(), sGroup.size()? "/":"", sSong.c_str());*/ - vector ci; - GetCourseInfo( GAMESTATE->GetCurrentStyleDef()->m_StepsType, ci, cd ); - - if( ci.size() == 0 ) - return 0; - - /* Take the average meter. */ - float fTotalMeter = 0; - for( unsigned c = 0; c < ci.size(); ++c ) - { - if( ci[c].Mystery ) - { - switch( GetDifficulty(ci[c]) ) - { - case DIFFICULTY_INVALID: - { - int iMeterLow, iMeterHigh; - GetMeterRange(ci[c], iMeterLow, iMeterHigh ); - fTotalMeter += (iMeterLow + iMeterHigh) / 2.0f; - break; - } - /* XXX? */ - case DIFFICULTY_BEGINNER: fTotalMeter += 1; break; - case DIFFICULTY_EASY: fTotalMeter += 2; break; - case DIFFICULTY_MEDIUM: fTotalMeter += 5; break; - case DIFFICULTY_HARD: fTotalMeter += 7; break; - case DIFFICULTY_CHALLENGE: fTotalMeter += 9; break; - } - } - else - fTotalMeter += ci[c].pNotes->GetMeter(); - } -// LOG->Trace("Course '%s': %f", m_sName.c_str(), fTotalMeter/ci.size() ); - return fTotalMeter / ci.size(); -} - void Course::LoadFromCRSFile( CString sPath ) { LOG->Trace( "Course::LoadFromCRSFile( '%s' )", sPath.c_str() ); - Unload(); + Init(); m_sPath = sPath; // save path @@ -152,7 +103,7 @@ void Course::LoadFromCRSFile( CString sPath ) else if( 0 == stricmp(sValueName, "METER") ) { if( sParams.params.size() == 2 ) - m_iMeter[COURSE_DIFFICULTY_REGULAR] = atoi( sParams[1] ); /* compat */ + m_iCustomMeter[COURSE_DIFFICULTY_REGULAR] = atoi( sParams[1] ); /* compat */ else if( sParams.params.size() == 3 ) { const CourseDifficulty cd = StringToCourseDifficulty( sParams[1] ); @@ -162,7 +113,7 @@ void Course::LoadFromCRSFile( CString sPath ) m_sPath.c_str(), sParams[1].c_str() ); continue; } - m_iMeter[cd] = atoi( sParams[2] ); + m_iCustomMeter[cd] = atoi( sParams[2] ); } } @@ -314,13 +265,13 @@ void Course::LoadFromCRSFile( CString sPath ) ignore, ignore, ignore); } -void Course::Unload() +void Course::Init() { m_bIsAutogen = false; m_bRepeat = false; m_bRandomize = false; m_iLives = -1; - m_iMeter[0] = m_iMeter[1] = -1; + ZERO( m_iCustomMeter ); m_entries.clear(); m_sPath = m_sName = m_sTranslitName = m_sBannerPath = m_sCDTitlePath = ""; } @@ -343,9 +294,9 @@ void Course::Save() f.PutLine( ssprintf("#LIVES:%i;", m_iLives) ); FOREACH_CourseDifficulty( cd ) { - if( m_iMeter[cd] == -1 ) + if( m_iCustomMeter[cd] == -1 ) continue; - f.PutLine( ssprintf("#METER:%s:%i;", CourseDifficultyToString(cd).c_str(), m_iMeter[cd]) ); + f.PutLine( ssprintf("#METER:%s:%i;", CourseDifficultyToString(cd).c_str(), m_iCustomMeter[cd]) ); } for( unsigned i=0; i Normal, Hard; - GetCourseInfo( nt, Normal, COURSE_DIFFICULTY_REGULAR ); - GetCourseInfo( nt, Hard, cd ); + Trail *Regular = GetTrail( nt, COURSE_DIFFICULTY_REGULAR ); + Trail *Other = GetTrail( nt, cd ); - if( Normal.size() != Hard.size() ) - return true; /* it changed */ - - for( unsigned i=0; i ci; - GetCourseInfo( nt, ci ); - return ci.size() > 0; + Trail* pTrail = GetTrail( nt, COURSE_DIFFICULTY_REGULAR ); + return !pTrail->m_vEntries.empty(); } static vector GetFilteredBestSongs( StepsType nt ) @@ -597,16 +510,22 @@ static vector GetFilteredBestSongs( StepsType nt ) /* This is called by many simple functions, like Course::GetTotalSeconds, and may * be called on all songs to sort. It can take time to execute, so we cache the * results. */ -void Course::GetCourseInfo( StepsType nt, vector &ci, CourseDifficulty cd ) const +Trail* Course::GetTrail( StepsType nt, CourseDifficulty cd ) const { - const InfoParams params( nt, cd ); - InfoCache::const_iterator it = m_InfoCache.find( params ); - if( it != m_InfoCache.end() ) + // + // Look in the Trail cache + // + const TrailParams params( nt, cd ); + TrailCache::iterator it = m_TrailCache.find( params ); + if( it != m_TrailCache.end() ) { - ci = it->second; - return; + return &it->second; } + + // + // Construct a new Trail, add it to the cache, then return it. + // /* Different seed for each course, but the same for the whole round: */ RandomGen rnd( GAMESTATE->m_iRoundSeed + GetHashForString(m_sName) ); @@ -630,7 +549,8 @@ void Course::GetCourseInfo( StepsType nt, vector &ci, CourseDiffic vector AllSongsShuffled; int CurSong = 0; /* Current offset into AllSongsShuffled */ - ci.clear(); + + Trail trail; for( unsigned i=0; i &ci, CourseDiffic } } - Info cinfo; - cinfo.pSong = pSong; - cinfo.pNotes = pNotes; - cinfo.Modifiers = e.modifiers; - cinfo.Attacks = e.attacks; - cinfo.Random = ( e.type == COURSE_ENTRY_RANDOM || e.type == COURSE_ENTRY_RANDOM_WITHIN_GROUP ); - cinfo.Mystery = e.mystery; - cinfo.CourseIndex = i; - cinfo.Difficulty = entry_difficulty; - ci.push_back( cinfo ); + TrailEntry te; + te.pSong = pSong; + te.pNotes = pNotes; + te.Modifiers = e.modifiers; + te.Attacks = e.attacks; + te.bMystery = e.mystery; + te.iLowMeter = low_meter; + te.iHighMeter = high_meter; + trail.m_vEntries.push_back( te ); } /* Cache results. */ - m_InfoCache[params] = ci; + m_TrailCache[params] = trail; + return &m_TrailCache[params]; } bool Course::HasMods() const @@ -793,11 +713,14 @@ bool Course::AllSongsAreFixed() const void Course::ClearCache() { - m_InfoCache.clear(); + m_TrailCache.clear(); } RageColor Course::GetColor() const { + // FIXME: These colors shouldn't be hard-coded + int iMeter = 5; + switch (PREFSMAN->m_iCourseSortOrder) { case PrefsManager::COURSE_SORT_SONGS: @@ -813,31 +736,31 @@ RageColor Course::GetColor() const case PrefsManager::COURSE_SORT_METER: if ( !IsFixed() ) return RageColor(0,0,1,1); // blue - if (GetMeter() > 8.5) + if (iMeter > 8.5) return RageColor(1,0,0,1); // red - if (GetMeter() >= 7) + if (iMeter >= 7) return RageColor(1,0.5f,0,1); // orange - if (GetMeter() >= 5) + if (iMeter >= 5) return RageColor(1,1,0,1); // yellow return RageColor(0,1,0,1); // green case PrefsManager::COURSE_SORT_METER_SUM: if ( !IsFixed() ) return RageColor(0,0,1,1); // blue - if (SortOrder_TotalDifficulty >= 40) + if (m_SortOrder_TotalDifficulty >= 40) return RageColor(1,0,0,1); // red - if (SortOrder_TotalDifficulty >= 30) + if (m_SortOrder_TotalDifficulty >= 30) return RageColor(1,0.5f,0,1); // orange - if (SortOrder_TotalDifficulty >= 20) + if (m_SortOrder_TotalDifficulty >= 20) return RageColor(1,1,0,1); // yellow return RageColor(0,1,0,1); // green case PrefsManager::COURSE_SORT_RANK: - if (SortOrder_Ranking == 3) + if (m_SortOrder_Ranking == 3) return RageColor(0,0,1,1); // blue - if (SortOrder_Ranking == 2) + if (m_SortOrder_Ranking == 2) return RageColor(1,0.5f,0,1); // orange - if (SortOrder_Ranking == 1) + if (m_SortOrder_Ranking == 1) return RageColor(0,1,0,1); // green return RageColor(1,1,0,1); // yellow, never should get here default: @@ -859,14 +782,6 @@ bool Course::IsFixed() const return true; } -Difficulty Course::GetDifficulty( const Info &stage ) const -{ - Difficulty dc = m_entries[stage.CourseIndex].difficulty; - Difficulty new_dc = Difficulty( dc + COURSE_DIFFICULTY_CLASS_CHANGE[stage.Difficulty] ); - new_dc = clamp( new_dc, DIFFICULTY_BEGINNER, DIFFICULTY_CHALLENGE ); - return new_dc; -} - void Course::GetMeterRange( int stage, int& iMeterLowOut, int& iMeterHighOut, CourseDifficulty cd ) const { iMeterLowOut = m_entries[stage].low_meter; @@ -878,23 +793,14 @@ void Course::GetMeterRange( int stage, int& iMeterLowOut, int& iMeterHighOut, Co } -void Course::GetMeterRange( const Info &stage, int& iMeterLowOut, int& iMeterHighOut ) const +bool Course::GetTotalSeconds( StepsType st, float& fSecondsOut ) const { - GetMeterRange( stage.CourseIndex, iMeterLowOut, iMeterHighOut, stage.Difficulty ); -} + if( !IsFixed() ) + return false; -bool Course::GetTotalSeconds( float& fSecondsOut ) const -{ - vector ci; - GetCourseInfo( STEPS_TYPE_DANCE_SINGLE, ci ); + Trail* pTrail = GetTrail( st, COURSE_DIFFICULTY_REGULAR ); - fSecondsOut = 0; - for( unsigned i=0; im_fMusicLengthSeconds; - } + fSecondsOut = pTrail->GetLengthSeconds(); return true; } @@ -918,9 +824,9 @@ bool Course::HasBanner() const return m_sBannerPath != "" && IsAFile(m_sBannerPath); } -void Course::UpdateCourseStats() +void Course::UpdateCourseStats( StepsType st ) { - SortOrder_TotalDifficulty = 0; + m_SortOrder_TotalDifficulty = 0; unsigned i; @@ -930,17 +836,15 @@ void Course::UpdateCourseStats() if ( m_entries[i].type == COURSE_ENTRY_FIXED ) continue; - if ( SortOrder_Ranking == 2 ) - SortOrder_Ranking = 3; - SortOrder_TotalDifficulty = 999999; // large number + if ( m_SortOrder_Ranking == 2 ) + m_SortOrder_Ranking = 3; + m_SortOrder_TotalDifficulty = 999999; // large number return; } - vector ci; - GetCourseInfo( GAMESTATE->GetCurrentStyleDef()->m_StepsType, ci ); + Trail* pTrail = GetTrail( st, COURSE_DIFFICULTY_REGULAR ); - for( i = 0; i < ci.size(); i++ ) - SortOrder_TotalDifficulty += ci[i].pNotes->GetMeter(); + m_SortOrder_TotalDifficulty += pTrail->GetTotalMeter(); // OPTIMIZATION: Ranking info isn't dependant on style, so // call it sparingly. Its handled on startup and when @@ -948,23 +852,7 @@ void Course::UpdateCourseStats() LOG->Trace("%s: Total feet: %d", this->m_sName.c_str(), - SortOrder_TotalDifficulty ); -} - -void Course::Info::GetAttackArray( AttackArray &out ) const -{ - if( !Modifiers.empty() ) - { - Attack a; - a.fStartSecond = 0; - a.fSecsRemaining = 10000; /* whole song */ - a.level = ATTACK_LEVEL_1; - a.sModifier = Modifiers; - - out.push_back( a ); - } - - out.insert( out.end(), Attacks.begin(), Attacks.end() ); + m_SortOrder_TotalDifficulty ); } bool Course::IsRanking() const @@ -980,20 +868,11 @@ bool Course::IsRanking() const return false; } - -RadarValues Course::GetRadarValues( StepsType st, CourseDifficulty cd ) const +float Course::GetMeter( StepsType nt, CourseDifficulty cd ) const { - RadarValues rv; + /* If we have a manually-entered meter for this difficulty, use it. */ + if( m_iCustomMeter[cd] != -1 ) + return m_iCustomMeter[cd]; - vector ci; - this->GetCourseInfo( st, ci, cd ); - for( unsigned i = 0; i < ci.size(); ++i ) - { - const Steps *pNotes = ci[i].pNotes; - ASSERT( pNotes ); - rv += pNotes->GetRadarValues(); - } - - return rv; + return roundf( GetTrail(nt,cd)->GetAverageMeter() ); } - diff --git a/stepmania/src/Course.h b/stepmania/src/Course.h index c83173299c..643677077e 100644 --- a/stepmania/src/Course.h +++ b/stepmania/src/Course.h @@ -15,6 +15,7 @@ #include "GameConstantsAndTypes.h" #include "Attack.h" #include +#include "Trail.h" struct PlayerOptions; struct SongOptions; @@ -93,28 +94,14 @@ public: bool m_bRepeat; // repeat after last song? "Endless" bool m_bRandomize; // play the songs in a random order int m_iLives; // -1 means use bar life meter - int m_iMeter[NUM_COURSE_DIFFICULTIES]; // -1 autogens + int m_iCustomMeter[NUM_COURSE_DIFFICULTIES]; // -1 = no meter specified vector m_entries; - struct Info - { - Info(): pSong(NULL), pNotes(NULL), Random(false), Difficulty(COURSE_DIFFICULTY_INVALID) { } - void GetAttackArray( AttackArray &out ) const; - - Song* pSong; - Steps* pNotes; - CString Modifiers; - AttackArray Attacks; - bool Random; - bool Mystery; - CourseDifficulty Difficulty; - /* Corresponding entry in m_entries: */ - int CourseIndex; - }; // Dereferences course_entries and returns only the playable Songs and Steps - void GetCourseInfo( StepsType nt, vector &ci, CourseDifficulty cd = COURSE_DIFFICULTY_REGULAR ) const; + Trail* GetTrail( StepsType nt, CourseDifficulty cd ) const; + float GetMeter( StepsType nt, CourseDifficulty cd ) const; bool HasMods() const; bool AllSongsAreFixed() const; @@ -123,33 +110,27 @@ public: bool IsPlayableIn( StepsType nt ) const; bool CourseHasBestOrWorst() const; RageColor GetColor() const; - Difficulty GetDifficulty( const Info &stage ) const; - void GetMeterRange( const Info &stage, int& iMeterLowOut, int& iMeterHighOut ) const; - bool GetTotalSeconds( float& fSecondsOut ) const; + bool GetTotalSeconds( StepsType st, float& fSecondsOut ) const; bool IsNonstop() const { return GetPlayMode() == PLAY_MODE_NONSTOP; } bool IsOni() const { return GetPlayMode() == PLAY_MODE_ONI; } bool IsEndless() const { return GetPlayMode() == PLAY_MODE_ENDLESS; } PlayMode GetPlayMode() const; - float GetMeter( CourseDifficulty cd = COURSE_DIFFICULTY_REGULAR ) const; - float GetMeterForPlayer( PlayerNumber pn ) const; bool IsFixed() const; void LoadFromCRSFile( CString sPath ); - void Unload(); + void Init(); void Save(); void AutogenEndlessFromGroup( CString sGroupName, Difficulty diff ); void AutogenNonstopFromGroup( CString sGroupName, Difficulty diff ); - RadarValues GetRadarValues( StepsType st, CourseDifficulty cd ) const; - // sorting values - int SortOrder_TotalDifficulty; - int SortOrder_Ranking; + int m_SortOrder_TotalDifficulty; + int m_SortOrder_Ranking; bool IsRanking() const; - void UpdateCourseStats(); + void UpdateCourseStats( StepsType st ); /* Call per-screen, and if song or notes pointers change: */ void ClearCache(); @@ -158,10 +139,9 @@ private: CString GetAutogenDifficultySuffix( Difficulty diff ) const; void GetMeterRange( int stage, int& iMeterLowOut, int& iMeterHighOut, CourseDifficulty cd ) const; - typedef pair InfoParams; - typedef vector InfoData; - typedef map InfoCache; - mutable InfoCache m_InfoCache; + typedef pair TrailParams; + typedef map TrailCache; + mutable TrailCache m_TrailCache; }; #endif diff --git a/stepmania/src/CourseContentsList.cpp b/stepmania/src/CourseContentsList.cpp index c3e1c9e854..cb71c084ce 100644 --- a/stepmania/src/CourseContentsList.cpp +++ b/stepmania/src/CourseContentsList.cpp @@ -56,17 +56,25 @@ void CourseContentsList::SetFromCourse( const Course* pCourse ) return; } - vector ci[NUM_PLAYERS]; - for( int pn = 0; pn < NUM_PLAYERS; ++pn ) - pCourse->GetCourseInfo( GAMESTATE->GetCurrentStyleDef()->m_StepsType, ci[pn], GAMESTATE->m_PreferredCourseDifficulty[pn] ); + Trail* pTrail[NUM_PLAYERS]; + FOREACH_PlayerNumber(pn) + { + pTrail[pn] = pCourse->GetTrail( GAMESTATE->GetCurrentStyleDef()->m_StepsType, GAMESTATE->m_PreferredCourseDifficulty[pn] ); + } - m_iNumContents = 0; - for( int i=0; im_vEntries.size(), MAX_TOTAL_CONTENTS); i++ ) { CourseEntryDisplay& display = m_CourseContentDisplays[m_iNumContents]; - const Course::Info pci[NUM_PLAYERS] = { ci[0][i], ci[1][i] }; - display.LoadFromCourseInfo( m_iNumContents+1, pCourse, pci ); + TrailEntry* pte[NUM_PLAYERS]; + FOREACH_EnabledPlayer(pn) + pte[pn] = &pTrail[0]->m_vEntries[i]; + display.LoadFromTrailEntry( m_iNumContents+1, pCourse, pte ); m_iNumContents++; } diff --git a/stepmania/src/CourseEntryDisplay.cpp b/stepmania/src/CourseEntryDisplay.cpp index 35371bbb7b..18891e57b0 100644 --- a/stepmania/src/CourseEntryDisplay.cpp +++ b/stepmania/src/CourseEntryDisplay.cpp @@ -87,24 +87,24 @@ void CourseEntryDisplay::SetDifficulty( PlayerNumber pn, const CString &text, Ra m_textFoot[pn].SetDiffuse( c ); } -void CourseEntryDisplay::LoadFromCourseInfo( int iNum, const Course *pCourse, const Course::Info pci[NUM_PLAYERS] ) +void CourseEntryDisplay::LoadFromTrailEntry( int iNum, const Course *pCourse, TrailEntry *tes[NUM_PLAYERS] ) { - const Course::Info &ci = pci[GAMESTATE->m_MasterPlayerNumber]; - - if( ci.Mystery ) + TrailEntry *te = tes[GAMESTATE->m_MasterPlayerNumber]; + bool bMystery = te->bMystery; + if( bMystery ) { - for( int pn = 0; pn < NUM_PLAYERS; ++pn ) + FOREACH_EnabledPlayer(pn) { - Difficulty dc = pCourse->GetDifficulty( pci[pn] ); + TrailEntry *te = tes[pn]; + Difficulty dc = te->pNotes->GetDifficulty(); if( dc == DIFFICULTY_INVALID ) { - int iLow, iHigh; - pCourse->GetMeterRange(pci[pn], iLow, iHigh); - - SetDifficulty( (PlayerNumber)pn, ssprintf(iLow==iHigh?"%d":"%d-%d", iLow, iHigh), RageColor(1,1,1,1) ); + int iLow = te->iLowMeter; + int iHigh = te->iHighMeter; + SetDifficulty( pn, ssprintf(iLow==iHigh?"%d":"%d-%d", iLow, iHigh), RageColor(1,1,1,1) ); } else - SetDifficulty( (PlayerNumber)pn, "?", SONGMAN->GetDifficultyColor( dc ) ); + SetDifficulty( pn, "?", SONGMAN->GetDifficultyColor( dc ) ); } m_TextBanner.LoadFromString( "??????????", "??????????", "", "", "", "" ); @@ -112,17 +112,18 @@ void CourseEntryDisplay::LoadFromCourseInfo( int iNum, const Course *pCourse, co } else { - for( int pn = 0; pn < NUM_PLAYERS; ++pn ) + FOREACH_EnabledPlayer(pn) { - RageColor colorNotes = SONGMAN->GetDifficultyColor( pci[pn].pNotes->GetDifficulty() ); - SetDifficulty( (PlayerNumber)pn, ssprintf("%d", pci[pn].pNotes->GetMeter()), colorNotes ); + TrailEntry *te = tes[pn]; + RageColor colorNotes = SONGMAN->GetDifficultyColor( te->pNotes->GetDifficulty() ); + SetDifficulty( pn, ssprintf("%d", te->pNotes->GetMeter()), colorNotes ); } - m_TextBanner.LoadFromSong( ci.pSong ); - m_TextBanner.SetDiffuse( SONGMAN->GetSongColor( ci.pSong ) ); + m_TextBanner.LoadFromSong( te->pSong ); + m_TextBanner.SetDiffuse( SONGMAN->GetSongColor( te->pSong ) ); } m_textNumber.SetText( ssprintf("%d", iNum) ); - m_textModifiers.SetText( ci.Modifiers ); + m_textModifiers.SetText( te->Modifiers ); } diff --git a/stepmania/src/CourseEntryDisplay.h b/stepmania/src/CourseEntryDisplay.h index c97f3de568..f9f6ba044d 100644 --- a/stepmania/src/CourseEntryDisplay.h +++ b/stepmania/src/CourseEntryDisplay.h @@ -28,7 +28,7 @@ class CourseEntryDisplay : public ActorFrame public: void Load(); - void LoadFromCourseInfo( int iNum, const Course *pCourse, const Course::Info ci[NUM_PLAYERS] ); + void LoadFromTrailEntry( int iNum, const Course *pCourse, TrailEntry *te[NUM_PLAYERS] ); private: void SetDifficulty( PlayerNumber pn, const CString &text, RageColor c ); diff --git a/stepmania/src/CourseUtil.cpp b/stepmania/src/CourseUtil.cpp index aedf887a67..6d81a7cb42 100644 --- a/stepmania/src/CourseUtil.cpp +++ b/stepmania/src/CourseUtil.cpp @@ -16,6 +16,8 @@ #include "ProfileManager.h" #include "SongManager.h" #include "XmlFile.h" +#include "GameState.h" +#include "StyleDef.h" // @@ -64,8 +66,8 @@ static bool CompareCoursePointersByDifficulty(const Course* pCourse1, const Cour static bool CompareCoursePointersByTotalDifficulty(const Course* pCourse1, const Course* pCourse2) { - int iNum1 = pCourse1->SortOrder_TotalDifficulty; - int iNum2 = pCourse2->SortOrder_TotalDifficulty; + int iNum1 = pCourse1->m_SortOrder_TotalDifficulty; + int iNum2 = pCourse2->m_SortOrder_TotalDifficulty; if( iNum1 == iNum2 ) return CompareCoursePointersByAutogen( pCourse1, pCourse2 ); @@ -93,8 +95,8 @@ static bool CompareRandom( const Course* pCourse1, const Course* pCourse2 ) static bool CompareCoursePointersByRanking(const Course* pCourse1, const Course* pCourse2) { - int iNum1 = pCourse1->SortOrder_Ranking; - int iNum2 = pCourse2->SortOrder_Ranking; + int iNum1 = pCourse1->m_SortOrder_Ranking; + int iNum2 = pCourse2->m_SortOrder_Ranking; if( iNum1 == iNum2 ) return CompareCoursePointersByAutogen( pCourse1, pCourse2 ); @@ -109,14 +111,14 @@ void CourseUtil::SortCoursePointerArrayByDifficulty( vector &apCourses void CourseUtil::SortCoursePointerArrayByRanking( vector &apCourses ) { for(unsigned i=0; iUpdateCourseStats(); + apCourses[i]->UpdateCourseStats( GAMESTATE->GetCurrentStyleDef()->m_StepsType ); sort( apCourses.begin(), apCourses.end(), CompareCoursePointersByRanking ); } void CourseUtil::SortCoursePointerArrayByTotalDifficulty( vector &apCourses ) { for(unsigned i=0; iUpdateCourseStats(); + apCourses[i]->UpdateCourseStats( GAMESTATE->GetCurrentStyleDef()->m_StepsType ); sort( apCourses.begin(), apCourses.end(), CompareCoursePointersByTotalDifficulty ); } @@ -157,7 +159,7 @@ void CourseUtil::SortCoursePointerArrayByAvgDifficulty( vector &apCours RageTimer foo; course_sort_val.clear(); for(unsigned i = 0; i < apCourses.size(); ++i) - course_sort_val[apCourses[i]] = apCourses[i]->GetMeter(); + course_sort_val[apCourses[i]] = apCourses[i]->GetMeter( GAMESTATE->GetCurrentStyleDef()->m_StepsType, COURSE_DIFFICULTY_REGULAR ); sort( apCourses.begin(), apCourses.end(), CompareCoursePointersByTitle ); stable_sort( apCourses.begin(), apCourses.end(), CompareCoursePointersBySortValueAscending ); diff --git a/stepmania/src/DifficultyMeter.cpp b/stepmania/src/DifficultyMeter.cpp index 8aee796cc6..2fa8b1a9d6 100644 --- a/stepmania/src/DifficultyMeter.cpp +++ b/stepmania/src/DifficultyMeter.cpp @@ -20,6 +20,7 @@ #include "Course.h" #include "SongManager.h" #include "ActorUtil.h" +#include "StyleDef.h" #define NUM_FEET_IN_METER THEME->GetMetricI(m_sName,"NumFeetInMeter") @@ -117,7 +118,9 @@ void DifficultyMeter::SetFromCourse( const Course* pCourse, PlayerNumber pn ) return; } - const int meter = (int) roundf(pCourse->GetMeterForPlayer( pn )); + StepsType st = GAMESTATE->GetCurrentStyleDef()->m_StepsType; + CourseDifficulty cd = GAMESTATE->m_PreferredCourseDifficulty[pn]; + const int meter = (int) roundf( pCourse->GetMeter(st,cd) ); // XXX metrics Difficulty FakeDifficulty; diff --git a/stepmania/src/EnumHelper.h b/stepmania/src/EnumHelper.h index 419d53576a..308a5f217a 100644 --- a/stepmania/src/EnumHelper.h +++ b/stepmania/src/EnumHelper.h @@ -33,58 +33,4 @@ static const CString EMPTY_STRING; return (X)(i+1); /*invalid*/ \ } - - -// -// An enum class with reflection-like functionality. -// String literals are stored in GetString instead of a static member so that -// the literals can be defined in the header. -// -#define BEGIN_ENUM( name ) \ -class name { \ -public: \ - enum Value { \ - -#define MIDDLE_ENUM( name ) \ - NUM, \ - INVALID = -1, \ - }; \ -protected: \ - Value m_value; \ - CCStringRef GetString(int i) const { \ - const CString s[NUM] = { \ - -#define END_ENUM( name ) \ - }; return s[i]; } \ -public: \ - name( Value value ) { m_value=value; } \ - name() { MakeInvalid(); } \ - name( int value ) { m_value=(Value)value; } \ - operator int&() { return (int&)m_value; } \ - operator size_t() const { return (size_t)m_value; } \ - static size_t Num() { return (size_t)NUM; } \ - name& operator=(Value val) { m_value = val; return *this; } \ - bool operator<(const name& other) const { return m_value < other.m_value; } \ - void MakeInvalid() { m_value=INVALID; } \ - bool IsValid() const { return m_value>=0 && m_value::iterator var = vect.begin(); var != vect.end(); var++ ) +#define FOREACH_CONST( elemType, vect, var ) for( vector::const_iterator var = vect.begin(); var != vect.end(); var++ ) + + +#endif diff --git a/stepmania/src/GameConstantsAndTypes.cpp b/stepmania/src/GameConstantsAndTypes.cpp index d34096d446..37fd787642 100644 --- a/stepmania/src/GameConstantsAndTypes.cpp +++ b/stepmania/src/GameConstantsAndTypes.cpp @@ -15,6 +15,7 @@ #include "RageUtil.h" #include "ThemeManager.h" #include "EnumHelper.h" +#include "Foreach.h" static const CString RadarCategoryNames[NUM_RADAR_CATEGORIES] = { @@ -170,3 +171,49 @@ LuaFunction_Str( StringTo##X, LuaStringTo##X(str) ); /* register it */ LuaXToString( Difficulty ); LuaStringToX( Difficulty ); + + +void DisplayBpms::Add( float f ) +{ + vfBpms.push_back( f ); +} + +float DisplayBpms::GetMin() +{ + float fMin = 99999; + FOREACH_CONST( float, vfBpms, f ) + { + if( *f != -1 ) + fMin = min( fMin, *f ); + } + if( fMin == 99999 ) + return 0; + else + return fMin; +} + +float DisplayBpms::GetMax() +{ + float fMax = 0; + FOREACH_CONST( float, vfBpms, f ) + { + if( *f != -1 ) + fMax = max( fMax, *f ); + } + return fMax; +} + +bool DisplayBpms::BpmIsConstant() +{ + return GetMin() == GetMax(); +} + +bool DisplayBpms::IsMystery() +{ + FOREACH_CONST( float, vfBpms, f ) + { + if( *f == -1 ) + return true; + } + return false; +} diff --git a/stepmania/src/GameConstantsAndTypes.h b/stepmania/src/GameConstantsAndTypes.h index dd564578a3..d0d7a1e6b2 100644 --- a/stepmania/src/GameConstantsAndTypes.h +++ b/stepmania/src/GameConstantsAndTypes.h @@ -363,4 +363,14 @@ CString PeakComboAwardToThemedString( PeakComboAward pma ); PeakComboAward StringToPeakComboAward( const CString& pma ); +struct DisplayBpms +{ + void Add( float f ); + float GetMin(); + float GetMax(); + bool BpmIsConstant(); + bool IsMystery(); + vector vfBpms; +}; + #endif diff --git a/stepmania/src/Makefile.am b/stepmania/src/Makefile.am index a7e5c2c158..c631abe8cf 100644 --- a/stepmania/src/Makefile.am +++ b/stepmania/src/Makefile.am @@ -66,7 +66,8 @@ ProfileHtml.cpp ProfileHtml.h RandomSample.cpp RandomSample.h ScoreKeeper.h Scor ScoreKeeperRave.cpp ScoreKeeperRave.h Song.cpp song.h SongCacheIndex.cpp SongCacheIndex.h \ SongOptions.cpp SongOptions.h SongUtil.cpp SongUtil.h StageStats.cpp StageStats.h Steps.cpp Steps.h \ StepsUtil.cpp StepsUtil.h Style.h StyleDef.cpp StyleDef.h \ -StyleInput.h TimeConstants.cpp TimeConstants.h TimingData.cpp TimingData.h TitleSubstitution.cpp TitleSubstitution.h +StyleInput.h TimeConstants.cpp TimeConstants.h TimingData.cpp TimingData.h \ +Trail.cpp Trail.h TitleSubstitution.cpp TitleSubstitution.h FileTypes = IniFile.cpp IniFile.h \ MsdFile.cpp MsdFile.h \ diff --git a/stepmania/src/PaneDisplay.cpp b/stepmania/src/PaneDisplay.cpp index 47e6660cbd..f18edb6284 100644 --- a/stepmania/src/PaneDisplay.cpp +++ b/stepmania/src/PaneDisplay.cpp @@ -157,10 +157,9 @@ void PaneDisplay::SetContent( PaneContents c ) rv = GAMESTATE->m_pCurNotes[m_PlayerNumber]->GetRadarValues(); else if( g_Contents[c].req&NEED_COURSE ) { - vector ci; CourseDifficulty cd = GAMESTATE->m_PreferredCourseDifficulty[m_PlayerNumber]; StepsType st = GAMESTATE->GetCurrentStyleDef()->m_StepsType; - rv = GAMESTATE->m_pCurCourse->GetRadarValues( st, cd ); + rv = GAMESTATE->m_pCurCourse->GetTrail(st,cd)->GetRadarValues(); } const Song *pSong = GAMESTATE->m_pCurSong; diff --git a/stepmania/src/PlayerOptions.cpp b/stepmania/src/PlayerOptions.cpp index 06c6fc9913..3788b5fb4a 100644 --- a/stepmania/src/PlayerOptions.cpp +++ b/stepmania/src/PlayerOptions.cpp @@ -21,6 +21,7 @@ #include "Course.h" #include "Steps.h" #include "ThemeManager.h" +#include "Foreach.h" #define ONE( arr ) { for( unsigned Z = 0; Z < ARRAYSIZE(arr); ++Z ) arr[Z]=1.0f; } @@ -573,13 +574,11 @@ bool PlayerOptions::IsEasierForSongAndSteps( Song* pSong, Steps* pSteps ) bool PlayerOptions::IsEasierForCourse( Course* pCourse, StepsType st, CourseDifficulty cd ) { - vector ci; - pCourse->GetCourseInfo( st, ci, cd ); + Trail *pTrail = pCourse->GetTrail( st, cd ); - for( unsigned i=0; im_vEntries, e ) { - const Course::Info& info = ci[i]; - if( info.pSong && IsEasierForSongAndSteps(info.pSong, info.pNotes) ) + if( e->pSong && IsEasierForSongAndSteps(e->pSong, e->pNotes) ) return true; } return false; diff --git a/stepmania/src/Profile.cpp b/stepmania/src/Profile.cpp index 0176e1954e..ac138b20a4 100644 --- a/stepmania/src/Profile.cpp +++ b/stepmania/src/Profile.cpp @@ -307,7 +307,7 @@ int Profile::GetPossibleCourseDancePointsForStepsType( StepsType st ) const if( !pCourse->HasCourseDifficulty(st,cd) ) continue; - const RadarValues& fRadars = pCourse->GetRadarValues(st,cd); + const RadarValues& fRadars = pCourse->GetTrail(st,cd)->GetRadarValues(); iTotal += ScoreKeeperMAX2::GetPossibleDancePoints( fRadars ); } } @@ -342,7 +342,7 @@ int Profile::GetActualCourseDancePointsForStepsType( StepsType st ) const FOREACH_ShownCourseDifficulty( cd ) { const HighScoreList& hs = h.hs[st][cd]; - const RadarValues& fRadars = pCourse->GetRadarValues(st,cd); + const RadarValues& fRadars = pCourse->GetTrail(st,cd)->GetRadarValues(); int iPossibleDP = ScoreKeeperMAX2::GetPossibleDancePoints( fRadars ); iTotal += (int)truncf( hs.GetTopScore().fPercentDP * iPossibleDP ); } diff --git a/stepmania/src/ProfileHtml.cpp b/stepmania/src/ProfileHtml.cpp index fd2412c57d..95df40ab7e 100644 --- a/stepmania/src/ProfileHtml.cpp +++ b/stepmania/src/ProfileHtml.cpp @@ -894,7 +894,8 @@ bool PrintPercentCompleteForStepsType( RageFile &f, const Profile *pProfile, Ste * style is set. */ if( GAMESTATE->m_CurStyle == STYLE_INVALID ) GAMESTATE->m_CurStyle = STYLE_DANCE_SINGLE; - TranslatedWrite(f, ssprintf("(%.2f)",pCourse->GetMeter(cd)) ); + float fMeter = pCourse->GetMeter(st,cd); + TranslatedWrite(f, ssprintf("(%.2f)",fMeter) ); HighScore hs = pProfile->GetCourseHighScoreList(pCourse, st, cd).GetTopScore(); Grade grade = hs.grade; if( grade != GRADE_NO_DATA ) @@ -1011,9 +1012,9 @@ bool PrintCatalogForSong( RageFile &f, const Profile *pProfile, Song* pSong ) BEGIN_TABLE(2); TABLE_LINE2( "Artist", pSong->GetDisplayArtist() ); TABLE_LINE2( "GroupName", pSong->m_sGroupName ); - float fMinBPM, fMaxBPM; - pSong->GetDisplayBPM( fMinBPM, fMaxBPM ); - CString sBPM = (fMinBPM==fMaxBPM) ? ssprintf("%.1f",fMinBPM) : ssprintf("%.1f - %.1f",fMinBPM,fMaxBPM); + DisplayBpms bpms; + pSong->GetDisplayBpms( bpms ); + CString sBPM = (bpms.BpmIsConstant()) ? ssprintf("%.1f",bpms.GetMin()) : ssprintf("%.1f - %.1f",bpms.GetMin(),bpms.GetMax()); TABLE_LINE2( "BPM", sBPM ); TABLE_LINE2( "Credit", pSong->m_sCredit ); TABLE_LINE2( "MusicLength", SecondsToMMSSMsMs(pSong->m_fMusicLengthSeconds) ); diff --git a/stepmania/src/ScreenGameplay.cpp b/stepmania/src/ScreenGameplay.cpp index d22f88ec5e..51d3f7b415 100644 --- a/stepmania/src/ScreenGameplay.cpp +++ b/stepmania/src/ScreenGameplay.cpp @@ -49,6 +49,7 @@ #include "StageStats.h" #include "PlayerAI.h" // for NUM_SKILL_LEVELS #include "NetworkSyncManager.h" +#include "Foreach.h" // // Defines @@ -182,37 +183,36 @@ void ScreenGameplay::Init() // if( GAMESTATE->IsCourseMode() ) { + Course* pCourse = GAMESTATE->m_pCurCourse; const StepsType st = GAMESTATE->GetCurrentStyleDef()->m_StepsType; + /* Increment the play count. */ if( !m_bDemonstration ) FOREACH_EnabledPlayer(p) - PROFILEMAN->IncrementCoursePlayCount( GAMESTATE->m_pCurCourse, st, GAMESTATE->m_PreferredCourseDifficulty[p], (PlayerNumber)p ); + PROFILEMAN->IncrementCoursePlayCount( pCourse, st, GAMESTATE->m_PreferredCourseDifficulty[p], (PlayerNumber)p ); + + m_apSongsQueue.clear(); + PlayerNumber pnMaster = GAMESTATE->m_MasterPlayerNumber; + Trail *pTrail = pCourse->GetTrail( st, GAMESTATE->m_PreferredCourseDifficulty[pnMaster] ); + FOREACH_CONST( TrailEntry, pTrail->m_vEntries, e ) + { + m_apSongsQueue.push_back( e->pSong ); + } FOREACH_PlayerNumber(p) { - vector ci; - GAMESTATE->m_pCurCourse->GetCourseInfo( GAMESTATE->GetCurrentStyleDef()->m_StepsType, ci, GAMESTATE->m_PreferredCourseDifficulty[p] ); + Trail *pTrail = pCourse->GetTrail( st, GAMESTATE->m_PreferredCourseDifficulty[p] ); m_apNotesQueue[p].clear(); m_asModifiersQueue[p].clear(); - for( unsigned c=0; cm_vEntries, e ) { - m_apNotesQueue[p].push_back( ci[c].pNotes ); + m_apNotesQueue[p].push_back( e->pNotes ); AttackArray a; - ci[c].GetAttackArray( a ); + e->GetAttackArray( a ); m_asModifiersQueue[p].push_back( a ); - - const CString path = THEME->GetPathToG( ssprintf("ScreenGameplay course song %i", c+1), true ); - if( path != "" ) - TEXTUREMAN->CacheTexture( path ); } - if( p == 0 ) - { - m_apSongsQueue.clear(); - for( unsigned c=0; cm_pCurSong ) { - float fMinBpm, fMaxBpm; - GAMESTATE->m_pCurSong->GetDisplayBPM( fMinBpm, fMaxBpm ); - if( fMinBpm == fMaxBpm ) - sTitle += ssprintf( " (%.0f)", fMinBpm ); - else - sTitle += ssprintf( " (%.0f-%.0f)", fMinBpm, fMaxBpm ); + Song* pSong = GAMESTATE->m_pCurSong; + pSong->GetDisplayBpms( bpms ); } else if( GAMESTATE->m_pCurCourse ) { - float fTotalMinBpm = -1, fTotalMaxBpm = -1; // -1 == no marker - vector ci; - GAMESTATE->m_pCurCourse->GetCourseInfo( GAMESTATE->GetCurrentStyleDef()->m_StepsType, ci ); - - ASSERT( ci.size() ); - - for( unsigned i = 0; i < ci.size(); ++i ) - { - if( ci[i].Mystery ) - continue; - - Song *pSong = ci[i].pSong; - ASSERT( pSong ); - switch( pSong->m_DisplayBPMType ) - { - case Song::DISPLAY_ACTUAL: - case Song::DISPLAY_SPECIFIED: - { - float fMinBpm, fMaxBpm; - pSong->GetDisplayBPM( fMinBpm, fMaxBpm ); - if( fTotalMinBpm == -1 ) fTotalMinBpm = fMinBpm; - else fTotalMinBpm = min( fTotalMinBpm, fMinBpm ); - if( fTotalMaxBpm == -1 ) fTotalMaxBpm = fMaxBpm; - else fTotalMaxBpm = max( fTotalMaxBpm, fMaxBpm ); - } - break; - case Song::DISPLAY_RANDOM: - break; - default: - ASSERT(0); - } - } - - if( fTotalMinBpm == -1 || fTotalMaxBpm == -1 ) - sTitle += ssprintf( " (??" "?)" ); /* split so gcc doesn't think this is a trigraph */ - else if( fTotalMinBpm == fTotalMaxBpm ) - sTitle += ssprintf( " (%.0f)", fTotalMinBpm ); - else - sTitle += ssprintf( " (%.0f-%.0f)", fTotalMinBpm, fTotalMaxBpm ); + Course *pCourse = GAMESTATE->m_pCurCourse; + StepsType st = GAMESTATE->GetCurrentStyleDef()->m_StepsType; + Trail* pTrail = pCourse->GetTrail(st,COURSE_DIFFICULTY_REGULAR); + pTrail->GetDisplayBpms( bpms ); } + + if( bpms.IsMystery() ) + sTitle += ssprintf( " (??" "?)" ); /* split so gcc doesn't think this is a trigraph */ + else if( bpms.BpmIsConstant() ) + sTitle += ssprintf( " (%.0f)", bpms.GetMin() ); + else + sTitle += ssprintf( " (%.0f-%.0f)", bpms.GetMin(), bpms.GetMax() ); } } diff --git a/stepmania/src/ScreenSelectCourse.cpp b/stepmania/src/ScreenSelectCourse.cpp index ea351ca6be..3bbae58f26 100644 --- a/stepmania/src/ScreenSelectCourse.cpp +++ b/stepmania/src/ScreenSelectCourse.cpp @@ -385,11 +385,11 @@ void ScreenSelectCourse::AfterCourseChange() case TYPE_COURSE: { Course* pCourse = m_MusicWheel.GetSelectedCourse(); - const StepsType &st = GAMESTATE->GetCurrentStyleDef()->m_StepsType; + StepsType st = GAMESTATE->GetCurrentStyleDef()->m_StepsType; m_textNumSongs.SetText( ssprintf("%d", pCourse->GetEstimatedNumStages()) ); float fTotalSeconds; - if( pCourse->GetTotalSeconds(fTotalSeconds) ) + if( pCourse->GetTotalSeconds(st, fTotalSeconds) ) m_textTime.SetText( SecondsToMMSSMsMs(fTotalSeconds) ); else m_textTime.SetText( "xx:xx.xx" ); // The numbers format doesn't have a '?'. Is there a better solution? diff --git a/stepmania/src/ScreenSelectMusic.cpp b/stepmania/src/ScreenSelectMusic.cpp index 9b7b975ba7..2471c92ccb 100644 --- a/stepmania/src/ScreenSelectMusic.cpp +++ b/stepmania/src/ScreenSelectMusic.cpp @@ -34,6 +34,7 @@ #include "LightsManager.h" #include "StageStats.h" #include "StepsUtil.h" +#include "Foreach.h" const int NUM_SCORE_DIGITS = 9; @@ -1479,6 +1480,8 @@ void ScreenSelectMusic::AfterMusicChange() case TYPE_COURSE: { Course* pCourse = m_MusicWheel.GetSelectedCourse(); + StepsType st = GAMESTATE->GetCurrentStyleDef()->m_StepsType; + Trail *pTrail = pCourse->GetTrail( st, COURSE_DIFFICULTY_REGULAR ); SampleMusicToPlay = THEME->GetPathS(m_sName,"course music"); m_fSampleStartSeconds = 0; @@ -1486,7 +1489,7 @@ void ScreenSelectMusic::AfterMusicChange() m_textNumSongs.SetText( ssprintf("%d", pCourse->GetEstimatedNumStages()) ); float fTotalSeconds; - if( pCourse->GetTotalSeconds(fTotalSeconds) ) + if( pCourse->GetTotalSeconds(st,fTotalSeconds) ) m_textTotalTime.SetText( SecondsToMMSSMsMs(fTotalSeconds) ); else m_textTotalTime.SetText( "xx:xx.xx" ); // The numbers format doesn't have a '?'. Is there a better solution? @@ -1498,18 +1501,15 @@ void ScreenSelectMusic::AfterMusicChange() m_CourseContentsFrame.TweenInAfterChangedCourse(); m_DifficultyDisplay.UnsetDifficulties(); - vector ci; - pCourse->GetCourseInfo( GAMESTATE->GetCurrentStyleDef()->m_StepsType, ci ); - - for( unsigned i = 0; i < ci.size(); ++i ) + FOREACH_CONST( TrailEntry, pTrail->m_vEntries, e ) { - if( ci[i].Mystery ) + if( e->bMystery ) { m_Artists.push_back( "???" ); m_AltArtists.push_back( "???" ); } else { - m_Artists.push_back( ci[i].pSong->GetDisplayArtist() ); - m_AltArtists.push_back( ci[i].pSong->GetTranslitArtist() ); + m_Artists.push_back( e->pSong->GetDisplayArtist() ); + m_AltArtists.push_back( e->pSong->GetTranslitArtist() ); } } @@ -1556,9 +1556,9 @@ void ScreenSelectMusic::AfterMusicChange() m_Artist.SetTips( m_Artists, m_AltArtists ); - for( int p=0; p ci; - course.GetCourseInfo( GAMESTATE->GetCurrentStyleDef()->m_StepsType, ci ); - if( ci.empty() ) + Trail *pTrail = course.GetTrail( GAMESTATE->GetCurrentStyleDef()->m_StepsType, COURSE_DIFFICULTY_REGULAR ); + if( pTrail->m_vEntries.empty() ) return false; po_out.Init(); - po_out.FromString( ci[0].Modifiers ); + po_out.FromString( pTrail->m_vEntries[0].Modifiers ); so_out.Init(); - so_out.FromString( ci[0].Modifiers ); + so_out.FromString( pTrail->m_vEntries[0].Modifiers ); - pSongOut = ci[0].pSong; - pNotesOut = ci[0].pNotes; + pSongOut = pTrail->m_vEntries[0].pSong; + pNotesOut = pTrail->m_vEntries[0].pNotes; return true; } @@ -949,13 +948,13 @@ void SongManager::UpdateRankingCourses() for(unsigned i=0; i < m_pCourses.size(); i++) { if (m_pCourses[i]->GetEstimatedNumStages() > 7) - m_pCourses[i]->SortOrder_Ranking = 3; + m_pCourses[i]->m_SortOrder_Ranking = 3; else - m_pCourses[i]->SortOrder_Ranking = 2; + m_pCourses[i]->m_SortOrder_Ranking = 2; for(unsigned j = 0; j < RankingCourses.size(); j++) if (!RankingCourses[j].CompareNoCase(m_pCourses[i]->m_sPath)) - m_pCourses[i]->SortOrder_Ranking = 1; + m_pCourses[i]->m_SortOrder_Ranking = 1; } } diff --git a/stepmania/src/SongUtil.cpp b/stepmania/src/SongUtil.cpp index ef11f8bf79..d974eacee0 100644 --- a/stepmania/src/SongUtil.cpp +++ b/stepmania/src/SongUtil.cpp @@ -118,13 +118,13 @@ void SongUtil::SortSongPointerArrayByDifficulty( vector &arraySongPointer bool CompareSongPointersByBPM(const Song *pSong1, const Song *pSong2) { - float fMinBPM1, fMaxBPM1, fMinBPM2, fMaxBPM2; - pSong1->GetDisplayBPM( fMinBPM1, fMaxBPM1 ); - pSong2->GetDisplayBPM( fMinBPM2, fMaxBPM2 ); + DisplayBpms bpms1, bpms2; + pSong1->GetDisplayBpms( bpms1 ); + pSong2->GetDisplayBpms( bpms2 ); - if( fMaxBPM1 < fMaxBPM2 ) + if( bpms1.GetMax() < bpms2.GetMax() ) return true; - if( fMaxBPM1 > fMaxBPM2 ) + if( bpms1.GetMax() > bpms2.GetMax() ) return false; return CompareCStringsAsc( pSong1->GetSongFilePath(), pSong2->GetSongFilePath() ); @@ -267,9 +267,9 @@ CString SongUtil::GetSectionNameFromSongAndSort( const Song* pSong, SortOrder so case SORT_BPM: { const int iBPMGroupSize = 20; - float fMinBPM, fMaxBPM; - pSong->GetDisplayBPM( fMinBPM, fMaxBPM ); - int iMaxBPM = (int)fMaxBPM; + DisplayBpms bpms; + pSong->GetDisplayBpms( bpms ); + int iMaxBPM = (int)bpms.GetMax(); iMaxBPM += iBPMGroupSize - (iMaxBPM%iBPMGroupSize) - 1; return ssprintf("%03d-%03d",iMaxBPM-(iBPMGroupSize-1), iMaxBPM); } diff --git a/stepmania/src/StepMania.dsp b/stepmania/src/StepMania.dsp index ab5786a0f8..e05229fdf6 100644 --- a/stepmania/src/StepMania.dsp +++ b/stepmania/src/StepMania.dsp @@ -65,7 +65,7 @@ IntDir=.\../Debug6 TargetDir=\stepmania\stepmania\Program TargetName=StepMania-debug SOURCE="$(InputPath)" -PreLink_Cmds=disasm\verinc cl /Zl /nologo /c verstub.cpp /Fo$(IntDir)\ +PreLink_Cmds=disasm\verinc cl /Zl /nologo /c verstub.cpp /Fo$(IntDir)\ PostBuild_Cmds=disasm\mapconv $(IntDir)\$(TargetName).map $(TargetDir)\StepMania.vdi # End Special Build Tool @@ -142,7 +142,7 @@ IntDir=.\../Release6 TargetDir=\stepmania\stepmania\Program TargetName=StepMania SOURCE="$(InputPath)" -PreLink_Cmds=disasm\verinc cl /Zl /nologo /c verstub.cpp /Fo$(IntDir)\ +PreLink_Cmds=disasm\verinc cl /Zl /nologo /c verstub.cpp /Fo$(IntDir)\ PostBuild_Cmds=disasm\mapconv $(IntDir)\$(TargetName).map $(TargetDir)\StepMania.vdi # End Special Build Tool @@ -1435,7 +1435,7 @@ SOURCE=.\FontCharmaps.h # End Source File # Begin Source File -SOURCE=.\ForeachEnum.h +SOURCE=.\Foreach.h # End Source File # Begin Source File @@ -2213,6 +2213,25 @@ SOURCE=.\TitleSubstitution.cpp SOURCE=.\TitleSubstitution.h # End Source File +# Begin Source File + +SOURCE=.\Trail.cpp + +!IF "$(CFG)" == "StepMania - Win32 Debug" + +!ELSEIF "$(CFG)" == "StepMania - Xbox Debug" + +!ELSEIF "$(CFG)" == "StepMania - Win32 Release" + +!ELSEIF "$(CFG)" == "StepMania - Xbox Release" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\Trail.h +# End Source File # End Group # Begin Group "File Types" diff --git a/stepmania/src/StepMania.vcproj b/stepmania/src/StepMania.vcproj index 8a65f8e185..56840908c0 100644 --- a/stepmania/src/StepMania.vcproj +++ b/stepmania/src/StepMania.vcproj @@ -122,7 +122,7 @@ cl /Zl /nologo /c verstub.cpp /Fo"$(IntDir)"\ + + + + pNotes; + ASSERT( pNotes ); + rv += pNotes->GetRadarValues(); + } + + return rv; +} + +float Trail::GetAverageMeter() const +{ + if( m_vEntries.empty() ) + return 0; + + return GetTotalMeter() / (float)m_vEntries.size(); +} + +int Trail::GetTotalMeter() const +{ + int iTotalMeter = 0; + FOREACH_CONST( TrailEntry, m_vEntries, e ) + { + iTotalMeter += e->pNotes->GetMeter(); + } + + return iTotalMeter; +} + +float Trail::GetLengthSeconds() const +{ + float fSecs = 0; + FOREACH_CONST( TrailEntry, m_vEntries, e ) + { + fSecs += e->pSong->m_fMusicLengthSeconds; + } + return fSecs; +} + +void Trail::GetDisplayBpms( DisplayBpms &AddTo ) +{ + FOREACH_CONST( TrailEntry, m_vEntries, e ) + { + if( e->bMystery ) + { + AddTo.Add( -1 ); + continue; + } + + Song *pSong = e->pSong; + ASSERT( pSong ); + switch( pSong->m_DisplayBPMType ) + { + case Song::DISPLAY_ACTUAL: + case Song::DISPLAY_SPECIFIED: + { + pSong->GetDisplayBpms( AddTo ); + } + break; + case Song::DISPLAY_RANDOM: + AddTo.Add( -1 ); + break; + default: + ASSERT(0); + } + } +} + diff --git a/stepmania/src/Trail.h b/stepmania/src/Trail.h new file mode 100644 index 0000000000..ab266daa2b --- /dev/null +++ b/stepmania/src/Trail.h @@ -0,0 +1,51 @@ +#ifndef Trail_H +#define Trail_H + +#include "Attack.h" + +class Song; +class Steps; + +struct TrailEntry +{ + TrailEntry(): + pSong(NULL), + pNotes(NULL), + bMystery(false), + iLowMeter(-1), + iHighMeter(-1) + { + } + void GetAttackArray( AttackArray &out ) const; + + Song* pSong; + Steps* pNotes; + CString Modifiers; + AttackArray Attacks; + bool bMystery; + int iLowMeter; + int iHighMeter; +}; + +class Trail +{ +public: + StepsType m_st; + CourseDifficulty m_cd; + vector m_vEntries; + + Trail() + { + m_st = STEPS_TYPE_INVALID; + m_cd = COURSE_DIFFICULTY_INVALID; + } + + RadarValues GetRadarValues() const; + float GetAverageMeter() const; + int GetTotalMeter() const; + float GetLengthSeconds() const; + void GetDisplayBpms( DisplayBpms &AddTo ); +}; + + +#endif diff --git a/stepmania/src/song.h b/stepmania/src/song.h index 06df00d02c..b1473b731a 100644 --- a/stepmania/src/song.h +++ b/stepmania/src/song.h @@ -168,7 +168,7 @@ public: void AddForegroundChange( BackgroundChange seg ); void AddLyricSegment( LyricSegment seg ); - void GetDisplayBPM( float &fMinBPMOut, float &fMaxBPMOut ) const; + void GetDisplayBpms( DisplayBpms &AddTo ) const; CString GetBackgroundAtBeat( float fBeat ) const; float GetBPMAtBeat( float fBeat ) const { return m_Timing.GetBPMAtBeat( fBeat ); }