Files
itgmania212121/stepmania/src/SongManager.cpp
T

1004 lines
27 KiB
C++
Raw Normal View History

2003-02-16 04:01:45 +00:00
#include "global.h"
2002-02-28 19:40:40 +00:00
/*
-----------------------------------------------------------------------------
Class: SongManager
Desc: See header.
2002-05-19 01:59:48 +00:00
Copyright (c) 2001-2002 by the person(s) listed below. All rights reserved.
2002-02-28 19:40:40 +00:00
Chris Danford
-----------------------------------------------------------------------------
*/
#include "SongManager.h"
#include "IniFile.h"
2002-05-01 19:14:55 +00:00
#include "RageLog.h"
#include "NotesLoaderDWI.h"
2002-06-14 22:25:22 +00:00
2002-07-23 01:41:40 +00:00
#include "GameState.h"
2002-05-29 09:47:24 +00:00
#include "PrefsManager.h"
2002-07-27 19:29:51 +00:00
#include "RageException.h"
#include "RageTimer.h"
#include "arch/LoadingWindow/LoadingWindow.h"
2002-02-28 19:40:40 +00:00
#include "AnnouncerManager.h"
#include "ThemeManager.h"
#include "GameManager.h"
2002-05-19 01:59:48 +00:00
SongManager* SONGMAN = NULL; // global and accessable from anywhere in our program
2002-02-28 19:40:40 +00:00
const CString CATEGORY_RANKING_FILE = "CategoryRanking.dat";
const CString COURSE_RANKING_FILE = "CourseRanking.dat";
const CString NOTES_SCORES_FILE[NUM_MEMORY_CARDS] = { "Player1NotesScores.dat", "Player2NotesScores.dat", "MachineNotesScores.dat" };
const CString COURSE_SCORES_FILE[NUM_MEMORY_CARDS] = { "Player1CourseScores.dat", "Player2CourseScores.dat", "MachineCourseScores.dat" };
const int CATEGORY_RANKING_VERSION = 1;
const int COURSE_RANKING_VERSION = 1;
const int NOTES_SCORES_VERSION = 1;
const int COURSE_SCORES_VERSION = 1;
2003-01-22 05:29:27 +00:00
2002-02-28 19:40:40 +00:00
2002-09-03 06:33:08 +00:00
#define NUM_GROUP_COLORS THEME->GetMetricI("SongManager","NumGroupColors")
#define GROUP_COLOR( i ) THEME->GetMetricC("SongManager",ssprintf("GroupColor%d",i+1))
#define BEGINNER_COLOR THEME->GetMetricC("SongManager","BeginnerColor")
#define EASY_COLOR THEME->GetMetricC("SongManager","EasyColor")
#define MEDIUM_COLOR THEME->GetMetricC("SongManager","MediumColor")
#define HARD_COLOR THEME->GetMetricC("SongManager","HardColor")
#define CHALLENGE_COLOR THEME->GetMetricC("SongManager","ChallengeColor")
2002-08-28 22:42:40 +00:00
#define EXTRA_COLOR THEME->GetMetricC("SongManager","ExtraColor")
vector<RageColor> g_vGroupColors;
RageColor g_ExtraColor;
2002-04-16 17:31:00 +00:00
2002-02-28 19:40:40 +00:00
2002-11-17 09:13:35 +00:00
SongManager::SongManager( LoadingWindow *ld )
2002-02-28 19:40:40 +00:00
{
2003-02-05 19:16:00 +00:00
/* We initialize things that assume they can get at SONGMAN; we only
* init one of these, so hook us up to it immediately. */
SONGMAN = this;
try
{
g_vGroupColors.clear();
for( int i=0; i<NUM_GROUP_COLORS; i++ )
g_vGroupColors.push_back( GROUP_COLOR(i) );
g_ExtraColor = EXTRA_COLOR;
InitSongArrayFromDisk( ld );
InitMachineScoresFromDisk();
InitCoursesFromDisk();
} catch(...) {
SONGMAN = NULL;
throw;
}
2002-02-28 19:40:40 +00:00
}
SongManager::~SongManager()
{
2003-01-22 05:29:27 +00:00
SaveMachineScoresToDisk();
2002-06-14 22:25:22 +00:00
FreeSongArray();
2002-02-28 19:40:40 +00:00
}
2002-11-17 09:13:35 +00:00
void SongManager::InitSongArrayFromDisk( LoadingWindow *ld )
2002-02-28 19:40:40 +00:00
{
2002-11-17 09:13:35 +00:00
LoadStepManiaSongDir( "Songs", ld );
2002-06-27 17:49:10 +00:00
for( unsigned i=0; i<PREFSMAN->m_asAdditionalSongFolders.size(); i++ )
2002-11-17 09:13:35 +00:00
LoadStepManiaSongDir( PREFSMAN->m_asAdditionalSongFolders[i], ld );
2002-04-16 17:31:00 +00:00
2002-09-10 08:38:46 +00:00
if( PREFSMAN->m_DWIPath != "" )
LoadStepManiaSongDir( PREFSMAN->m_DWIPath + "/Songs", ld );
2002-09-10 08:38:46 +00:00
LOG->Trace( "Found %d Songs.", m_pSongs.size() );
2002-03-06 08:25:09 +00:00
}
void SongManager::SanityCheckGroupDir( CString sDir ) const
{
// Check to see if they put a song directly inside the group folder.
CStringArray arrayFiles;
GetDirListing( sDir + "/*.mp3", arrayFiles );
GetDirListing( sDir + "/*.ogg", arrayFiles );
GetDirListing( sDir + "/*.wav", arrayFiles );
if( !arrayFiles.empty() )
2002-12-21 19:34:02 +00:00
RageException::Throw(
"The folder '%s' contains music files.\n\n"
"This means that you have a music outside of a song folder.\n"
"All song folders must reside in a group folder. For example, 'Songs/DDR 4th Mix/B4U'.\n"
"See the StepMania readme for more info.",
sDir.GetString()
);
}
2002-09-10 07:11:29 +00:00
void SongManager::AddGroup( CString sDir, CString sGroupDirName )
{
unsigned j;
for(j = 0; j < m_arrayGroupNames.size(); ++j)
2002-09-10 07:11:29 +00:00
if( sGroupDirName == m_arrayGroupNames[j] ) break;
if( j != m_arrayGroupNames.size() )
2002-09-10 07:11:29 +00:00
return; /* the group is already added */
// Look for a group banner in this group folder
CStringArray arrayGroupBanners;
2003-01-23 04:43:22 +00:00
GetDirListing( sDir+sGroupDirName+"/*.png", arrayGroupBanners );
GetDirListing( sDir+sGroupDirName+"/*.jpg", arrayGroupBanners );
GetDirListing( sDir+sGroupDirName+"/*.gif", arrayGroupBanners );
GetDirListing( sDir+sGroupDirName+"/*.bmp", arrayGroupBanners );
2002-09-10 07:11:29 +00:00
CString sBannerPath;
if( !arrayGroupBanners.empty() )
2002-09-10 07:11:29 +00:00
{
2003-01-23 04:43:22 +00:00
sBannerPath = sDir+sGroupDirName+"/"+arrayGroupBanners[0] ;
LOG->Trace( "Group banner for '%s' is '%s'.", sGroupDirName.GetString(), sBannerPath.GetString() );
2002-09-10 07:11:29 +00:00
}
2002-10-31 04:23:39 +00:00
m_arrayGroupNames.push_back( sGroupDirName );
m_GroupBannerPaths.push_back(sBannerPath);
2002-09-10 07:11:29 +00:00
}
2002-11-17 09:13:35 +00:00
void SongManager::LoadStepManiaSongDir( CString sDir, LoadingWindow *ld )
2002-03-06 08:25:09 +00:00
{
2003-01-23 04:43:22 +00:00
/* Make sure sDir has a trailing slash. */
2002-10-31 08:05:13 +00:00
TrimRight( sDir, "/\\" );
2003-01-23 04:43:22 +00:00
sDir += "/";
2002-03-06 08:25:09 +00:00
// Find all group directories in "Songs" folder
CStringArray arrayGroupDirs;
2003-01-23 04:43:22 +00:00
GetDirListing( sDir+"*", arrayGroupDirs, true );
2002-03-06 08:25:09 +00:00
SortCStringArray( arrayGroupDirs );
for( unsigned i=0; i< arrayGroupDirs.size(); i++ ) // for each dir in /Songs/
2002-03-06 08:25:09 +00:00
{
CString sGroupDirName = arrayGroupDirs[i];
if( 0 == stricmp( sGroupDirName, "cvs" ) ) // the directory called "CVS"
continue; // ignore it
2003-01-23 04:43:22 +00:00
SanityCheckGroupDir(sDir+sGroupDirName);
2002-03-06 08:25:09 +00:00
// Find all Song folders in this group directory
CStringArray arraySongDirs;
2003-01-23 04:43:22 +00:00
GetDirListing( sDir+sGroupDirName + "/*", arraySongDirs, true, true );
2002-03-06 08:25:09 +00:00
SortCStringArray( arraySongDirs );
unsigned j;
2002-09-09 02:23:47 +00:00
int loaded = 0;
for( j=0; j< arraySongDirs.size(); j++ ) // for each song dir
2002-03-06 08:25:09 +00:00
{
CString sSongDirName = arraySongDirs[j];
2003-01-23 04:43:22 +00:00
if( 0 == stricmp( Basename(sSongDirName), "cvs" ) ) // the directory called "CVS"
2002-03-06 08:25:09 +00:00
continue; // ignore it
// this is a song directory. Load a new song!
2002-11-17 09:13:35 +00:00
if( ld ) {
2003-01-23 04:43:22 +00:00
ld->SetText( ssprintf("Loading songs...\n%s\n%s",
Basename(sGroupDirName).GetString(),
Basename(sSongDirName).GetString()));
2002-11-17 09:13:35 +00:00
ld->Paint();
}
2002-03-06 08:25:09 +00:00
Song* pNewSong = new Song;
2003-01-23 04:43:22 +00:00
if( !pNewSong->LoadFromSongDir( sSongDirName ) ) {
/* The song failed to load. */
delete pNewSong;
continue;
}
2002-10-31 04:23:39 +00:00
m_pSongs.push_back( pNewSong );
2002-09-09 02:23:47 +00:00
loaded++;
}
/* Don't add the group name if we didn't load any songs in this group. */
if(!loaded) continue;
/* Add this group to the group array. */
2002-09-10 07:11:29 +00:00
AddGroup(sDir, sGroupDirName);
2002-03-06 08:25:09 +00:00
}
2002-11-17 09:13:35 +00:00
if( ld ) {
ld->Paint();
ld->SetText("Done loading songs.");
}
2002-03-06 08:25:09 +00:00
}
2002-06-14 22:25:22 +00:00
void SongManager::FreeSongArray()
2002-02-28 19:40:40 +00:00
{
for( unsigned i=0; i<m_pSongs.size(); i++ )
2002-02-28 19:40:40 +00:00
SAFE_DELETE( m_pSongs[i] );
2002-10-24 20:15:24 +00:00
m_pSongs.clear();
2002-06-14 22:25:22 +00:00
2002-10-24 20:15:24 +00:00
m_GroupBannerPaths.clear();
2002-02-28 19:40:40 +00:00
}
void SongManager::ReloadSongArray()
{
2002-07-23 01:41:40 +00:00
InitSongArrayFromDisk( NULL );
2002-06-14 22:25:22 +00:00
FreeSongArray();
2002-02-28 19:40:40 +00:00
}
2003-01-22 05:29:27 +00:00
void SongManager::InitMachineScoresFromDisk()
2002-02-28 19:40:40 +00:00
{
// Init category ranking
2003-01-22 05:29:27 +00:00
{
2003-01-26 07:33:03 +00:00
for( int i=0; i<NUM_NOTES_TYPES; i++ )
for( int j=0; j<NUM_RANKING_CATEGORIES; j++ )
2003-01-27 02:00:38 +00:00
for( int k=0; k<NUM_RANKING_LINES; k++ )
2002-02-28 19:40:40 +00:00
{
m_MachineScores[i][j][k].fScore = 573000;
m_MachineScores[i][j][k].sName = DEFAULT_RANKING_NAME;
2002-02-28 19:40:40 +00:00
}
2003-01-22 05:29:27 +00:00
}
2002-02-28 19:40:40 +00:00
// category ranking
2003-01-22 05:29:27 +00:00
{
FILE* fp = fopen( CATEGORY_RANKING_FILE, "r" );
2003-01-22 05:29:27 +00:00
if( fp )
{
int version;
fscanf(fp, "%d\n", &version );
if( version == CATEGORY_RANKING_VERSION )
{
2003-01-26 07:33:03 +00:00
for( int i=0; i<NUM_NOTES_TYPES; i++ )
for( int j=0; j<NUM_RANKING_CATEGORIES; j++ )
2003-01-27 02:00:38 +00:00
for( int k=0; k<NUM_RANKING_LINES; k++ )
if( fp && !feof(fp) )
{
char szName[256];
fscanf(fp, "%f %[^\n]\n", &m_MachineScores[i][j][k].fScore, szName);
m_MachineScores[i][j][k].sName = szName;
}
}
2003-01-22 05:29:27 +00:00
fclose(fp);
}
2002-02-28 19:40:40 +00:00
}
// course ranking
{
FILE* fp = fopen( COURSE_RANKING_FILE, "r" );
if( fp )
{
int version;
2003-02-17 20:43:23 +00:00
fscanf(fp, "%i\n", &version );
if( version == COURSE_RANKING_VERSION )
{
while( fp && !feof(fp) )
{
char szPath[256];
fscanf(fp, "%s\n", szPath);
Course* pCourse = GetCourseFromPath( szPath );
if( pCourse == NULL )
pCourse = GetCourseFromName( szPath );
for( int i=0; i<NUM_NOTES_TYPES; i++ )
for( int j=0; j<NUM_RANKING_LINES; j++ )
if( fp && !feof(fp) )
{
int iDancePoints;
float fSurviveTime;
char szName[256];
fscanf(fp, "%d %f %[^\n]\n", &iDancePoints, &fSurviveTime, szName);
if( pCourse )
{
pCourse->m_RankingScores[i][j].iDancePoints = iDancePoints;
pCourse->m_RankingScores[i][j].fSurviveTime = fSurviveTime;
pCourse->m_RankingScores[i][j].sName = szName;
}
}
}
}
fclose(fp);
}
}
// notes scores
for( int c=0; c<NUM_MEMORY_CARDS; c++ )
{
FILE* fp = fopen( NOTES_SCORES_FILE[c], "r" );
2003-01-22 05:29:27 +00:00
if( fp )
{
int version;
fscanf(fp, "%d\n", &version );
if( version == COURSE_SCORES_VERSION )
{
while( fp && !feof(fp) )
{
char szSongDir[256];
unsigned uNumNotes;
fscanf(fp, "%[^\n]\n%u\n", szSongDir, &uNumNotes);
Song* pSong = this->GetSongFromDir( szSongDir );
for( unsigned i=0; i<uNumNotes; i++ )
{
NotesType nt;
Difficulty dc;
char szDescription[256];
fscanf(fp, "%d\n%d\n%[^\n]\n", &nt, &dc, szDescription);
Notes* pNotes = NULL;
if( pSong )
if( dc==DIFFICULTY_INVALID )
pNotes = pSong->GetNotes( nt, szDescription );
else
pNotes = pSong->GetNotes( nt, dc );
int iNumTimesPlayed;
Grade grade;
float fScore;
fscanf(fp, "%d %d %f\n", &iNumTimesPlayed, &grade, &fScore );
if( pNotes )
{
pNotes->m_MemCardScores[c].iNumTimesPlayed = iNumTimesPlayed;
pNotes->m_MemCardScores[c].grade = grade;
pNotes->m_MemCardScores[c].fScore = fScore;
}
}
}
}
fclose(fp);
}
}
// course scores
{
for( int c=0; c<NUM_MEMORY_CARDS; c++ )
{
FILE* fp = fopen( COURSE_SCORES_FILE[c], "r" );
if( fp )
{
int version;
fscanf(fp, "%d\n", &version );
if( version == COURSE_SCORES_VERSION )
{
while( fp && !feof(fp) )
{
char szPath[256];
fscanf(fp, "%[^\n]\n", szPath);
Course* pCourse = GetCourseFromPath( szPath );
if( pCourse == NULL )
pCourse = GetCourseFromName( szPath );
2003-01-26 07:33:03 +00:00
for( int i=0; i<NUM_NOTES_TYPES; i++ )
if( fp && !feof(fp) )
{
int iNumTimesPlayed;
int iDancePoints;
float fSurviveTime;
fscanf(fp, "%d %d %f\n", &iNumTimesPlayed, &iDancePoints, &fSurviveTime);
if( pCourse )
2003-01-26 07:33:03 +00:00
{
pCourse->m_MemCardScores[c][i].iNumTimesPlayed = iNumTimesPlayed;
pCourse->m_MemCardScores[c][i].iDancePoints = iDancePoints;
pCourse->m_MemCardScores[c][i].fSurviveTime = fSurviveTime;
2003-01-26 07:33:03 +00:00
}
}
}
}
fclose(fp);
}
}
2003-01-22 05:29:27 +00:00
}
2002-02-28 19:40:40 +00:00
}
2003-01-22 05:29:27 +00:00
void SongManager::SaveMachineScoresToDisk()
2002-02-28 19:40:40 +00:00
{
// category ranking
LOG->Trace("Writing category ranking");
2002-02-28 19:40:40 +00:00
{
FILE* fp = fopen( CATEGORY_RANKING_FILE, "w" );
2003-01-22 05:29:27 +00:00
if( fp )
{
fprintf(fp,"%d\n",CATEGORY_RANKING_VERSION);
2003-01-26 07:33:03 +00:00
for( int i=0; i<NUM_NOTES_TYPES; i++ )
for( int j=0; j<NUM_RANKING_CATEGORIES; j++ )
2003-01-27 02:00:38 +00:00
for( int k=0; k<NUM_RANKING_LINES; k++ )
{
LOG->Trace("Writing %i,%i,%i", i, j, k);
LOG->Trace(" %p", m_MachineScores[i][j][k].sName.c_str());
if( fp )
fprintf(fp, "%f %s\n", m_MachineScores[i][j][k].fScore, m_MachineScores[i][j][k].sName.c_str());
}
2003-01-22 05:29:27 +00:00
fclose(fp);
}
2003-01-22 05:29:27 +00:00
}
2002-02-28 19:40:40 +00:00
// course ranking
LOG->Trace("Writing course ranking");
2003-01-22 05:29:27 +00:00
{
FILE* fp = fopen( COURSE_RANKING_FILE, "w" );
2002-02-28 19:40:40 +00:00
2003-01-22 05:29:27 +00:00
if( fp )
{
fprintf(fp,"%d\n",COURSE_RANKING_VERSION);
for( unsigned c=0; c<m_pCourses.size(); c++ ) // foreach course
2003-01-22 05:29:27 +00:00
{
Course* pCourse = m_pCourses[c];
LOG->Trace("Writing c = %i", c);
ASSERT(pCourse);
LOG->Trace(" ag %i", pCourse->m_bIsAutoGen );
if( pCourse->m_bIsAutoGen )
{
LOG->Trace(" %p", pCourse->m_sName.c_str() );
fprintf(fp, "%s\n", pCourse->m_sName.c_str());
}
else
{
LOG->Trace(" %p", pCourse->m_sPath.c_str() );
fprintf(fp, "%s\n", pCourse->m_sPath.c_str());
}
2003-01-22 05:29:27 +00:00
2003-01-26 07:33:03 +00:00
for( int i=0; i<NUM_NOTES_TYPES; i++ )
2003-01-27 02:00:38 +00:00
for( int j=0; j<NUM_RANKING_LINES; j++ )
{
LOG->Trace(" Writing %i %i", i, j);
LOG->Trace(" %p", pCourse->m_RankingScores[i][j].sName.c_str());
2003-01-26 07:33:03 +00:00
fprintf(fp, "%d %f %s\n",
pCourse->m_RankingScores[i][j].iDancePoints,
pCourse->m_RankingScores[i][j].fSurviveTime,
pCourse->m_RankingScores[i][j].sName.c_str());
}
2003-01-22 05:29:27 +00:00
}
fclose(fp);
2002-02-28 19:40:40 +00:00
}
}
2002-02-28 19:40:40 +00:00
// notes scores
LOG->Trace("Writing note scores");
for( int c=0; c<NUM_MEMORY_CARDS; c++ )
{
FILE* fp = fopen( NOTES_SCORES_FILE[c], "w" );
2003-01-22 05:29:27 +00:00
if( fp )
{
fprintf(fp,"%d\n",NOTES_SCORES_VERSION);
for( unsigned s=0; s<m_pSongs.size(); s++ ) // foreach song
{
LOG->Trace("Writing s = %i", s);
Song* pSong = m_pSongs[s];
ASSERT(pSong);
vector<Notes*> vNotes = pSong->m_apNotes;
for( int n=(int)vNotes.size()-1; n>=0; n-- )
{
LOG->Trace(" n = %i", n);
if( vNotes[n]->m_MemCardScores[c].grade <= GRADE_E )
{
LOG->Trace("erase");
vNotes.erase( vNotes.begin()+n );
}
}
if( vNotes.size() == 0 )
continue; // skip
LOG->Trace("ok");
LOG->Trace("write %p %i", pSong->GetSongDir().c_str(), vNotes.size());
fprintf(fp, "%s\n%u\n",
pSong->GetSongDir().c_str(),
vNotes.size() );
for( unsigned i=0; i<vNotes.size(); i++ )
{
LOG->Trace(" i = %i", i);
Notes* pNotes = vNotes[i];
ASSERT(pNotes);
LOG->Trace(" %p", pNotes->GetDescription().c_str());
fprintf(fp, "%d\n%d\n%s\n",
pNotes->m_NotesType,
pNotes->GetDifficulty(),
pNotes->GetDescription().c_str() );
LOG->Trace(" ...");
fprintf(fp, "%d %d %f\n",
pNotes->m_MemCardScores[c].iNumTimesPlayed,
pNotes->m_MemCardScores[c].grade,
pNotes->m_MemCardScores[c].fScore);
}
}
2003-01-22 05:29:27 +00:00
fclose(fp);
}
}
// course scores
LOG->Trace("Writing course scores");
{
for( int c=0; c<NUM_MEMORY_CARDS; c++ )
{
FILE* fp = fopen( COURSE_SCORES_FILE[c], "w" );
if( fp )
{
fprintf(fp,"%d\n",COURSE_SCORES_VERSION);
for( unsigned c=0; c<m_pCourses.size(); c++ ) // foreach song
{
LOG->Trace(" c=%i", c);
Course* pCourse = m_pCourses[c];
ASSERT(pCourse);
LOG->Trace(" %i", pCourse->m_bIsAutoGen );
if( pCourse->m_bIsAutoGen )
{
LOG->Trace(" %p", pCourse->m_sName.c_str() );
fprintf(fp, "%s\n", pCourse->m_sName.c_str());
}
else {
LOG->Trace(" %p", pCourse->m_sPath.c_str() );
fprintf(fp, "%s\n", pCourse->m_sPath.c_str());
}
for( int i=0; i<NUM_NOTES_TYPES; i++ )
{
LOG->Trace(" %i", i );
fprintf(fp, "%d %d %f\n",
pCourse->m_MemCardScores[c][i].iNumTimesPlayed,
pCourse->m_MemCardScores[c][i].iDancePoints,
pCourse->m_MemCardScores[c][i].fSurviveTime);
}
}
fclose(fp);
}
}
2003-01-22 05:29:27 +00:00
}
2002-03-06 08:25:09 +00:00
}
CString SongManager::GetGroupBannerPath( CString sGroupName )
2002-03-06 08:25:09 +00:00
{
unsigned i;
for(i = 0; i < m_arrayGroupNames.size(); ++i)
2002-09-07 07:24:44 +00:00
if( sGroupName == m_arrayGroupNames[i] ) break;
2002-03-06 08:25:09 +00:00
if( i == m_arrayGroupNames.size() )
2002-03-06 08:25:09 +00:00
return "";
2002-09-07 07:24:44 +00:00
return m_GroupBannerPaths[i];
2002-03-06 08:25:09 +00:00
}
2002-04-01 02:04:43 +00:00
void SongManager::GetGroupNames( CStringArray &AddTo )
{
2002-10-24 19:55:09 +00:00
AddTo.insert(AddTo.end(), m_arrayGroupNames.begin(), m_arrayGroupNames.end() );
2002-04-16 17:31:00 +00:00
}
2002-04-01 02:04:43 +00:00
bool SongManager::DoesGroupExist( CString sGroupName )
{
return find( m_arrayGroupNames.begin(), m_arrayGroupNames.end(), sGroupName ) != m_arrayGroupNames.end();
}
RageColor SongManager::GetGroupColor( const CString &sGroupName )
2002-04-16 17:31:00 +00:00
{
// search for the group index
unsigned i;
for( i=0; i<m_arrayGroupNames.size(); i++ )
2002-04-01 02:04:43 +00:00
{
2002-04-16 17:31:00 +00:00
if( m_arrayGroupNames[i] == sGroupName )
break;
2002-04-01 02:04:43 +00:00
}
ASSERT( i != m_arrayGroupNames.size() ); // this is not a valid group
2002-04-16 17:31:00 +00:00
return g_vGroupColors[i%g_vGroupColors.size()];
2002-04-01 02:04:43 +00:00
}
2002-12-17 05:22:32 +00:00
RageColor SongManager::GetSongColor( const Song* pSong )
{
ASSERT( pSong );
for( unsigned i=0; i<pSong->m_apNotes.size(); i++ )
{
2002-12-17 05:22:32 +00:00
const Notes* pNotes = pSong->m_apNotes[i];
2003-01-23 21:51:35 +00:00
if( pNotes->GetMeter() >= 10 )
return EXTRA_COLOR;
}
return GetGroupColor( pSong->m_sGroupName );
}
RageColor SongManager::GetDifficultyColor( Difficulty dc )
{
switch( dc )
{
case DIFFICULTY_BEGINNER: return BEGINNER_COLOR;
case DIFFICULTY_EASY: return EASY_COLOR;
case DIFFICULTY_MEDIUM: return MEDIUM_COLOR;
case DIFFICULTY_HARD: return HARD_COLOR;
case DIFFICULTY_CHALLENGE: return CHALLENGE_COLOR;
default: ASSERT(0); return CHALLENGE_COLOR;
}
}
void SongManager::GetSongs( vector<Song*> &AddTo, CString sGroupName, int iMaxStages ) const
2002-04-01 02:04:43 +00:00
{
AddTo.clear();
for( unsigned i=0; i<m_pSongs.size(); i++ )
if( sGroupName=="" || sGroupName==m_pSongs[i]->m_sGroupName )
if( GetNumStagesForSong(m_pSongs[i])<=iMaxStages )
AddTo.push_back( m_pSongs[i] );
2002-04-01 02:04:43 +00:00
}
2002-04-16 17:31:00 +00:00
2003-02-05 18:34:27 +00:00
int SongManager::GetNumSongs() const
{
return m_pSongs.size();
}
2003-02-05 18:34:27 +00:00
int SongManager::GetNumGroups() const
{
return m_arrayGroupNames.size();
}
int SongManager::GetNumCourses() const
{
return m_pCourses.size();
}
CString SongManager::ShortenGroupName( CString sLongGroupName )
2002-04-16 17:31:00 +00:00
{
sLongGroupName.Replace( "Dance Dance Revolution", "DDR" );
sLongGroupName.Replace( "dance dance revolution", "DDR" );
sLongGroupName.Replace( "DANCE DANCE REVOLUTION", "DDR" );
sLongGroupName.Replace( "Pump It Up", "PIU" );
sLongGroupName.Replace( "pump it up", "PIU" );
sLongGroupName.Replace( "PUMP IT UP", "PIU" );
sLongGroupName.Replace( "ParaParaParadise", "PPP" );
sLongGroupName.Replace( "paraparaparadise", "PPP" );
sLongGroupName.Replace( "PARAPARAPARADISE", "PPP" );
sLongGroupName.Replace( "Para Para Paradise", "PPP" );
sLongGroupName.Replace( "para para paradise", "PPP" );
sLongGroupName.Replace( "PARA PARA PARADISE", "PPP" );
sLongGroupName.Replace( "Dancing Stage", "DS" );
sLongGroupName.Replace( "Dancing Stage", "DS" );
sLongGroupName.Replace( "Dancing Stage", "DS" );
return sLongGroupName;
}
int SongManager::GetNumStagesForSong( const Song* pSong )
{
ASSERT( pSong );
if( pSong->m_fMusicLengthSeconds > PREFSMAN->m_fMarathonVerSongSeconds )
return 3;
if( pSong->m_fMusicLengthSeconds > PREFSMAN->m_fLongVerSongSeconds )
return 2;
else
return 1;
2002-04-16 17:31:00 +00:00
}
2002-06-14 22:25:22 +00:00
void SongManager::InitCoursesFromDisk()
{
2002-07-02 17:34:20 +00:00
//
// Load courses from CRS files
//
CStringArray saCourseFiles;
2003-02-05 18:34:27 +00:00
GetDirListing( "Courses/*.crs", saCourseFiles, false, true );
for( unsigned i=0; i<saCourseFiles.size(); i++ )
2002-07-02 17:34:20 +00:00
{
2003-01-22 05:29:27 +00:00
Course* pCourse = new Course;
2003-02-05 19:16:00 +00:00
pCourse->LoadFromCRSFile( saCourseFiles[i] );
m_pCourses.push_back( pCourse );
2002-07-02 17:34:20 +00:00
}
2002-07-02 17:34:20 +00:00
//
// Create group courses for Endless and Nonstop
2002-07-02 17:34:20 +00:00
//
2002-06-14 22:25:22 +00:00
CStringArray saGroupNames;
this->GetGroupNames( saGroupNames );
unsigned g;
for( g=0; g<saGroupNames.size(); g++ ) // foreach Group
2002-06-14 22:25:22 +00:00
{
CString sGroupName = saGroupNames[g];
2003-01-03 05:56:28 +00:00
vector<Song*> apGroupSongs;
GetSongs( apGroupSongs, sGroupName );
2002-06-14 22:25:22 +00:00
2002-09-29 05:06:18 +00:00
for( Difficulty dc=DIFFICULTY_EASY; dc<=DIFFICULTY_HARD; dc=Difficulty(dc+1) ) // foreach Difficulty
2002-07-04 21:05:18 +00:00
{
2003-01-22 05:29:27 +00:00
Course* pCourse = new Course;
pCourse->AutoGenEndlessFromGroupAndDifficulty( sGroupName, dc, apGroupSongs );
2002-07-04 21:05:18 +00:00
m_pCourses.push_back( pCourse );
2002-06-14 22:25:22 +00:00
}
}
}
2003-01-22 05:29:27 +00:00
void SongManager::FreeCourses()
2002-06-14 22:25:22 +00:00
{
2003-01-22 05:29:27 +00:00
for( unsigned i=0; i<m_pCourses.size(); i++ )
delete m_pCourses[i];
m_pCourses.clear();
2002-06-14 22:25:22 +00:00
}
2002-08-01 13:42:56 +00:00
2002-12-21 18:23:37 +00:00
/* Called periodically to wipe out cached NoteData. This is called when we change
* screens. */
2003-01-27 23:10:44 +00:00
void SongManager::CleanData()
2002-12-21 18:23:37 +00:00
{
for( unsigned i=0; i<m_pSongs.size(); i++ )
{
for( unsigned n=0; n<m_pSongs[i]->m_apNotes.size(); n++ )
{
m_pSongs[i]->m_apNotes[n]->Compress();
}
}
}
2002-12-21 18:23:37 +00:00
2003-01-26 09:40:30 +00:00
void SongManager::GetNonstopCourses( vector<Course*> &AddTo )
{
2003-01-22 05:29:27 +00:00
for( unsigned i=0; i<m_pCourses.size(); i++ )
{
if( !m_pCourses[i]->m_bRepeat && m_pCourses[i]->m_iLives <= 0 ) // use bar life meter
AddTo.push_back( m_pCourses[i] );
}
2002-12-21 18:23:37 +00:00
}
2003-01-26 09:40:30 +00:00
void SongManager::GetOniCourses( vector<Course*> &AddTo )
{
2003-01-22 05:29:27 +00:00
for( unsigned i=0; i<m_pCourses.size(); i++ )
{
if( !m_pCourses[i]->m_bRepeat && m_pCourses[i]->m_iLives > 0 ) // use battery life meter
AddTo.push_back( m_pCourses[i] );
}
}
2003-01-26 09:40:30 +00:00
void SongManager::GetEndlessCourses( vector<Course*> &AddTo )
{
2003-01-22 05:29:27 +00:00
for( unsigned i=0; i<m_pCourses.size(); i++ )
{
2003-01-22 05:29:27 +00:00
if( m_pCourses[i]->m_bRepeat )
AddTo.push_back( m_pCourses[i] );
}
}
2002-08-30 20:49:56 +00:00
bool SongManager::GetExtraStageInfoFromCourse( bool bExtra2, CString sPreferredGroup,
Song*& pSongOut, Notes*& pNotesOut, PlayerOptions& po_out, SongOptions& so_out )
{
CString sCoursePath = "Songs/" + sPreferredGroup + "/" + (bExtra2 ? "extra2" : "extra1") + ".crs";
if( !DoesFileExist(sCoursePath) )
{
bool bFound = false;
/* try alternative song folders */
for( unsigned i=0; i<PREFSMAN->m_asAdditionalSongFolders.size(); i++ )
{
sCoursePath = PREFSMAN->m_asAdditionalSongFolders[i] + "/" + sPreferredGroup + "/" + (bExtra2 ? "extra2" : "extra1") + ".crs";
if( DoesFileExist(sCoursePath) )
{
bFound = true;
break;
}
}
if( !bFound && PREFSMAN->m_DWIPath != "" )
{
sCoursePath = PREFSMAN->m_DWIPath + "/Songs/" + sPreferredGroup + "/" + (bExtra2 ? "extra2" : "extra1") + ".crs";
if( DoesFileExist(sCoursePath) )
bFound = true;
}
/*Couldn't find course in DWI path or Alternative Song Folders*/
if( !bFound )
return false;
}
2002-08-30 20:49:56 +00:00
Course course;
2003-02-05 19:16:00 +00:00
course.LoadFromCRSFile( sCoursePath );
if( course.GetEstimatedNumStages() <= 0 ) return false;
2002-08-30 20:49:56 +00:00
CString sModifiers;
if( course.GetFirstStageInfo( pSongOut, pNotesOut, sModifiers, GAMESTATE->GetCurrentStyleDef()->m_NotesType ) )
{
po_out.Init();
po_out.FromString( sModifiers );
so_out.Init();
so_out.FromString( sModifiers );
return true;
}
else
return false;
2002-08-30 20:49:56 +00:00
}
2002-08-01 13:42:56 +00:00
/* Return true if n1 < n2. */
bool CompareNotesPointersForExtra(const Notes *n1, const Notes *n2)
{
/* Equate CHALLENGE to HARD. */
Difficulty d1 = min(n1->GetDifficulty(), DIFFICULTY_HARD);
Difficulty d2 = min(n2->GetDifficulty(), DIFFICULTY_HARD);
if(d1 < d2) return true;
if(d1 > d2) return false;
/* n1 difficulty == n2 difficulty */
if(CompareNotesPointersByMeter(n1,n2)) return true;
if(CompareNotesPointersByMeter(n2,n1)) return false;
/* n1 meter == n2 meter */
return CompareNotesPointersByRadarValues(n1,n2);
}
void SongManager::GetExtraStageInfo( bool bExtra2, CString sPreferredGroup, const StyleDef *sd,
2002-08-01 13:42:56 +00:00
Song*& pSongOut, Notes*& pNotesOut, PlayerOptions& po_out, SongOptions& so_out )
{
if(GetExtraStageInfoFromCourse(bExtra2, (GAMESTATE->m_sPreferredGroup == "ALL MUSIC" ? GAMESTATE->m_pCurSong->m_sGroupName : GAMESTATE->m_sPreferredGroup), pSongOut, pNotesOut, po_out, so_out))
2002-08-01 13:42:56 +00:00
return;
// Choose a hard song for the extra stage
Song* pExtra1Song = NULL; // the absolute hardest Song and Notes. Use this for extra stage 1.
Notes* pExtra1Notes = NULL;
Song* pExtra2Song = NULL; // a medium-hard Song and Notes. Use this for extra stage 2.
Notes* pExtra2Notes = NULL;
2003-01-03 05:56:28 +00:00
vector<Song*> apSongs;
CString sGroup = GAMESTATE->m_sPreferredGroup=="ALL MUSIC" ? GAMESTATE->m_pCurSong->m_sGroupName : GAMESTATE->m_sPreferredGroup;
SONGMAN->GetSongs( apSongs, sGroup );
for( unsigned s=0; s<apSongs.size(); s++ ) // foreach song
2002-08-01 13:42:56 +00:00
{
Song* pSong = apSongs[s];
2003-01-03 05:56:28 +00:00
vector<Notes*> apNotes;
pSong->GetNotes( apNotes, sd->m_NotesType );
for( unsigned n=0; n<apNotes.size(); n++ ) // foreach Notes
2002-08-01 13:42:56 +00:00
{
Notes* pNotes = apNotes[n];
if( pExtra1Notes == NULL || CompareNotesPointersForExtra(pExtra1Notes,pNotes) ) // pNotes is harder than pHardestNotes
2002-08-01 13:42:56 +00:00
{
pExtra1Song = pSong;
pExtra1Notes = pNotes;
}
// for extra 2, we don't want to choose the hardest notes possible. So, we'll disgard Notes with meter > 8
2003-01-02 22:10:51 +00:00
if( bExtra2 && pNotes->GetMeter() > 8 )
2002-08-01 13:42:56 +00:00
continue; // skip
if( pExtra2Notes == NULL || CompareNotesPointersForExtra(pExtra2Notes,pNotes) ) // pNotes is harder than pHardestNotes
2002-08-01 13:42:56 +00:00
{
pExtra2Song = pSong;
pExtra2Notes = pNotes;
}
}
}
if( pExtra2Song == NULL && pExtra1Song != NULL )
{
pExtra2Song = pExtra1Song;
pExtra2Notes = pExtra1Notes;
}
// If there are any notes at all that match this NotesType, everything should be filled out.
// Also, it's guaranteed that there is at least one Notes that matches the NotesType because the player
// had to play something before reaching the extra stage!
ASSERT( pExtra2Song && pExtra1Song && pExtra2Notes && pExtra1Notes );
pSongOut = (bExtra2 ? pExtra2Song : pExtra1Song);
pNotesOut = (bExtra2 ? pExtra2Notes : pExtra1Notes);
po_out.Init();
so_out.Init();
po_out.m_bReverseScroll = true;
2003-01-25 11:05:12 +00:00
po_out.m_fScrollSpeed = 1.5f;
2002-08-01 13:42:56 +00:00
so_out.m_DrainType = (bExtra2 ? SongOptions::DRAIN_SUDDEN_DEATH : SongOptions::DRAIN_NO_RECOVER);
// should we do something fancy here, like turn on different effects?
2002-12-13 23:41:11 +00:00
int iSongHash = GetHashForString( pSongOut->GetSongDir() );
2003-02-14 06:57:53 +00:00
switch( ((unsigned int)iSongHash) % 5 )
2002-08-01 13:42:56 +00:00
{
2002-09-30 02:19:02 +00:00
case 0: po_out.m_bEffects[PlayerOptions::EFFECT_DIZZY] = true; break;
case 1: po_out.m_bDark = true; break;
case 2: po_out.m_bEffects[PlayerOptions::EFFECT_DRUNK] = true; break;
case 3: po_out.m_bEffects[PlayerOptions::EFFECT_MINI] = true; break;
case 4: po_out.m_bEffects[PlayerOptions::EFFECT_SPACE] = true; break;
2002-08-01 13:42:56 +00:00
default: ASSERT(0);
}
}
Song* SongManager::GetRandomSong()
{
if( m_pSongs.empty() )
return NULL;
return SONGMAN->m_pSongs[ rand()%m_pSongs.size() ];
}
2002-12-02 05:25:44 +00:00
Song* SongManager::GetSongFromDir( CString sDir )
{
if( sDir[sDir.GetLength()-1] != '/' )
sDir += '/';
2002-12-02 05:25:44 +00:00
for( unsigned int i=0; i<m_pSongs.size(); i++ )
2002-12-02 05:25:44 +00:00
if( sDir.CompareNoCase(m_pSongs[i]->GetSongDir()) == 0 )
return m_pSongs[i];
return NULL;
}
Course* SongManager::GetCourseFromPath( CString sPath )
{
2003-01-22 05:29:27 +00:00
for( unsigned int i=0; i<m_pCourses.size(); i++ )
if( sPath.CompareNoCase(m_pCourses[i]->m_sPath) == 0 )
return m_pCourses[i];
return NULL;
}
2003-01-22 05:29:27 +00:00
Course* SongManager::GetCourseFromName( CString sName )
{
for( unsigned int i=0; i<m_pCourses.size(); i++ )
if( sName.CompareNoCase(m_pCourses[i]->m_sName) == 0 )
return m_pCourses[i];
return NULL;
}
2003-01-22 05:29:27 +00:00
bool SongManager::IsUsingMemoryCard( PlayerNumber pn )
{
return true;
}
2003-01-27 02:00:38 +00:00
struct CategoryScoreToInsert
{
PlayerNumber pn;
2003-01-27 02:00:38 +00:00
RankingCategory cat;
float fScore;
2003-01-27 02:00:38 +00:00
static int CompareDescending( const CategoryScoreToInsert &hs1, const CategoryScoreToInsert &hs2 )
{
if( hs1.fScore > hs2.fScore ) return -1;
else if( hs1.fScore == hs2.fScore ) return 0;
else return +1;
}
2003-01-27 02:00:38 +00:00
static void SortDescending( vector<CategoryScoreToInsert>& vHSout )
{
sort( vHSout.begin(), vHSout.end(), CompareDescending );
}
};
void SongManager::AddScores( NotesType nt, bool bPlayerEnabled[NUM_PLAYERS], RankingCategory hsc[NUM_PLAYERS], float fScore[NUM_PLAYERS], int iNewRecordIndexOut[NUM_PLAYERS] ) // set iNewRecordIndex = -1 if not a new record
{
2003-01-27 02:00:38 +00:00
vector<CategoryScoreToInsert> vHS;
for( int p=0; p<NUM_PLAYERS; p++ )
{
iNewRecordIndexOut[p] = -1;
if( !bPlayerEnabled[p] )
continue; // skip
2003-01-27 02:00:38 +00:00
CategoryScoreToInsert hs;
hs.pn = (PlayerNumber)p;
2003-01-27 02:00:38 +00:00
hs.cat = hsc[p];
hs.fScore = fScore[p];
vHS.push_back( hs );
}
// Sort descending before inserting.
// This guarantees that a high score will not switch poitions on us when we later insert scores for the other player
2003-01-27 02:00:38 +00:00
CategoryScoreToInsert::SortDescending( vHS );
for( unsigned i=0; i<vHS.size(); i++ )
{
2003-01-27 02:00:38 +00:00
CategoryScoreToInsert& newHS = vHS[i];
MachineScore* machineScores = m_MachineScores[nt][newHS.cat];
for( int i=0; i<NUM_RANKING_LINES; i++ )
{
if( newHS.fScore > machineScores[i].fScore )
{
// We found the insert point. Shift down.
for( int j=NUM_RANKING_LINES-1; j>i; j-- )
machineScores[j] = machineScores[j-1];
// insert
2003-01-27 02:00:38 +00:00
machineScores[i].fScore = newHS.fScore;
machineScores[i].sName = DEFAULT_RANKING_NAME;
iNewRecordIndexOut[newHS.pn] = i;
2003-01-27 02:00:38 +00:00
break;
}
}
}
}