Refactor.

Finding out which songs were random was broken: if a non-static
song (eg. player's best) was missing ("BEST99999"), m_entries
doesn't necessarily match one-to-one with the results of GetStageInfo.
This commit is contained in:
Glenn Maynard
2003-07-21 21:54:07 +00:00
parent bd10a6e212
commit 4106afb299
5 changed files with 114 additions and 156 deletions
+7 -8
View File
@@ -178,23 +178,22 @@ void BPMDisplay::SetBPM( const Song* pSong )
void BPMDisplay::SetBPM( const Course* pCourse )
{
ASSERT( pCourse );
vector<Song*> vSongs;
vector<Notes*> vNotes;
vector<CString> vsModifiers;
pCourse->GetStageInfo( vSongs, vNotes, vsModifiers, GAMESTATE->GetCurrentStyleDef()->m_NotesType );
ASSERT( vSongs.size() );
vector<Course::Info> ci;
pCourse->GetCourseInfo( GAMESTATE->GetCurrentStyleDef()->m_NotesType, ci );
ASSERT( ci.size() );
vector<float> BPMS;
for( unsigned i = 0; i < vSongs.size(); ++i )
for( unsigned i = 0; i < ci.size(); ++i )
{
if( pCourse->IsMysterySong(i) )
if( ci[i].Random )
{
BPMS.push_back( -1 );
continue;
}
Song *pSong = vSongs[i];
Song *pSong = ci[i].Song;
ASSERT( pSong );
switch( pSong->m_DisplayBPMType )
{
+76 -128
View File
@@ -370,82 +370,98 @@ void Course::AutogenNonstopFromGroup( CString sGroupName, vector<Song*> &apSongs
*/
bool Course::HasDifficult( NotesType nt ) const
{
if( ContainsAnyMysterySongs() )
{
for( unsigned i=0; i<m_entries.size(); i++ )
{
if( m_entries[i].type != Entry::random && m_entries[i].type != Entry::random_within_group )
continue;
/* CHALLENGE doesn't get any harder. */
if( m_entries[i].difficulty == DIFFICULTY_CHALLENGE )
continue;
/* 10..10 doesn't get any harder. */
if( m_entries[i].difficulty == DIFFICULTY_INVALID &&
m_entries[i].low_meter == MAX_BOTTOM_RANGE &&
m_entries[i].high_meter == MAX_BOTTOM_RANGE )
continue;
return true;
}
return false;
}
/* We don't have any random songs. Check to see if any songs would change
* if difficult. */
/* Check to see if any songs would change if difficult. */
const bool OldDifficulty = GAMESTATE->m_bDifficultCourses;
vector<Song*> vSongs, vHardSongs;
vector<Notes*> vNotes, vHardNotes;
vector<CString> vsIgnore;
vector<Info> Normal, Hard;
GAMESTATE->m_bDifficultCourses = false;
GetStageInfo( vSongs, vNotes, vsIgnore, nt );
GetCourseInfo( nt, Normal );
GAMESTATE->m_bDifficultCourses = true;
GetStageInfo( vHardSongs, vHardNotes, vsIgnore, nt );
GetCourseInfo( nt, Hard );
GAMESTATE->m_bDifficultCourses = OldDifficulty;
if( vSongs.size() != vHardSongs.size() )
if( Normal.size() != Hard.size() )
return true; /* it changed */
for( unsigned i=0; i<vSongs.size(); i++ )
if( vSongs[i] != vHardSongs[i] || vNotes[i] != vHardNotes[i] )
for( unsigned i=0; i<Normal.size(); i++ )
{
if( Normal[i].CourseIndex != Hard[i].CourseIndex )
return true; /* it changed */
if( Normal[i].Random )
{
const Entry &e = m_entries[ Normal[i].CourseIndex ];
/* Difficulties under CHALLENGE change by getting harder. */
if( e.difficulty < DIFFICULTY_CHALLENGE )
return true;
/* Meters under MAX_BOTTOM_RANGE..MAX_BOTTOM_RANGE change by getting harder. */
if( e.difficulty != DIFFICULTY_INVALID &&
e.low_meter < MAX_BOTTOM_RANGE &&
e.high_meter < MAX_BOTTOM_RANGE )
return true;
continue;
}
if( Normal[i].Song != Hard[i].Song || Normal[i].Notes != Hard[i].Notes )
return true;
}
return false;
}
bool Course::IsPlayableIn( NotesType nt ) const
{
/* XXX: Is this good enough? This needs to be guaranteed: if we say
* a course is playable and it's not, we'll crash in ScreenGameplay. */
vector<Song*> vSongs;
vector<Notes*> vNotes;
vector<CString> vsModifiers;
GetStageInfo( vSongs, vNotes, vsModifiers, nt);
return vNotes.size() > 0;
vector<Info> ci;
GetCourseInfo( nt, ci );
return ci.size() > 0;
}
void Course::GetStageInfo(
vector<Song*>& vSongsOut,
vector<Notes*>& vNotesOut,
vector<CString>& vsModifiersOut,
bool Course::GetFirstStageInfo(
Song*& pSongOut,
Notes*& pNotesOut,
CString& sModifiersOut,
NotesType nt ) const
{
vector<Info> ci;
GetCourseInfo( nt, ci );
if( ci.empty() )
return false;
pSongOut = ci[0].Song;
pNotesOut = ci[0].Notes;
sModifiersOut = ci[0].Modifiers;
return true;
}
void Course::GetCourseInfo( NotesType nt, vector<Course::Info> &ci ) const
{
vector<Entry> entries = m_entries;
if( m_bRandomize )
random_shuffle( entries.begin(), entries.end() );
vector<Song*> vSongsByMostPlayed;
vector<Song*> vSongsByMostPlayed = SONGMAN->GetBestSongs();
// filter out songs that don't have both medium and hard steps and long ver sons
for( int j=vSongsByMostPlayed.size()-1; j>=0; j-- )
{
Song* pSong = vSongsByMostPlayed[j];
if( pSong->m_fMusicLengthSeconds > PREFSMAN->m_fLongVerSongSeconds ||
pSong->m_fMusicLengthSeconds > PREFSMAN->m_fMarathonVerSongSeconds ||
!pSong->GetNotes(nt, DIFFICULTY_MEDIUM, PREFSMAN->m_bAutogenMissingTypes) ||
!pSong->GetNotes(nt, DIFFICULTY_HARD, PREFSMAN->m_bAutogenMissingTypes) )
vSongsByMostPlayed.erase( vSongsByMostPlayed.begin()+j );
}
vector<Song*> AllSongsShuffled = SONGMAN->GetAllSongs();
random_shuffle( AllSongsShuffled.begin(), AllSongsShuffled.end() );
int CurSong = 0; /* Current offset into AllSongsShuffled */
ci.clear();
for( unsigned i=0; i<entries.size(); i++ )
{
const Entry& e = entries[i];
@@ -500,26 +516,6 @@ void Course::GetStageInfo(
case Entry::best:
case Entry::worst:
{
if(vSongsByMostPlayed.size() == 0)
{
/* Probably the first time getting here; fill it in just once. */
/* XXX: This is still expensive enough to cause a noticable
* frame drop when scrolling over best/worst entries. */
vSongsByMostPlayed = SONGMAN->GetAllSongs();
SortSongPointerArrayByMostPlayed( vSongsByMostPlayed );
// filter out songs that don't have both medium and hard steps and long ver sons
for( int j=vSongsByMostPlayed.size()-1; j>=0; j-- )
{
Song* pSong = vSongsByMostPlayed[j];
if( pSong->m_fMusicLengthSeconds > PREFSMAN->m_fLongVerSongSeconds ||
pSong->m_fMusicLengthSeconds > PREFSMAN->m_fMarathonVerSongSeconds ||
!pSong->GetNotes(nt, DIFFICULTY_MEDIUM, PREFSMAN->m_bAutogenMissingTypes) ||
!pSong->GetNotes(nt, DIFFICULTY_HARD, PREFSMAN->m_bAutogenMissingTypes) )
vSongsByMostPlayed.erase( vSongsByMostPlayed.begin()+j );
}
}
if( e.players_index >= (int)vSongsByMostPlayed.size() )
break;
@@ -567,36 +563,13 @@ void Course::GetStageInfo(
}
}
vSongsOut.push_back( pSong );
vNotesOut.push_back( pNotes );
vsModifiersOut.push_back( e.modifiers );
Info cinfo;
cinfo.Song = pSong;
cinfo.Notes = pNotes;
cinfo.Modifiers = e.modifiers;
cinfo.Random = ( e.type == Entry::random || e.type == Entry::random_within_group );
ci.push_back( cinfo );
}
}
bool Course::GetFirstStageInfo(
Song*& pSongOut,
Notes*& pNotesOut,
CString& sModifiersOut,
NotesType nt ) const
{
vector<Song*> vSongs;
vector<Notes*> vNotes;
vector<CString> vsModifiers;
GetStageInfo(
vSongs,
vNotes,
vsModifiers,
nt );
if( vSongs.empty() )
return false;
pSongOut = vSongs[0];
pNotesOut = vNotes[0];
sModifiersOut = vsModifiers[0];
return true;
}
RageColor Course::GetColor() const
@@ -610,18 +583,6 @@ RageColor Course::GetColor() const
return RageColor(0,1,0,1); // green
}
bool Course::IsMysterySong( int stage ) const
{
switch( m_entries[stage].type )
{
case Entry::fixed: return false;
case Entry::random: return true;
case Entry::random_within_group: return true;
case Entry::best: return false;
case Entry::worst: return false;
default: ASSERT(0); return true;
}
}
Difficulty Course::GetDifficulty( int stage ) const
{
@@ -646,31 +607,18 @@ void Course::GetMeterRange( int stage, int& iMeterLowOut, int& iMeterHighOut ) c
}
}
bool Course::ContainsAnyMysterySongs() const
{
for( unsigned i=0; i<m_entries.size(); i++ )
if( IsMysterySong(i) )
return true;
return false;
}
bool Course::GetTotalSeconds( float& fSecondsOut ) const
{
if( ContainsAnyMysterySongs() )
return false;
vector<Song*> vSongsOut;
vector<Notes*> vNotesOut;
vector<CString> vsModifiersOut;
GetStageInfo(
vSongsOut,
vNotesOut,
vsModifiersOut,
NOTES_TYPE_DANCE_SINGLE ); // doesn't matter
vector<Info> ci;
GetCourseInfo( NOTES_TYPE_DANCE_SINGLE, ci );
fSecondsOut = 0;
for( unsigned i=0; i<vSongsOut.size(); i++ )
fSecondsOut += vSongsOut[i]->m_fMusicLengthSeconds;
for( unsigned i=0; i<ci.size(); i++ )
{
if( ci[i].Random )
return false;
fSecondsOut += ci[i].Song->m_fMusicLengthSeconds;
}
return true;
}
+14 -3
View File
@@ -59,10 +59,23 @@ public:
bool m_bDifficult; // only make something difficult once
int m_iLives; // -1 means use bar life meter
struct Info
{
Info(): Song(NULL), Notes(NULL), Random(false) { }
Song* Song;
Notes* Notes;
CString Modifiers;
bool Random;
/* Corresponding entry in m_entries: */
int CourseIndex;
};
// Dereferences course_entries and returns only the playable Songs and Notes
void GetCourseInfo( NotesType nt, vector<Info> &ci ) const;
int GetEstimatedNumStages() const { return m_entries.size(); }
bool HasDifficult( NotesType nt ) const;
bool IsPlayableIn( NotesType nt ) const;
void GetStageInfo( // Derefrences course_entries and returns only the playable Songs and Notes
void GetStageInfo(
vector<Song*>& vSongsOut,
vector<Notes*>& vNotesOut,
vector<CString>& vsModifiersOut,
@@ -73,10 +86,8 @@ public:
CString& sModifiersOut,
NotesType nt ) const;
RageColor GetColor() const;
bool IsMysterySong( int stage ) const;
Difficulty GetDifficulty( int stage ) const;
void GetMeterRange( int stage, int& iMeterLowOut, int& iMeterHighOut ) const;
bool ContainsAnyMysterySongs() const;
bool GetTotalSeconds( float& fSecondsOut ) const;
bool IsNonstop() const { return !m_bRepeat && m_iLives <= 0; } // use bar life meter
+7 -12
View File
@@ -54,32 +54,27 @@ void CourseContentsList::SetFromCourse( Course* pCourse )
m_iNumContents = 0;
vector<Song*> vSongs;
vector<Notes*> vNotes;
vector<CString> vsModifiers;
pCourse->GetStageInfo( vSongs, vNotes, vsModifiers, GAMESTATE->GetCurrentStyleDef()->m_NotesType );
vector<Course::Info> ci;
pCourse->GetCourseInfo( GAMESTATE->GetCurrentStyleDef()->m_NotesType, ci );
for( int i=0; i<min((int)vSongs.size(), MAX_TOTAL_CONTENTS); i++ )
for( int i=0; i<min((int)ci.size(), MAX_TOTAL_CONTENTS); i++ )
{
CourseEntryDisplay& display = m_CourseContentDisplays[m_iNumContents];
if( pCourse->IsMysterySong(i) )
if( ci[i].Random )
{
Difficulty dc = pCourse->GetDifficulty(i);
int iMeterLow, iMeterHigh;
pCourse->GetMeterRange(i, iMeterLow, iMeterHigh);
if( dc == DIFFICULTY_INVALID )
display.LoadFromMeterRange( m_iNumContents+1, iMeterLow, iMeterHigh, vsModifiers[i] );
display.LoadFromMeterRange( m_iNumContents+1, iMeterLow, iMeterHigh, ci[i].Modifiers );
else
display.LoadFromDifficulty( m_iNumContents+1, dc, vsModifiers[i] );
display.LoadFromDifficulty( m_iNumContents+1, dc, ci[i].Modifiers );
}
else
{
Song* pSong = vSongs[i];
Notes* pNotes = vNotes[i];
CString sModifiers = vsModifiers[i];
display.LoadFromSongAndNotes( m_iNumContents+1, pSong, pNotes, vsModifiers[i] );
display.LoadFromSongAndNotes( m_iNumContents+1, ci[i].Song, ci[i].Notes, ci[i].Modifiers );
}
m_iNumContents ++;
+10 -5
View File
@@ -145,12 +145,17 @@ ScreenGameplay::ScreenGameplay( bool bDemonstration ) : Screen("ScreenGameplay")
//
if( GAMESTATE->IsCourseMode() )
{
Course* pCourse = GAMESTATE->m_pCurCourse;
pCourse->GetStageInfo( m_apSongsQueue, m_apNotesQueue[0], m_asModifiersQueue[0], GAMESTATE->GetCurrentStyleDef()->m_NotesType );
for( int p=1; p<NUM_PLAYERS; p++ )
vector<Course::Info> ci;
GAMESTATE->m_pCurCourse->GetCourseInfo( GAMESTATE->GetCurrentStyleDef()->m_NotesType, ci );
for( int p=0; p<NUM_PLAYERS; p++ )
{
m_apNotesQueue[p] = m_apNotesQueue[0];
m_asModifiersQueue[p] = m_asModifiersQueue[0];
m_apNotesQueue[p].clear();
m_asModifiersQueue[p].clear();
for( unsigned c=0; c<ci.size(); ++c )
{
m_apNotesQueue[p].push_back( ci[c].Notes );
m_asModifiersQueue[p].push_back( ci[c].Modifiers );
}
}
}
else