refactor Course: move some responsibilities to Trail

This commit is contained in:
Chris Danford
2004-05-23 00:53:20 +00:00
parent 6ac93f463a
commit abfc956e4f
30 changed files with 479 additions and 472 deletions
+15 -45
View File
@@ -91,9 +91,11 @@ void BPMDisplay::Update( float fDeltaTime )
} }
void BPMDisplay::SetBPMRange( const vector<float> &BPMS ) void BPMDisplay::SetBPMRange( const DisplayBpms &bpms )
{ {
ASSERT( BPMS.size() ); ASSERT( !bpms.vfBpms.empty() );
const vector<float> &BPMS = bpms.vfBpms;
unsigned i; unsigned i;
bool AllIdentical = true; bool AllIdentical = true;
@@ -159,9 +161,9 @@ void BPMDisplay::SetBPMRange( const vector<float> &BPMS )
void BPMDisplay::CycleRandomly() void BPMDisplay::CycleRandomly()
{ {
vector<float> BPMS; DisplayBpms bpms;
BPMS.push_back(-1); bpms.Add(-1);
SetBPMRange( BPMS ); SetBPMRange( bpms );
m_fCycleTime = 0.2f; m_fCycleTime = 0.2f;
} }
@@ -183,12 +185,9 @@ void BPMDisplay::SetBPM( const Song* pSong )
case Song::DISPLAY_ACTUAL: case Song::DISPLAY_ACTUAL:
case Song::DISPLAY_SPECIFIED: case Song::DISPLAY_SPECIFIED:
{ {
float fMinBPM, fMaxBPM; DisplayBpms bpms;
pSong->GetDisplayBPM( fMinBPM, fMaxBPM ); pSong->GetDisplayBpms( bpms );
vector<float> BPMS; SetBPMRange( bpms );
BPMS.push_back(fMinBPM);
BPMS.push_back(fMaxBPM);
SetBPMRange( BPMS );
m_fCycleTime = 1.0f; m_fCycleTime = 1.0f;
} }
break; break;
@@ -204,43 +203,14 @@ void BPMDisplay::SetBPM( const Course* pCourse )
{ {
ASSERT( pCourse ); ASSERT( pCourse );
vector<Course::Info> ci; Trail *pTrail = pCourse->GetTrail( GAMESTATE->GetCurrentStyleDef()->m_StepsType, COURSE_DIFFICULTY_REGULAR );
pCourse->GetCourseInfo( GAMESTATE->GetCurrentStyleDef()->m_StepsType, ci );
ASSERT( ci.size() ); ASSERT( pTrail->m_vEntries.size() );
vector<float> BPMS; DisplayBpms bpms;
for( unsigned i = 0; i < ci.size(); ++i ) pTrail->GetDisplayBpms( bpms );
{
if( ci[i].Mystery )
{
BPMS.push_back( -1 );
continue;
}
Song *pSong = ci[i].pSong; SetBPMRange( bpms );
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);
}
}
SetBPMRange( BPMS );
m_fCycleTime = 0.2f; m_fCycleTime = 0.2f;
} }
+1 -1
View File
@@ -34,7 +34,7 @@ public:
protected: protected:
float GetActiveBPM() const; float GetActiveBPM() const;
void SetBPMRange( const vector<float> &m_BPMS ); void SetBPMRange( const DisplayBpms &bpms );
BitmapText m_textBPM; BitmapText m_textBPM;
AutoActor m_sprLabel; AutoActor m_sprLabel;
+73 -194
View File
@@ -15,6 +15,7 @@
#include "song.h" #include "song.h"
#include "GameManager.h" #include "GameManager.h"
#include "SongManager.h" #include "SongManager.h"
#include "GameState.h"
#include "RageException.h" #include "RageException.h"
#include "RageLog.h" #include "RageLog.h"
#include "MsdFile.h" #include "MsdFile.h"
@@ -23,7 +24,6 @@
#include "RageUtil.h" #include "RageUtil.h"
#include "TitleSubstitution.h" #include "TitleSubstitution.h"
#include "Steps.h" #include "Steps.h"
#include "GameState.h"
#include "BannerCache.h" #include "BannerCache.h"
#include "RageFile.h" #include "RageFile.h"
#include "arch/arch.h" #include "arch/arch.h"
@@ -40,7 +40,7 @@ const int MAX_BOTTOM_RANGE = 10;
Course::Course() Course::Course()
{ {
Unload(); Init();
} }
PlayMode Course::GetPlayMode() const PlayMode Course::GetPlayMode() const
@@ -50,60 +50,11 @@ PlayMode Course::GetPlayMode() const
return m_iLives > 0? PLAY_MODE_ONI:PLAY_MODE_NONSTOP; 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<Info> 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 ) void Course::LoadFromCRSFile( CString sPath )
{ {
LOG->Trace( "Course::LoadFromCRSFile( '%s' )", sPath.c_str() ); LOG->Trace( "Course::LoadFromCRSFile( '%s' )", sPath.c_str() );
Unload(); Init();
m_sPath = sPath; // save path m_sPath = sPath; // save path
@@ -152,7 +103,7 @@ void Course::LoadFromCRSFile( CString sPath )
else if( 0 == stricmp(sValueName, "METER") ) else if( 0 == stricmp(sValueName, "METER") )
{ {
if( sParams.params.size() == 2 ) 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 ) else if( sParams.params.size() == 3 )
{ {
const CourseDifficulty cd = StringToCourseDifficulty( sParams[1] ); const CourseDifficulty cd = StringToCourseDifficulty( sParams[1] );
@@ -162,7 +113,7 @@ void Course::LoadFromCRSFile( CString sPath )
m_sPath.c_str(), sParams[1].c_str() ); m_sPath.c_str(), sParams[1].c_str() );
continue; 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); ignore, ignore, ignore);
} }
void Course::Unload() void Course::Init()
{ {
m_bIsAutogen = false; m_bIsAutogen = false;
m_bRepeat = false; m_bRepeat = false;
m_bRandomize = false; m_bRandomize = false;
m_iLives = -1; m_iLives = -1;
m_iMeter[0] = m_iMeter[1] = -1; ZERO( m_iCustomMeter );
m_entries.clear(); m_entries.clear();
m_sPath = m_sName = m_sTranslitName = m_sBannerPath = m_sCDTitlePath = ""; m_sPath = m_sName = m_sTranslitName = m_sBannerPath = m_sCDTitlePath = "";
} }
@@ -343,9 +294,9 @@ void Course::Save()
f.PutLine( ssprintf("#LIVES:%i;", m_iLives) ); f.PutLine( ssprintf("#LIVES:%i;", m_iLives) );
FOREACH_CourseDifficulty( cd ) FOREACH_CourseDifficulty( cd )
{ {
if( m_iMeter[cd] == -1 ) if( m_iCustomMeter[cd] == -1 )
continue; 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<m_entries.size(); i++ ) for( unsigned i=0; i<m_entries.size(); i++ )
@@ -435,7 +386,7 @@ void Course::AutogenEndlessFromGroup( CString sGroupName, Difficulty diff )
m_bRepeat = true; m_bRepeat = true;
m_bRandomize = true; m_bRandomize = true;
m_iLives = -1; m_iLives = -1;
m_iMeter[0] = m_iMeter[1] = -1; m_iCustomMeter[0] = m_iCustomMeter[1] = -1;
if( sGroupName == "" ) if( sGroupName == "" )
{ {
@@ -502,58 +453,20 @@ bool Course::HasCourseDifficulty( StepsType nt, CourseDifficulty cd ) const
{ {
/* Check to see if any songs would change if difficult. */ /* Check to see if any songs would change if difficult. */
/* COURSE_DIFFICULTY_REGULAR is always available (provided IsPlayableIn). */ /* COURSE_DIFFICULTY_REGULAR is always available (if IsPlayableIn == true). */
if( cd == COURSE_DIFFICULTY_REGULAR ) if( cd == COURSE_DIFFICULTY_REGULAR )
return true; return true;
vector<Info> Normal, Hard; Trail *Regular = GetTrail( nt, COURSE_DIFFICULTY_REGULAR );
GetCourseInfo( nt, Normal, COURSE_DIFFICULTY_REGULAR ); Trail *Other = GetTrail( nt, cd );
GetCourseInfo( nt, Hard, cd );
if( Normal.size() != Hard.size() ) return Regular != Other;
return true; /* it changed */
for( unsigned i=0; i<Normal.size(); i++ )
{
if( Normal[i].CourseIndex != Hard[i].CourseIndex )
return true; /* it changed */
if( Normal[i].Mystery )
{
const CourseEntry &e = m_entries[ Normal[i].CourseIndex ];
if( e.difficulty != DIFFICULTY_INVALID )
{
/* Check if the song's difficulty class will actually change. */
Difficulty dc = (Difficulty) (e.difficulty + COURSE_DIFFICULTY_CLASS_CHANGE[cd]);
dc = clamp( dc, DIFFICULTY_BEGINNER, DIFFICULTY_CHALLENGE );
if( dc != e.difficulty )
return true;
}
/* Meters under MAX_BOTTOM_RANGE..MAX_BOTTOM_RANGE change by getting harder. */
if( e.difficulty == DIFFICULTY_INVALID )
{
/* Check if the meter will actually change. */
int iNewLowMeter = clamp( 1, e.low_meter + COURSE_DIFFICULTY_METER_CHANGE[cd], MAX_BOTTOM_RANGE );
int iNewHighMeter = clamp( 1, e.high_meter + COURSE_DIFFICULTY_METER_CHANGE[cd], MAX_BOTTOM_RANGE );
if( iNewLowMeter != e.low_meter || iNewHighMeter != e.high_meter )
return true;
}
continue;
}
if( Normal[i].pSong != Hard[i].pSong || Normal[i].pNotes != Hard[i].pNotes )
return true;
}
return false;
} }
bool Course::IsPlayableIn( StepsType nt ) const bool Course::IsPlayableIn( StepsType nt ) const
{ {
vector<Info> ci; Trail* pTrail = GetTrail( nt, COURSE_DIFFICULTY_REGULAR );
GetCourseInfo( nt, ci ); return !pTrail->m_vEntries.empty();
return ci.size() > 0;
} }
static vector<Song*> GetFilteredBestSongs( StepsType nt ) static vector<Song*> GetFilteredBestSongs( StepsType nt )
@@ -597,16 +510,22 @@ static vector<Song*> GetFilteredBestSongs( StepsType nt )
/* This is called by many simple functions, like Course::GetTotalSeconds, and may /* 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 * be called on all songs to sort. It can take time to execute, so we cache the
* results. */ * results. */
void Course::GetCourseInfo( StepsType nt, vector<Course::Info> &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 ); // Look in the Trail cache
if( it != m_InfoCache.end() ) //
const TrailParams params( nt, cd );
TrailCache::iterator it = m_TrailCache.find( params );
if( it != m_TrailCache.end() )
{ {
ci = it->second; return &it->second;
return;
} }
//
// Construct a new Trail, add it to the cache, then return it.
//
/* Different seed for each course, but the same for the whole round: */ /* Different seed for each course, but the same for the whole round: */
RandomGen rnd( GAMESTATE->m_iRoundSeed + GetHashForString(m_sName) ); RandomGen rnd( GAMESTATE->m_iRoundSeed + GetHashForString(m_sName) );
@@ -630,7 +549,8 @@ void Course::GetCourseInfo( StepsType nt, vector<Course::Info> &ci, CourseDiffic
vector<Song*> AllSongsShuffled; vector<Song*> AllSongsShuffled;
int CurSong = 0; /* Current offset into AllSongsShuffled */ int CurSong = 0; /* Current offset into AllSongsShuffled */
ci.clear();
Trail trail;
for( unsigned i=0; i<entries.size(); i++ ) for( unsigned i=0; i<entries.size(); i++ )
{ {
@@ -754,20 +674,20 @@ void Course::GetCourseInfo( StepsType nt, vector<Course::Info> &ci, CourseDiffic
} }
} }
Info cinfo; TrailEntry te;
cinfo.pSong = pSong; te.pSong = pSong;
cinfo.pNotes = pNotes; te.pNotes = pNotes;
cinfo.Modifiers = e.modifiers; te.Modifiers = e.modifiers;
cinfo.Attacks = e.attacks; te.Attacks = e.attacks;
cinfo.Random = ( e.type == COURSE_ENTRY_RANDOM || e.type == COURSE_ENTRY_RANDOM_WITHIN_GROUP ); te.bMystery = e.mystery;
cinfo.Mystery = e.mystery; te.iLowMeter = low_meter;
cinfo.CourseIndex = i; te.iHighMeter = high_meter;
cinfo.Difficulty = entry_difficulty; trail.m_vEntries.push_back( te );
ci.push_back( cinfo );
} }
/* Cache results. */ /* Cache results. */
m_InfoCache[params] = ci; m_TrailCache[params] = trail;
return &m_TrailCache[params];
} }
bool Course::HasMods() const bool Course::HasMods() const
@@ -793,11 +713,14 @@ bool Course::AllSongsAreFixed() const
void Course::ClearCache() void Course::ClearCache()
{ {
m_InfoCache.clear(); m_TrailCache.clear();
} }
RageColor Course::GetColor() const RageColor Course::GetColor() const
{ {
// FIXME: These colors shouldn't be hard-coded
int iMeter = 5;
switch (PREFSMAN->m_iCourseSortOrder) switch (PREFSMAN->m_iCourseSortOrder)
{ {
case PrefsManager::COURSE_SORT_SONGS: case PrefsManager::COURSE_SORT_SONGS:
@@ -813,31 +736,31 @@ RageColor Course::GetColor() const
case PrefsManager::COURSE_SORT_METER: case PrefsManager::COURSE_SORT_METER:
if ( !IsFixed() ) if ( !IsFixed() )
return RageColor(0,0,1,1); // blue return RageColor(0,0,1,1); // blue
if (GetMeter() > 8.5) if (iMeter > 8.5)
return RageColor(1,0,0,1); // red return RageColor(1,0,0,1); // red
if (GetMeter() >= 7) if (iMeter >= 7)
return RageColor(1,0.5f,0,1); // orange return RageColor(1,0.5f,0,1); // orange
if (GetMeter() >= 5) if (iMeter >= 5)
return RageColor(1,1,0,1); // yellow return RageColor(1,1,0,1); // yellow
return RageColor(0,1,0,1); // green return RageColor(0,1,0,1); // green
case PrefsManager::COURSE_SORT_METER_SUM: case PrefsManager::COURSE_SORT_METER_SUM:
if ( !IsFixed() ) if ( !IsFixed() )
return RageColor(0,0,1,1); // blue return RageColor(0,0,1,1); // blue
if (SortOrder_TotalDifficulty >= 40) if (m_SortOrder_TotalDifficulty >= 40)
return RageColor(1,0,0,1); // red return RageColor(1,0,0,1); // red
if (SortOrder_TotalDifficulty >= 30) if (m_SortOrder_TotalDifficulty >= 30)
return RageColor(1,0.5f,0,1); // orange 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(1,1,0,1); // yellow
return RageColor(0,1,0,1); // green return RageColor(0,1,0,1); // green
case PrefsManager::COURSE_SORT_RANK: case PrefsManager::COURSE_SORT_RANK:
if (SortOrder_Ranking == 3) if (m_SortOrder_Ranking == 3)
return RageColor(0,0,1,1); // blue return RageColor(0,0,1,1); // blue
if (SortOrder_Ranking == 2) if (m_SortOrder_Ranking == 2)
return RageColor(1,0.5f,0,1); // orange 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(0,1,0,1); // green
return RageColor(1,1,0,1); // yellow, never should get here return RageColor(1,1,0,1); // yellow, never should get here
default: default:
@@ -859,14 +782,6 @@ bool Course::IsFixed() const
return true; 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 void Course::GetMeterRange( int stage, int& iMeterLowOut, int& iMeterHighOut, CourseDifficulty cd ) const
{ {
iMeterLowOut = m_entries[stage].low_meter; 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() )
}
bool Course::GetTotalSeconds( float& fSecondsOut ) const
{
vector<Info> ci;
GetCourseInfo( STEPS_TYPE_DANCE_SINGLE, ci );
fSecondsOut = 0;
for( unsigned i=0; i<ci.size(); i++ )
{
if( ci[i].Mystery )
return false; return false;
fSecondsOut += ci[i].pSong->m_fMusicLengthSeconds;
} Trail* pTrail = GetTrail( st, COURSE_DIFFICULTY_REGULAR );
fSecondsOut = pTrail->GetLengthSeconds();
return true; return true;
} }
@@ -918,9 +824,9 @@ bool Course::HasBanner() const
return m_sBannerPath != "" && IsAFile(m_sBannerPath); return m_sBannerPath != "" && IsAFile(m_sBannerPath);
} }
void Course::UpdateCourseStats() void Course::UpdateCourseStats( StepsType st )
{ {
SortOrder_TotalDifficulty = 0; m_SortOrder_TotalDifficulty = 0;
unsigned i; unsigned i;
@@ -930,17 +836,15 @@ void Course::UpdateCourseStats()
if ( m_entries[i].type == COURSE_ENTRY_FIXED ) if ( m_entries[i].type == COURSE_ENTRY_FIXED )
continue; continue;
if ( SortOrder_Ranking == 2 ) if ( m_SortOrder_Ranking == 2 )
SortOrder_Ranking = 3; m_SortOrder_Ranking = 3;
SortOrder_TotalDifficulty = 999999; // large number m_SortOrder_TotalDifficulty = 999999; // large number
return; return;
} }
vector<Info> ci; Trail* pTrail = GetTrail( st, COURSE_DIFFICULTY_REGULAR );
GetCourseInfo( GAMESTATE->GetCurrentStyleDef()->m_StepsType, ci );
for( i = 0; i < ci.size(); i++ ) m_SortOrder_TotalDifficulty += pTrail->GetTotalMeter();
SortOrder_TotalDifficulty += ci[i].pNotes->GetMeter();
// OPTIMIZATION: Ranking info isn't dependant on style, so // OPTIMIZATION: Ranking info isn't dependant on style, so
// call it sparingly. Its handled on startup and when // call it sparingly. Its handled on startup and when
@@ -948,23 +852,7 @@ void Course::UpdateCourseStats()
LOG->Trace("%s: Total feet: %d", LOG->Trace("%s: Total feet: %d",
this->m_sName.c_str(), this->m_sName.c_str(),
SortOrder_TotalDifficulty ); m_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() );
} }
bool Course::IsRanking() const bool Course::IsRanking() const
@@ -980,20 +868,11 @@ bool Course::IsRanking() const
return false; return false;
} }
float Course::GetMeter( StepsType nt, CourseDifficulty cd ) const
RadarValues Course::GetRadarValues( StepsType st, 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<Course::Info> ci; return roundf( GetTrail(nt,cd)->GetAverageMeter() );
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;
} }
+12 -32
View File
@@ -15,6 +15,7 @@
#include "GameConstantsAndTypes.h" #include "GameConstantsAndTypes.h"
#include "Attack.h" #include "Attack.h"
#include <map> #include <map>
#include "Trail.h"
struct PlayerOptions; struct PlayerOptions;
struct SongOptions; struct SongOptions;
@@ -93,28 +94,14 @@ public:
bool m_bRepeat; // repeat after last song? "Endless" bool m_bRepeat; // repeat after last song? "Endless"
bool m_bRandomize; // play the songs in a random order bool m_bRandomize; // play the songs in a random order
int m_iLives; // -1 means use bar life meter 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<CourseEntry> m_entries; vector<CourseEntry> 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 // Dereferences course_entries and returns only the playable Songs and Steps
void GetCourseInfo( StepsType nt, vector<Info> &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 HasMods() const;
bool AllSongsAreFixed() const; bool AllSongsAreFixed() const;
@@ -123,33 +110,27 @@ public:
bool IsPlayableIn( StepsType nt ) const; bool IsPlayableIn( StepsType nt ) const;
bool CourseHasBestOrWorst() const; bool CourseHasBestOrWorst() const;
RageColor GetColor() const; RageColor GetColor() const;
Difficulty GetDifficulty( const Info &stage ) const; bool GetTotalSeconds( StepsType st, float& fSecondsOut ) const;
void GetMeterRange( const Info &stage, int& iMeterLowOut, int& iMeterHighOut ) const;
bool GetTotalSeconds( float& fSecondsOut ) const;
bool IsNonstop() const { return GetPlayMode() == PLAY_MODE_NONSTOP; } bool IsNonstop() const { return GetPlayMode() == PLAY_MODE_NONSTOP; }
bool IsOni() const { return GetPlayMode() == PLAY_MODE_ONI; } bool IsOni() const { return GetPlayMode() == PLAY_MODE_ONI; }
bool IsEndless() const { return GetPlayMode() == PLAY_MODE_ENDLESS; } bool IsEndless() const { return GetPlayMode() == PLAY_MODE_ENDLESS; }
PlayMode GetPlayMode() const; PlayMode GetPlayMode() const;
float GetMeter( CourseDifficulty cd = COURSE_DIFFICULTY_REGULAR ) const;
float GetMeterForPlayer( PlayerNumber pn ) const;
bool IsFixed() const; bool IsFixed() const;
void LoadFromCRSFile( CString sPath ); void LoadFromCRSFile( CString sPath );
void Unload(); void Init();
void Save(); void Save();
void AutogenEndlessFromGroup( CString sGroupName, Difficulty diff ); void AutogenEndlessFromGroup( CString sGroupName, Difficulty diff );
void AutogenNonstopFromGroup( CString sGroupName, Difficulty diff ); void AutogenNonstopFromGroup( CString sGroupName, Difficulty diff );
RadarValues GetRadarValues( StepsType st, CourseDifficulty cd ) const;
// sorting values // sorting values
int SortOrder_TotalDifficulty; int m_SortOrder_TotalDifficulty;
int SortOrder_Ranking; int m_SortOrder_Ranking;
bool IsRanking() const; bool IsRanking() const;
void UpdateCourseStats(); void UpdateCourseStats( StepsType st );
/* Call per-screen, and if song or notes pointers change: */ /* Call per-screen, and if song or notes pointers change: */
void ClearCache(); void ClearCache();
@@ -158,10 +139,9 @@ private:
CString GetAutogenDifficultySuffix( Difficulty diff ) const; CString GetAutogenDifficultySuffix( Difficulty diff ) const;
void GetMeterRange( int stage, int& iMeterLowOut, int& iMeterHighOut, CourseDifficulty cd ) const; void GetMeterRange( int stage, int& iMeterLowOut, int& iMeterHighOut, CourseDifficulty cd ) const;
typedef pair<StepsType,CourseDifficulty> InfoParams; typedef pair<StepsType,CourseDifficulty> TrailParams;
typedef vector<Info> InfoData; typedef map<TrailParams, Trail> TrailCache;
typedef map<InfoParams, InfoData> InfoCache; mutable TrailCache m_TrailCache;
mutable InfoCache m_InfoCache;
}; };
#endif #endif
+14 -6
View File
@@ -56,17 +56,25 @@ void CourseContentsList::SetFromCourse( const Course* pCourse )
return; return;
} }
vector<Course::Info> ci[NUM_PLAYERS]; Trail* pTrail[NUM_PLAYERS];
for( int pn = 0; pn < NUM_PLAYERS; ++pn ) FOREACH_PlayerNumber(pn)
pCourse->GetCourseInfo( GAMESTATE->GetCurrentStyleDef()->m_StepsType, ci[pn], GAMESTATE->m_PreferredCourseDifficulty[pn] ); {
pTrail[pn] = pCourse->GetTrail( GAMESTATE->GetCurrentStyleDef()->m_StepsType, GAMESTATE->m_PreferredCourseDifficulty[pn] );
}
// FIXME: Is there a better way to handle when players don't have
// the same number of TrailEntries?
m_iNumContents = 0; m_iNumContents = 0;
for( int i=0; i<min((int)ci[0].size(), MAX_TOTAL_CONTENTS); i++ )
for( int i=0; i<min((int)pTrail[0]->m_vEntries.size(), MAX_TOTAL_CONTENTS); i++ )
{ {
CourseEntryDisplay& display = m_CourseContentDisplays[m_iNumContents]; CourseEntryDisplay& display = m_CourseContentDisplays[m_iNumContents];
const Course::Info pci[NUM_PLAYERS] = { ci[0][i], ci[1][i] }; TrailEntry* pte[NUM_PLAYERS];
display.LoadFromCourseInfo( m_iNumContents+1, pCourse, pci ); FOREACH_EnabledPlayer(pn)
pte[pn] = &pTrail[0]->m_vEntries[i];
display.LoadFromTrailEntry( m_iNumContents+1, pCourse, pte );
m_iNumContents++; m_iNumContents++;
} }
+18 -17
View File
@@ -87,24 +87,24 @@ void CourseEntryDisplay::SetDifficulty( PlayerNumber pn, const CString &text, Ra
m_textFoot[pn].SetDiffuse( c ); 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]; TrailEntry *te = tes[GAMESTATE->m_MasterPlayerNumber];
bool bMystery = te->bMystery;
if( ci.Mystery ) 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 ) if( dc == DIFFICULTY_INVALID )
{ {
int iLow, iHigh; int iLow = te->iLowMeter;
pCourse->GetMeterRange(pci[pn], iLow, iHigh); int iHigh = te->iHighMeter;
SetDifficulty( pn, ssprintf(iLow==iHigh?"%d":"%d-%d", iLow, iHigh), RageColor(1,1,1,1) );
SetDifficulty( (PlayerNumber)pn, ssprintf(iLow==iHigh?"%d":"%d-%d", iLow, iHigh), RageColor(1,1,1,1) );
} }
else else
SetDifficulty( (PlayerNumber)pn, "?", SONGMAN->GetDifficultyColor( dc ) ); SetDifficulty( pn, "?", SONGMAN->GetDifficultyColor( dc ) );
} }
m_TextBanner.LoadFromString( "??????????", "??????????", "", "", "", "" ); m_TextBanner.LoadFromString( "??????????", "??????????", "", "", "", "" );
@@ -112,17 +112,18 @@ void CourseEntryDisplay::LoadFromCourseInfo( int iNum, const Course *pCourse, co
} }
else else
{ {
for( int pn = 0; pn < NUM_PLAYERS; ++pn ) FOREACH_EnabledPlayer(pn)
{ {
RageColor colorNotes = SONGMAN->GetDifficultyColor( pci[pn].pNotes->GetDifficulty() ); TrailEntry *te = tes[pn];
SetDifficulty( (PlayerNumber)pn, ssprintf("%d", pci[pn].pNotes->GetMeter()), colorNotes ); RageColor colorNotes = SONGMAN->GetDifficultyColor( te->pNotes->GetDifficulty() );
SetDifficulty( pn, ssprintf("%d", te->pNotes->GetMeter()), colorNotes );
} }
m_TextBanner.LoadFromSong( ci.pSong ); m_TextBanner.LoadFromSong( te->pSong );
m_TextBanner.SetDiffuse( SONGMAN->GetSongColor( ci.pSong ) ); m_TextBanner.SetDiffuse( SONGMAN->GetSongColor( te->pSong ) );
} }
m_textNumber.SetText( ssprintf("%d", iNum) ); m_textNumber.SetText( ssprintf("%d", iNum) );
m_textModifiers.SetText( ci.Modifiers ); m_textModifiers.SetText( te->Modifiers );
} }
+1 -1
View File
@@ -28,7 +28,7 @@ class CourseEntryDisplay : public ActorFrame
public: public:
void Load(); 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: private:
void SetDifficulty( PlayerNumber pn, const CString &text, RageColor c ); void SetDifficulty( PlayerNumber pn, const CString &text, RageColor c );
+9 -7
View File
@@ -16,6 +16,8 @@
#include "ProfileManager.h" #include "ProfileManager.h"
#include "SongManager.h" #include "SongManager.h"
#include "XmlFile.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) static bool CompareCoursePointersByTotalDifficulty(const Course* pCourse1, const Course* pCourse2)
{ {
int iNum1 = pCourse1->SortOrder_TotalDifficulty; int iNum1 = pCourse1->m_SortOrder_TotalDifficulty;
int iNum2 = pCourse2->SortOrder_TotalDifficulty; int iNum2 = pCourse2->m_SortOrder_TotalDifficulty;
if( iNum1 == iNum2 ) if( iNum1 == iNum2 )
return CompareCoursePointersByAutogen( pCourse1, pCourse2 ); 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) static bool CompareCoursePointersByRanking(const Course* pCourse1, const Course* pCourse2)
{ {
int iNum1 = pCourse1->SortOrder_Ranking; int iNum1 = pCourse1->m_SortOrder_Ranking;
int iNum2 = pCourse2->SortOrder_Ranking; int iNum2 = pCourse2->m_SortOrder_Ranking;
if( iNum1 == iNum2 ) if( iNum1 == iNum2 )
return CompareCoursePointersByAutogen( pCourse1, pCourse2 ); return CompareCoursePointersByAutogen( pCourse1, pCourse2 );
@@ -109,14 +111,14 @@ void CourseUtil::SortCoursePointerArrayByDifficulty( vector<Course*> &apCourses
void CourseUtil::SortCoursePointerArrayByRanking( vector<Course*> &apCourses ) void CourseUtil::SortCoursePointerArrayByRanking( vector<Course*> &apCourses )
{ {
for(unsigned i=0; i<apCourses.size(); i++) for(unsigned i=0; i<apCourses.size(); i++)
apCourses[i]->UpdateCourseStats(); apCourses[i]->UpdateCourseStats( GAMESTATE->GetCurrentStyleDef()->m_StepsType );
sort( apCourses.begin(), apCourses.end(), CompareCoursePointersByRanking ); sort( apCourses.begin(), apCourses.end(), CompareCoursePointersByRanking );
} }
void CourseUtil::SortCoursePointerArrayByTotalDifficulty( vector<Course*> &apCourses ) void CourseUtil::SortCoursePointerArrayByTotalDifficulty( vector<Course*> &apCourses )
{ {
for(unsigned i=0; i<apCourses.size(); i++) for(unsigned i=0; i<apCourses.size(); i++)
apCourses[i]->UpdateCourseStats(); apCourses[i]->UpdateCourseStats( GAMESTATE->GetCurrentStyleDef()->m_StepsType );
sort( apCourses.begin(), apCourses.end(), CompareCoursePointersByTotalDifficulty ); sort( apCourses.begin(), apCourses.end(), CompareCoursePointersByTotalDifficulty );
} }
@@ -157,7 +159,7 @@ void CourseUtil::SortCoursePointerArrayByAvgDifficulty( vector<Course*> &apCours
RageTimer foo; RageTimer foo;
course_sort_val.clear(); course_sort_val.clear();
for(unsigned i = 0; i < apCourses.size(); ++i) 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 ); sort( apCourses.begin(), apCourses.end(), CompareCoursePointersByTitle );
stable_sort( apCourses.begin(), apCourses.end(), CompareCoursePointersBySortValueAscending ); stable_sort( apCourses.begin(), apCourses.end(), CompareCoursePointersBySortValueAscending );
+4 -1
View File
@@ -20,6 +20,7 @@
#include "Course.h" #include "Course.h"
#include "SongManager.h" #include "SongManager.h"
#include "ActorUtil.h" #include "ActorUtil.h"
#include "StyleDef.h"
#define NUM_FEET_IN_METER THEME->GetMetricI(m_sName,"NumFeetInMeter") #define NUM_FEET_IN_METER THEME->GetMetricI(m_sName,"NumFeetInMeter")
@@ -117,7 +118,9 @@ void DifficultyMeter::SetFromCourse( const Course* pCourse, PlayerNumber pn )
return; 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 // XXX metrics
Difficulty FakeDifficulty; Difficulty FakeDifficulty;
-54
View File
@@ -33,58 +33,4 @@ static const CString EMPTY_STRING;
return (X)(i+1); /*invalid*/ \ 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<NUM; } \
CCStringRef ToString() const { ASSERT(IsValid()); return GetString(m_value); } \
CString ToThemedString() const { return GetThemedString(#name,ToString()); } \
void FromString( CString s ) \
{ \
for( int i=0; i<NUM; i++ ) \
{ \
if( stricmp(s,GetString(i))==0 ) \
{ \
m_value = (Value)i; \
return; \
} \
} \
MakeInvalid(); \
} \
}; \
#define FOREACH( name, var ) for( name var(0); (int)var<(int)name::NUM; var++ )
CString GetThemedString( CCStringRef sClass, CCStringRef sValue );
#endif #endif
+9
View File
@@ -0,0 +1,9 @@
#ifndef Foreach_H
#define Foreach_H
#define FOREACH( elemType, vect, var ) for( vector<elemType>::iterator var = vect.begin(); var != vect.end(); var++ )
#define FOREACH_CONST( elemType, vect, var ) for( vector<elemType>::const_iterator var = vect.begin(); var != vect.end(); var++ )
#endif
+47
View File
@@ -15,6 +15,7 @@
#include "RageUtil.h" #include "RageUtil.h"
#include "ThemeManager.h" #include "ThemeManager.h"
#include "EnumHelper.h" #include "EnumHelper.h"
#include "Foreach.h"
static const CString RadarCategoryNames[NUM_RADAR_CATEGORIES] = { static const CString RadarCategoryNames[NUM_RADAR_CATEGORIES] = {
@@ -170,3 +171,49 @@ LuaFunction_Str( StringTo##X, LuaStringTo##X(str) ); /* register it */
LuaXToString( Difficulty ); LuaXToString( Difficulty );
LuaStringToX( 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;
}
+10
View File
@@ -363,4 +363,14 @@ CString PeakComboAwardToThemedString( PeakComboAward pma );
PeakComboAward StringToPeakComboAward( const CString& pma ); PeakComboAward StringToPeakComboAward( const CString& pma );
struct DisplayBpms
{
void Add( float f );
float GetMin();
float GetMax();
bool BpmIsConstant();
bool IsMystery();
vector<float> vfBpms;
};
#endif #endif
+2 -1
View File
@@ -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 \ 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 \ 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 \ 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 \ FileTypes = IniFile.cpp IniFile.h \
MsdFile.cpp MsdFile.h \ MsdFile.cpp MsdFile.h \
+1 -2
View File
@@ -157,10 +157,9 @@ void PaneDisplay::SetContent( PaneContents c )
rv = GAMESTATE->m_pCurNotes[m_PlayerNumber]->GetRadarValues(); rv = GAMESTATE->m_pCurNotes[m_PlayerNumber]->GetRadarValues();
else if( g_Contents[c].req&NEED_COURSE ) else if( g_Contents[c].req&NEED_COURSE )
{ {
vector<Course::Info> ci;
CourseDifficulty cd = GAMESTATE->m_PreferredCourseDifficulty[m_PlayerNumber]; CourseDifficulty cd = GAMESTATE->m_PreferredCourseDifficulty[m_PlayerNumber];
StepsType st = GAMESTATE->GetCurrentStyleDef()->m_StepsType; 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; const Song *pSong = GAMESTATE->m_pCurSong;
+4 -5
View File
@@ -21,6 +21,7 @@
#include "Course.h" #include "Course.h"
#include "Steps.h" #include "Steps.h"
#include "ThemeManager.h" #include "ThemeManager.h"
#include "Foreach.h"
#define ONE( arr ) { for( unsigned Z = 0; Z < ARRAYSIZE(arr); ++Z ) arr[Z]=1.0f; } #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 ) bool PlayerOptions::IsEasierForCourse( Course* pCourse, StepsType st, CourseDifficulty cd )
{ {
vector<Course::Info> ci; Trail *pTrail = pCourse->GetTrail( st, cd );
pCourse->GetCourseInfo( st, ci, cd );
for( unsigned i=0; i<ci.size(); i++ ) FOREACH_CONST( TrailEntry, pTrail->m_vEntries, e )
{ {
const Course::Info& info = ci[i]; if( e->pSong && IsEasierForSongAndSteps(e->pSong, e->pNotes) )
if( info.pSong && IsEasierForSongAndSteps(info.pSong, info.pNotes) )
return true; return true;
} }
return false; return false;
+2 -2
View File
@@ -307,7 +307,7 @@ int Profile::GetPossibleCourseDancePointsForStepsType( StepsType st ) const
if( !pCourse->HasCourseDifficulty(st,cd) ) if( !pCourse->HasCourseDifficulty(st,cd) )
continue; continue;
const RadarValues& fRadars = pCourse->GetRadarValues(st,cd); const RadarValues& fRadars = pCourse->GetTrail(st,cd)->GetRadarValues();
iTotal += ScoreKeeperMAX2::GetPossibleDancePoints( fRadars ); iTotal += ScoreKeeperMAX2::GetPossibleDancePoints( fRadars );
} }
} }
@@ -342,7 +342,7 @@ int Profile::GetActualCourseDancePointsForStepsType( StepsType st ) const
FOREACH_ShownCourseDifficulty( cd ) FOREACH_ShownCourseDifficulty( cd )
{ {
const HighScoreList& hs = h.hs[st][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 ); int iPossibleDP = ScoreKeeperMAX2::GetPossibleDancePoints( fRadars );
iTotal += (int)truncf( hs.GetTopScore().fPercentDP * iPossibleDP ); iTotal += (int)truncf( hs.GetTopScore().fPercentDP * iPossibleDP );
} }
+5 -4
View File
@@ -894,7 +894,8 @@ bool PrintPercentCompleteForStepsType( RageFile &f, const Profile *pProfile, Ste
* style is set. */ * style is set. */
if( GAMESTATE->m_CurStyle == STYLE_INVALID ) if( GAMESTATE->m_CurStyle == STYLE_INVALID )
GAMESTATE->m_CurStyle = STYLE_DANCE_SINGLE; 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(); HighScore hs = pProfile->GetCourseHighScoreList(pCourse, st, cd).GetTopScore();
Grade grade = hs.grade; Grade grade = hs.grade;
if( grade != GRADE_NO_DATA ) if( grade != GRADE_NO_DATA )
@@ -1011,9 +1012,9 @@ bool PrintCatalogForSong( RageFile &f, const Profile *pProfile, Song* pSong )
BEGIN_TABLE(2); BEGIN_TABLE(2);
TABLE_LINE2( "Artist", pSong->GetDisplayArtist() ); TABLE_LINE2( "Artist", pSong->GetDisplayArtist() );
TABLE_LINE2( "GroupName", pSong->m_sGroupName ); TABLE_LINE2( "GroupName", pSong->m_sGroupName );
float fMinBPM, fMaxBPM; DisplayBpms bpms;
pSong->GetDisplayBPM( fMinBPM, fMaxBPM ); pSong->GetDisplayBpms( bpms );
CString sBPM = (fMinBPM==fMaxBPM) ? ssprintf("%.1f",fMinBPM) : ssprintf("%.1f - %.1f",fMinBPM,fMaxBPM); CString sBPM = (bpms.BpmIsConstant()) ? ssprintf("%.1f",bpms.GetMin()) : ssprintf("%.1f - %.1f",bpms.GetMin(),bpms.GetMax());
TABLE_LINE2( "BPM", sBPM ); TABLE_LINE2( "BPM", sBPM );
TABLE_LINE2( "Credit", pSong->m_sCredit ); TABLE_LINE2( "Credit", pSong->m_sCredit );
TABLE_LINE2( "MusicLength", SecondsToMMSSMsMs(pSong->m_fMusicLengthSeconds) ); TABLE_LINE2( "MusicLength", SecondsToMMSSMsMs(pSong->m_fMusicLengthSeconds) );
+16 -16
View File
@@ -49,6 +49,7 @@
#include "StageStats.h" #include "StageStats.h"
#include "PlayerAI.h" // for NUM_SKILL_LEVELS #include "PlayerAI.h" // for NUM_SKILL_LEVELS
#include "NetworkSyncManager.h" #include "NetworkSyncManager.h"
#include "Foreach.h"
// //
// Defines // Defines
@@ -182,37 +183,36 @@ void ScreenGameplay::Init()
// //
if( GAMESTATE->IsCourseMode() ) if( GAMESTATE->IsCourseMode() )
{ {
Course* pCourse = GAMESTATE->m_pCurCourse;
const StepsType st = GAMESTATE->GetCurrentStyleDef()->m_StepsType; const StepsType st = GAMESTATE->GetCurrentStyleDef()->m_StepsType;
/* Increment the play count. */ /* Increment the play count. */
if( !m_bDemonstration ) if( !m_bDemonstration )
FOREACH_EnabledPlayer(p) 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) FOREACH_PlayerNumber(p)
{ {
vector<Course::Info> ci; Trail *pTrail = pCourse->GetTrail( st, GAMESTATE->m_PreferredCourseDifficulty[p] );
GAMESTATE->m_pCurCourse->GetCourseInfo( GAMESTATE->GetCurrentStyleDef()->m_StepsType, ci, GAMESTATE->m_PreferredCourseDifficulty[p] );
m_apNotesQueue[p].clear(); m_apNotesQueue[p].clear();
m_asModifiersQueue[p].clear(); m_asModifiersQueue[p].clear();
for( unsigned c=0; c<ci.size(); ++c ) FOREACH_CONST( TrailEntry, pTrail->m_vEntries, e )
{ {
m_apNotesQueue[p].push_back( ci[c].pNotes ); m_apNotesQueue[p].push_back( e->pNotes );
AttackArray a; AttackArray a;
ci[c].GetAttackArray( a ); e->GetAttackArray( a );
m_asModifiersQueue[p].push_back( 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; c<ci.size(); ++c )
m_apSongsQueue.push_back( ci[c].pSong );
}
} }
} }
else else
+11 -42
View File
@@ -535,57 +535,26 @@ CString ScreenOptions::GetExplanationTitle( int iRow ) const
{ {
if( SHOW_BPM_IN_SPEED_TITLE ) if( SHOW_BPM_IN_SPEED_TITLE )
{ {
DisplayBpms bpms;
if( GAMESTATE->m_pCurSong ) if( GAMESTATE->m_pCurSong )
{ {
float fMinBpm, fMaxBpm; Song* pSong = GAMESTATE->m_pCurSong;
GAMESTATE->m_pCurSong->GetDisplayBPM( fMinBpm, fMaxBpm ); pSong->GetDisplayBpms( bpms );
if( fMinBpm == fMaxBpm )
sTitle += ssprintf( " (%.0f)", fMinBpm );
else
sTitle += ssprintf( " (%.0f-%.0f)", fMinBpm, fMaxBpm );
} }
else if( GAMESTATE->m_pCurCourse ) else if( GAMESTATE->m_pCurCourse )
{ {
float fTotalMinBpm = -1, fTotalMaxBpm = -1; // -1 == no marker Course *pCourse = GAMESTATE->m_pCurCourse;
vector<Course::Info> ci; StepsType st = GAMESTATE->GetCurrentStyleDef()->m_StepsType;
GAMESTATE->m_pCurCourse->GetCourseInfo( GAMESTATE->GetCurrentStyleDef()->m_StepsType, ci ); Trail* pTrail = pCourse->GetTrail(st,COURSE_DIFFICULTY_REGULAR);
pTrail->GetDisplayBpms( bpms );
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 ) if( bpms.IsMystery() )
sTitle += ssprintf( " (??" "?)" ); /* split so gcc doesn't think this is a trigraph */ sTitle += ssprintf( " (??" "?)" ); /* split so gcc doesn't think this is a trigraph */
else if( fTotalMinBpm == fTotalMaxBpm ) else if( bpms.BpmIsConstant() )
sTitle += ssprintf( " (%.0f)", fTotalMinBpm ); sTitle += ssprintf( " (%.0f)", bpms.GetMin() );
else else
sTitle += ssprintf( " (%.0f-%.0f)", fTotalMinBpm, fTotalMaxBpm ); sTitle += ssprintf( " (%.0f-%.0f)", bpms.GetMin(), bpms.GetMax() );
}
} }
} }
+2 -2
View File
@@ -385,11 +385,11 @@ void ScreenSelectCourse::AfterCourseChange()
case TYPE_COURSE: case TYPE_COURSE:
{ {
Course* pCourse = m_MusicWheel.GetSelectedCourse(); 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()) ); m_textNumSongs.SetText( ssprintf("%d", pCourse->GetEstimatedNumStages()) );
float fTotalSeconds; float fTotalSeconds;
if( pCourse->GetTotalSeconds(fTotalSeconds) ) if( pCourse->GetTotalSeconds(st, fTotalSeconds) )
m_textTime.SetText( SecondsToMMSSMsMs(fTotalSeconds) ); m_textTime.SetText( SecondsToMMSSMsMs(fTotalSeconds) );
else else
m_textTime.SetText( "xx:xx.xx" ); // The numbers format doesn't have a '?'. Is there a better solution? m_textTime.SetText( "xx:xx.xx" ); // The numbers format doesn't have a '?'. Is there a better solution?
+10 -10
View File
@@ -34,6 +34,7 @@
#include "LightsManager.h" #include "LightsManager.h"
#include "StageStats.h" #include "StageStats.h"
#include "StepsUtil.h" #include "StepsUtil.h"
#include "Foreach.h"
const int NUM_SCORE_DIGITS = 9; const int NUM_SCORE_DIGITS = 9;
@@ -1479,6 +1480,8 @@ void ScreenSelectMusic::AfterMusicChange()
case TYPE_COURSE: case TYPE_COURSE:
{ {
Course* pCourse = m_MusicWheel.GetSelectedCourse(); 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"); SampleMusicToPlay = THEME->GetPathS(m_sName,"course music");
m_fSampleStartSeconds = 0; m_fSampleStartSeconds = 0;
@@ -1486,7 +1489,7 @@ void ScreenSelectMusic::AfterMusicChange()
m_textNumSongs.SetText( ssprintf("%d", pCourse->GetEstimatedNumStages()) ); m_textNumSongs.SetText( ssprintf("%d", pCourse->GetEstimatedNumStages()) );
float fTotalSeconds; float fTotalSeconds;
if( pCourse->GetTotalSeconds(fTotalSeconds) ) if( pCourse->GetTotalSeconds(st,fTotalSeconds) )
m_textTotalTime.SetText( SecondsToMMSSMsMs(fTotalSeconds) ); m_textTotalTime.SetText( SecondsToMMSSMsMs(fTotalSeconds) );
else else
m_textTotalTime.SetText( "xx:xx.xx" ); // The numbers format doesn't have a '?'. Is there a better solution? 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_CourseContentsFrame.TweenInAfterChangedCourse();
m_DifficultyDisplay.UnsetDifficulties(); m_DifficultyDisplay.UnsetDifficulties();
vector<Course::Info> ci; FOREACH_CONST( TrailEntry, pTrail->m_vEntries, e )
pCourse->GetCourseInfo( GAMESTATE->GetCurrentStyleDef()->m_StepsType, ci );
for( unsigned i = 0; i < ci.size(); ++i )
{ {
if( ci[i].Mystery ) if( e->bMystery )
{ {
m_Artists.push_back( "???" ); m_Artists.push_back( "???" );
m_AltArtists.push_back( "???" ); m_AltArtists.push_back( "???" );
} else { } else {
m_Artists.push_back( ci[i].pSong->GetDisplayArtist() ); m_Artists.push_back( e->pSong->GetDisplayArtist() );
m_AltArtists.push_back( ci[i].pSong->GetTranslitArtist() ); m_AltArtists.push_back( e->pSong->GetTranslitArtist() );
} }
} }
@@ -1556,9 +1556,9 @@ void ScreenSelectMusic::AfterMusicChange()
m_Artist.SetTips( m_Artists, m_AltArtists ); m_Artist.SetTips( m_Artists, m_AltArtists );
for( int p=0; p<NUM_PLAYERS; p++ ) FOREACH_PlayerNumber( p )
{ {
AfterNotesChange( (PlayerNumber)p ); AfterNotesChange( p );
} }
/* Make sure we never start the sample when moving fast. */ /* Make sure we never start the sample when moving fast. */
+7 -4
View File
@@ -132,16 +132,19 @@ void Song::AddLyricSegment( LyricSegment seg )
m_LyricSegments.push_back( seg ); m_LyricSegments.push_back( seg );
} }
void Song::GetDisplayBPM( float &fMinBPMOut, float &fMaxBPMOut ) const void Song::GetDisplayBpms( DisplayBpms &AddTo ) const
{ {
if( m_DisplayBPMType == DISPLAY_SPECIFIED ) if( m_DisplayBPMType == DISPLAY_SPECIFIED )
{ {
fMinBPMOut = m_fSpecifiedBPMMin; AddTo.Add( m_fSpecifiedBPMMin );
fMaxBPMOut = m_fSpecifiedBPMMax; AddTo.Add( m_fSpecifiedBPMMax );
} }
else else
{ {
m_Timing.GetActualBPM( fMinBPMOut, fMaxBPMOut ); float fMinBPM, fMaxBPM;
m_Timing.GetActualBPM( fMinBPM, fMaxBPM );
AddTo.Add( fMinBPM );
AddTo.Add( fMaxBPM );
} }
} }
+9 -10
View File
@@ -665,18 +665,17 @@ bool SongManager::GetExtraStageInfoFromCourse( bool bExtra2, CString sPreferredG
course.LoadFromCRSFile( sCoursePath ); course.LoadFromCRSFile( sCoursePath );
if( course.GetEstimatedNumStages() <= 0 ) return false; if( course.GetEstimatedNumStages() <= 0 ) return false;
vector<Course::Info> ci; Trail *pTrail = course.GetTrail( GAMESTATE->GetCurrentStyleDef()->m_StepsType, COURSE_DIFFICULTY_REGULAR );
course.GetCourseInfo( GAMESTATE->GetCurrentStyleDef()->m_StepsType, ci ); if( pTrail->m_vEntries.empty() )
if( ci.empty() )
return false; return false;
po_out.Init(); po_out.Init();
po_out.FromString( ci[0].Modifiers ); po_out.FromString( pTrail->m_vEntries[0].Modifiers );
so_out.Init(); so_out.Init();
so_out.FromString( ci[0].Modifiers ); so_out.FromString( pTrail->m_vEntries[0].Modifiers );
pSongOut = ci[0].pSong; pSongOut = pTrail->m_vEntries[0].pSong;
pNotesOut = ci[0].pNotes; pNotesOut = pTrail->m_vEntries[0].pNotes;
return true; return true;
} }
@@ -949,13 +948,13 @@ void SongManager::UpdateRankingCourses()
for(unsigned i=0; i < m_pCourses.size(); i++) for(unsigned i=0; i < m_pCourses.size(); i++)
{ {
if (m_pCourses[i]->GetEstimatedNumStages() > 7) if (m_pCourses[i]->GetEstimatedNumStages() > 7)
m_pCourses[i]->SortOrder_Ranking = 3; m_pCourses[i]->m_SortOrder_Ranking = 3;
else else
m_pCourses[i]->SortOrder_Ranking = 2; m_pCourses[i]->m_SortOrder_Ranking = 2;
for(unsigned j = 0; j < RankingCourses.size(); j++) for(unsigned j = 0; j < RankingCourses.size(); j++)
if (!RankingCourses[j].CompareNoCase(m_pCourses[i]->m_sPath)) if (!RankingCourses[j].CompareNoCase(m_pCourses[i]->m_sPath))
m_pCourses[i]->SortOrder_Ranking = 1; m_pCourses[i]->m_SortOrder_Ranking = 1;
} }
} }
+8 -8
View File
@@ -118,13 +118,13 @@ void SongUtil::SortSongPointerArrayByDifficulty( vector<Song*> &arraySongPointer
bool CompareSongPointersByBPM(const Song *pSong1, const Song *pSong2) bool CompareSongPointersByBPM(const Song *pSong1, const Song *pSong2)
{ {
float fMinBPM1, fMaxBPM1, fMinBPM2, fMaxBPM2; DisplayBpms bpms1, bpms2;
pSong1->GetDisplayBPM( fMinBPM1, fMaxBPM1 ); pSong1->GetDisplayBpms( bpms1 );
pSong2->GetDisplayBPM( fMinBPM2, fMaxBPM2 ); pSong2->GetDisplayBpms( bpms2 );
if( fMaxBPM1 < fMaxBPM2 ) if( bpms1.GetMax() < bpms2.GetMax() )
return true; return true;
if( fMaxBPM1 > fMaxBPM2 ) if( bpms1.GetMax() > bpms2.GetMax() )
return false; return false;
return CompareCStringsAsc( pSong1->GetSongFilePath(), pSong2->GetSongFilePath() ); return CompareCStringsAsc( pSong1->GetSongFilePath(), pSong2->GetSongFilePath() );
@@ -267,9 +267,9 @@ CString SongUtil::GetSectionNameFromSongAndSort( const Song* pSong, SortOrder so
case SORT_BPM: case SORT_BPM:
{ {
const int iBPMGroupSize = 20; const int iBPMGroupSize = 20;
float fMinBPM, fMaxBPM; DisplayBpms bpms;
pSong->GetDisplayBPM( fMinBPM, fMaxBPM ); pSong->GetDisplayBpms( bpms );
int iMaxBPM = (int)fMaxBPM; int iMaxBPM = (int)bpms.GetMax();
iMaxBPM += iBPMGroupSize - (iMaxBPM%iBPMGroupSize) - 1; iMaxBPM += iBPMGroupSize - (iMaxBPM%iBPMGroupSize) - 1;
return ssprintf("%03d-%03d",iMaxBPM-(iBPMGroupSize-1), iMaxBPM); return ssprintf("%03d-%03d",iMaxBPM-(iBPMGroupSize-1), iMaxBPM);
} }
+20 -1
View File
@@ -1435,7 +1435,7 @@ SOURCE=.\FontCharmaps.h
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\ForeachEnum.h SOURCE=.\Foreach.h
# End Source File # End Source File
# Begin Source File # Begin Source File
@@ -2213,6 +2213,25 @@ SOURCE=.\TitleSubstitution.cpp
SOURCE=.\TitleSubstitution.h SOURCE=.\TitleSubstitution.h
# End Source File # 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 # End Group
# Begin Group "File Types" # Begin Group "File Types"
+7 -1
View File
@@ -122,7 +122,7 @@ cl /Zl /nologo /c verstub.cpp /Fo&quot;$(IntDir)&quot;\
<Tool <Tool
Name="VCLinkerTool" Name="VCLinkerTool"
AdditionalOptions="/MACHINE:I386 &quot;$(intdir)\verstub.obj&quot;" AdditionalOptions="/MACHINE:I386 &quot;$(intdir)\verstub.obj&quot;"
OutputFile="../Program/StepMania.exe" OutputFile="../../itg/itg/Program/StepMania.exe"
LinkIncremental="1" LinkIncremental="1"
SuppressStartupBanner="TRUE" SuppressStartupBanner="TRUE"
AdditionalLibraryDirectories="" AdditionalLibraryDirectories=""
@@ -899,6 +899,12 @@ cl /Zl /nologo /c verstub.cpp /Fo&quot;$(IntDir)&quot;\
<File <File
RelativePath="TitleSubstitution.h"> RelativePath="TitleSubstitution.h">
</File> </File>
<File
RelativePath="Trail.cpp">
</File>
<File
RelativePath="Trail.h">
</File>
</Filter> </Filter>
<Filter <Filter
Name="File Types" Name="File Types"
+105
View File
@@ -0,0 +1,105 @@
#include "global.h"
/*
-----------------------------------------------------------------------------
Class: Trail
Desc: See header.
Copyright (c) 2001-2002 by the person(s) listed below. All rights reserved.
Chris Danford
-----------------------------------------------------------------------------
*/
#include "Trail.h"
#include "Foreach.h"
#include "Steps.h"
#include "Song.h"
void TrailEntry::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() );
}
RadarValues Trail::GetRadarValues() const
{
RadarValues rv;
FOREACH_CONST( TrailEntry, m_vEntries, e )
{
const Steps *pNotes = e->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);
}
}
}
+51
View File
@@ -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<TrailEntry> 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
+1 -1
View File
@@ -168,7 +168,7 @@ public:
void AddForegroundChange( BackgroundChange seg ); void AddForegroundChange( BackgroundChange seg );
void AddLyricSegment( LyricSegment seg ); void AddLyricSegment( LyricSegment seg );
void GetDisplayBPM( float &fMinBPMOut, float &fMaxBPMOut ) const; void GetDisplayBpms( DisplayBpms &AddTo ) const;
CString GetBackgroundAtBeat( float fBeat ) const; CString GetBackgroundAtBeat( float fBeat ) const;
float GetBPMAtBeat( float fBeat ) const { return m_Timing.GetBPMAtBeat( fBeat ); } float GetBPMAtBeat( float fBeat ) const { return m_Timing.GetBPMAtBeat( fBeat ); }