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;
bool AllIdentical = true;
@@ -159,9 +161,9 @@ void BPMDisplay::SetBPMRange( const vector<float> &BPMS )
void BPMDisplay::CycleRandomly()
{
vector<float> 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<float> 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<Course::Info> 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<float> 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;
}
+1 -1
View File
@@ -34,7 +34,7 @@ public:
protected:
float GetActiveBPM() const;
void SetBPMRange( const vector<float> &m_BPMS );
void SetBPMRange( const DisplayBpms &bpms );
BitmapText m_textBPM;
AutoActor m_sprLabel;
+72 -193
View File
@@ -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<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 )
{
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<m_entries.size(); i++ )
@@ -435,7 +386,7 @@ void Course::AutogenEndlessFromGroup( CString sGroupName, Difficulty diff )
m_bRepeat = true;
m_bRandomize = true;
m_iLives = -1;
m_iMeter[0] = m_iMeter[1] = -1;
m_iCustomMeter[0] = m_iCustomMeter[1] = -1;
if( sGroupName == "" )
{
@@ -502,58 +453,20 @@ bool Course::HasCourseDifficulty( StepsType nt, CourseDifficulty cd ) const
{
/* 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 )
return true;
vector<Info> 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<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;
return Regular != Other;
}
bool Course::IsPlayableIn( StepsType nt ) const
{
vector<Info> ci;
GetCourseInfo( nt, ci );
return ci.size() > 0;
Trail* pTrail = GetTrail( nt, COURSE_DIFFICULTY_REGULAR );
return !pTrail->m_vEntries.empty();
}
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
* be called on all songs to sort. It can take time to execute, so we cache the
* 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 );
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<Course::Info> &ci, CourseDiffic
vector<Song*> AllSongsShuffled;
int CurSong = 0; /* Current offset into AllSongsShuffled */
ci.clear();
Trail trail;
for( unsigned i=0; i<entries.size(); i++ )
{
@@ -754,20 +674,20 @@ void Course::GetCourseInfo( StepsType nt, vector<Course::Info> &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<Info> ci;
GetCourseInfo( STEPS_TYPE_DANCE_SINGLE, ci );
Trail* pTrail = GetTrail( st, COURSE_DIFFICULTY_REGULAR );
fSecondsOut = 0;
for( unsigned i=0; i<ci.size(); i++ )
{
if( ci[i].Mystery )
return false;
fSecondsOut += ci[i].pSong->m_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<Info> 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<Course::Info> 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() );
}
+12 -32
View File
@@ -15,6 +15,7 @@
#include "GameConstantsAndTypes.h"
#include "Attack.h"
#include <map>
#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<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
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 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<StepsType,CourseDifficulty> InfoParams;
typedef vector<Info> InfoData;
typedef map<InfoParams, InfoData> InfoCache;
mutable InfoCache m_InfoCache;
typedef pair<StepsType,CourseDifficulty> TrailParams;
typedef map<TrailParams, Trail> TrailCache;
mutable TrailCache m_TrailCache;
};
#endif
+15 -7
View File
@@ -56,17 +56,25 @@ void CourseContentsList::SetFromCourse( const Course* pCourse )
return;
}
vector<Course::Info> 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; i<min((int)ci[0].size(), MAX_TOTAL_CONTENTS); i++ )
// FIXME: Is there a better way to handle when players don't have
// the same number of TrailEntries?
m_iNumContents = 0;
for( int i=0; i<min((int)pTrail[0]->m_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++;
}
+18 -17
View File
@@ -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 );
}
+1 -1
View File
@@ -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 );
+9 -7
View File
@@ -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<Course*> &apCourses
void CourseUtil::SortCoursePointerArrayByRanking( vector<Course*> &apCourses )
{
for(unsigned i=0; i<apCourses.size(); i++)
apCourses[i]->UpdateCourseStats();
apCourses[i]->UpdateCourseStats( GAMESTATE->GetCurrentStyleDef()->m_StepsType );
sort( apCourses.begin(), apCourses.end(), CompareCoursePointersByRanking );
}
void CourseUtil::SortCoursePointerArrayByTotalDifficulty( vector<Course*> &apCourses )
{
for(unsigned i=0; i<apCourses.size(); i++)
apCourses[i]->UpdateCourseStats();
apCourses[i]->UpdateCourseStats( GAMESTATE->GetCurrentStyleDef()->m_StepsType );
sort( apCourses.begin(), apCourses.end(), CompareCoursePointersByTotalDifficulty );
}
@@ -157,7 +159,7 @@ void CourseUtil::SortCoursePointerArrayByAvgDifficulty( vector<Course*> &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 );
+4 -1
View File
@@ -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;
-54
View File
@@ -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<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
+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 "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;
}
+10
View File
@@ -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<float> vfBpms;
};
#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 \
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 \
+1 -2
View File
@@ -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<Course::Info> 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;
+4 -5
View File
@@ -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<Course::Info> ci;
pCourse->GetCourseInfo( st, ci, cd );
Trail *pTrail = pCourse->GetTrail( st, cd );
for( unsigned i=0; i<ci.size(); i++ )
FOREACH_CONST( TrailEntry, pTrail->m_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;
+2 -2
View File
@@ -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 );
}
+5 -4
View File
@@ -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) );
+16 -16
View File
@@ -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<Course::Info> 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; 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;
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; c<ci.size(); ++c )
m_apSongsQueue.push_back( ci[c].pSong );
}
}
}
else
+14 -45
View File
@@ -535,57 +535,26 @@ CString ScreenOptions::GetExplanationTitle( int iRow ) const
{
if( SHOW_BPM_IN_SPEED_TITLE )
{
DisplayBpms bpms;
if( GAMESTATE->m_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<Course::Info> 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() );
}
}
+2 -2
View File
@@ -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?
+10 -10
View File
@@ -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<Course::Info> 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<NUM_PLAYERS; p++ )
FOREACH_PlayerNumber( p )
{
AfterNotesChange( (PlayerNumber)p );
AfterNotesChange( p );
}
/* 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 );
}
void Song::GetDisplayBPM( float &fMinBPMOut, float &fMaxBPMOut ) const
void Song::GetDisplayBpms( DisplayBpms &AddTo ) const
{
if( m_DisplayBPMType == DISPLAY_SPECIFIED )
{
fMinBPMOut = m_fSpecifiedBPMMin;
fMaxBPMOut = m_fSpecifiedBPMMax;
AddTo.Add( m_fSpecifiedBPMMin );
AddTo.Add( m_fSpecifiedBPMMax );
}
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 );
if( course.GetEstimatedNumStages() <= 0 ) return false;
vector<Course::Info> 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;
}
}
+8 -8
View File
@@ -118,13 +118,13 @@ void SongUtil::SortSongPointerArrayByDifficulty( vector<Song*> &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);
}
+22 -3
View File
@@ -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"
+7 -1
View File
@@ -122,7 +122,7 @@ cl /Zl /nologo /c verstub.cpp /Fo&quot;$(IntDir)&quot;\
<Tool
Name="VCLinkerTool"
AdditionalOptions="/MACHINE:I386 &quot;$(intdir)\verstub.obj&quot;"
OutputFile="../Program/StepMania.exe"
OutputFile="../../itg/itg/Program/StepMania.exe"
LinkIncremental="1"
SuppressStartupBanner="TRUE"
AdditionalLibraryDirectories=""
@@ -899,6 +899,12 @@ cl /Zl /nologo /c verstub.cpp /Fo&quot;$(IntDir)&quot;\
<File
RelativePath="TitleSubstitution.h">
</File>
<File
RelativePath="Trail.cpp">
</File>
<File
RelativePath="Trail.h">
</File>
</Filter>
<Filter
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 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 ); }