2004-04-18 08:36:04 +00:00
|
|
|
#include "global.h"
|
|
|
|
|
#include "CourseUtil.h"
|
|
|
|
|
#include "Course.h"
|
|
|
|
|
#include "RageTimer.h"
|
|
|
|
|
#include "ProfileManager.h"
|
2005-07-01 05:07:22 +00:00
|
|
|
#include "Profile.h"
|
2004-04-18 08:36:04 +00:00
|
|
|
#include "SongManager.h"
|
2004-05-22 01:37:00 +00:00
|
|
|
#include "XmlFile.h"
|
2004-05-23 00:53:20 +00:00
|
|
|
#include "GameState.h"
|
2004-06-28 07:26:00 +00:00
|
|
|
#include "Style.h"
|
2005-04-25 22:44:32 +00:00
|
|
|
#include "Foreach.h"
|
2005-08-03 03:28:13 +00:00
|
|
|
#include "GameState.h"
|
2004-04-18 08:36:04 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Sorting stuff
|
|
|
|
|
//
|
2005-05-19 20:34:35 +00:00
|
|
|
static bool CompareCoursePointersByName( const Course* pCourse1, const Course* pCourse2 )
|
2004-04-18 08:36:04 +00:00
|
|
|
{
|
2005-05-23 00:38:09 +00:00
|
|
|
CString sName1 = pCourse1->GetDisplayFullTitle();
|
|
|
|
|
CString sName2 = pCourse2->GetDisplayFullTitle();
|
2005-05-19 20:36:34 +00:00
|
|
|
return sName1.CompareNoCase( sName2 ) < 0;
|
2004-04-18 08:36:04 +00:00
|
|
|
}
|
|
|
|
|
|
2005-05-19 20:34:35 +00:00
|
|
|
static bool CompareCoursePointersByAutogen( const Course* pCourse1, const Course* pCourse2 )
|
2004-04-18 08:36:04 +00:00
|
|
|
{
|
|
|
|
|
int b1 = pCourse1->m_bIsAutogen;
|
|
|
|
|
int b2 = pCourse2->m_bIsAutogen;
|
|
|
|
|
if( b1 < b2 )
|
|
|
|
|
return true;
|
|
|
|
|
else if( b1 > b2 )
|
|
|
|
|
return false;
|
|
|
|
|
else
|
|
|
|
|
return CompareCoursePointersByName(pCourse1,pCourse2);
|
|
|
|
|
}
|
|
|
|
|
|
2005-05-19 20:34:35 +00:00
|
|
|
static bool CompareCoursePointersByDifficulty( const Course* pCourse1, const Course* pCourse2 )
|
2004-04-18 08:36:04 +00:00
|
|
|
{
|
|
|
|
|
int iNum1 = pCourse1->GetEstimatedNumStages();
|
|
|
|
|
int iNum2 = pCourse2->GetEstimatedNumStages();
|
|
|
|
|
if( iNum1 < iNum2 )
|
|
|
|
|
return true;
|
|
|
|
|
else if( iNum1 > iNum2 )
|
|
|
|
|
return false;
|
|
|
|
|
else // iNum1 == iNum2
|
|
|
|
|
return CompareCoursePointersByAutogen( pCourse1, pCourse2 );
|
|
|
|
|
}
|
|
|
|
|
|
2005-05-19 20:34:35 +00:00
|
|
|
static bool CompareCoursePointersByTotalDifficulty( const Course* pCourse1, const Course* pCourse2 )
|
2004-04-18 08:36:04 +00:00
|
|
|
{
|
2004-05-23 00:53:20 +00:00
|
|
|
int iNum1 = pCourse1->m_SortOrder_TotalDifficulty;
|
|
|
|
|
int iNum2 = pCourse2->m_SortOrder_TotalDifficulty;
|
2004-04-18 08:36:04 +00:00
|
|
|
|
|
|
|
|
if( iNum1 == iNum2 )
|
|
|
|
|
return CompareCoursePointersByAutogen( pCourse1, pCourse2 );
|
|
|
|
|
return iNum1 < iNum2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool MovePlayersBestToEnd( const Course* pCourse1, const Course* pCourse2 )
|
|
|
|
|
{
|
|
|
|
|
bool C1HasBest = pCourse1->CourseHasBestOrWorst();
|
|
|
|
|
bool C2HasBest = pCourse2->CourseHasBestOrWorst();
|
|
|
|
|
if( !C1HasBest && !C2HasBest )
|
|
|
|
|
return false;
|
|
|
|
|
if( C1HasBest && !C2HasBest )
|
|
|
|
|
return false;
|
|
|
|
|
if( !C1HasBest && C2HasBest )
|
|
|
|
|
return true;
|
|
|
|
|
|
2004-07-11 10:02:38 +00:00
|
|
|
return CompareCoursePointersByName( pCourse1, pCourse2 );
|
2004-04-18 08:36:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool CompareRandom( const Course* pCourse1, const Course* pCourse2 )
|
|
|
|
|
{
|
|
|
|
|
return ( pCourse1->IsFixed() && !pCourse2->IsFixed() );
|
|
|
|
|
}
|
|
|
|
|
|
2005-05-19 20:34:35 +00:00
|
|
|
static bool CompareCoursePointersByRanking( const Course* pCourse1, const Course* pCourse2 )
|
2004-04-18 08:36:04 +00:00
|
|
|
{
|
2004-05-23 00:53:20 +00:00
|
|
|
int iNum1 = pCourse1->m_SortOrder_Ranking;
|
|
|
|
|
int iNum2 = pCourse2->m_SortOrder_Ranking;
|
2004-04-18 08:36:04 +00:00
|
|
|
|
|
|
|
|
if( iNum1 == iNum2 )
|
|
|
|
|
return CompareCoursePointersByAutogen( pCourse1, pCourse2 );
|
|
|
|
|
return iNum1 < iNum2;
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-25 22:44:32 +00:00
|
|
|
void CourseUtil::SortCoursePointerArrayByDifficulty( vector<Course*> &vpCoursesInOut )
|
2004-04-18 08:36:04 +00:00
|
|
|
{
|
2005-04-25 22:44:32 +00:00
|
|
|
sort( vpCoursesInOut.begin(), vpCoursesInOut.end(), CompareCoursePointersByDifficulty );
|
2004-04-18 08:36:04 +00:00
|
|
|
}
|
|
|
|
|
|
2005-04-25 22:44:32 +00:00
|
|
|
void CourseUtil::SortCoursePointerArrayByRanking( vector<Course*> &vpCoursesInOut )
|
2004-04-18 08:36:04 +00:00
|
|
|
{
|
2005-05-19 20:34:35 +00:00
|
|
|
for( unsigned i=0; i<vpCoursesInOut.size(); i++ )
|
2005-04-25 22:44:32 +00:00
|
|
|
vpCoursesInOut[i]->UpdateCourseStats( GAMESTATE->GetCurrentStyle()->m_StepsType );
|
|
|
|
|
sort( vpCoursesInOut.begin(), vpCoursesInOut.end(), CompareCoursePointersByRanking );
|
2004-04-18 08:36:04 +00:00
|
|
|
}
|
|
|
|
|
|
2005-04-25 22:44:32 +00:00
|
|
|
void CourseUtil::SortCoursePointerArrayByTotalDifficulty( vector<Course*> &vpCoursesInOut )
|
2004-04-18 08:36:04 +00:00
|
|
|
{
|
2005-05-19 20:34:35 +00:00
|
|
|
for( unsigned i=0; i<vpCoursesInOut.size(); i++ )
|
2005-04-25 22:44:32 +00:00
|
|
|
vpCoursesInOut[i]->UpdateCourseStats( GAMESTATE->GetCurrentStyle()->m_StepsType );
|
|
|
|
|
sort( vpCoursesInOut.begin(), vpCoursesInOut.end(), CompareCoursePointersByTotalDifficulty );
|
2004-04-18 08:36:04 +00:00
|
|
|
}
|
|
|
|
|
|
2005-05-19 20:34:35 +00:00
|
|
|
static bool CompareCoursePointersByType( const Course* pCourse1, const Course* pCourse2 )
|
2004-04-18 08:36:04 +00:00
|
|
|
{
|
|
|
|
|
return pCourse1->GetPlayMode() < pCourse2->GetPlayMode();
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-25 22:44:32 +00:00
|
|
|
void CourseUtil::SortCoursePointerArrayByType( vector<Course*> &vpCoursesInOut )
|
2004-04-18 08:36:04 +00:00
|
|
|
{
|
2005-04-25 22:44:32 +00:00
|
|
|
stable_sort( vpCoursesInOut.begin(), vpCoursesInOut.end(), CompareCoursePointersByType );
|
2004-04-18 08:36:04 +00:00
|
|
|
}
|
|
|
|
|
|
2005-04-25 22:44:32 +00:00
|
|
|
void CourseUtil::MoveRandomToEnd( vector<Course*> &vpCoursesInOut )
|
2004-04-18 08:36:04 +00:00
|
|
|
{
|
2005-04-25 22:44:32 +00:00
|
|
|
stable_sort( vpCoursesInOut.begin(), vpCoursesInOut.end(), CompareRandom );
|
2004-04-18 08:36:04 +00:00
|
|
|
}
|
|
|
|
|
|
2005-04-25 22:44:32 +00:00
|
|
|
static map<const Course*, CString> course_sort_val;
|
2004-04-18 08:36:04 +00:00
|
|
|
|
2005-05-19 20:34:35 +00:00
|
|
|
bool CompareCoursePointersBySortValueAscending( const Course *pSong1, const Course *pSong2 )
|
2004-04-18 08:36:04 +00:00
|
|
|
{
|
|
|
|
|
return course_sort_val[pSong1] < course_sort_val[pSong2];
|
|
|
|
|
}
|
|
|
|
|
|
2005-05-19 20:34:35 +00:00
|
|
|
bool CompareCoursePointersBySortValueDescending( const Course *pSong1, const Course *pSong2 )
|
2004-04-18 08:36:04 +00:00
|
|
|
{
|
|
|
|
|
return course_sort_val[pSong1] > course_sort_val[pSong2];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CompareCoursePointersByTitle( const Course *pCourse1, const Course *pCourse2 )
|
|
|
|
|
{
|
2004-07-11 10:02:38 +00:00
|
|
|
return CompareCoursePointersByName( pCourse1, pCourse2 );
|
2004-04-18 08:36:04 +00:00
|
|
|
}
|
|
|
|
|
|
2005-04-25 22:44:32 +00:00
|
|
|
void CourseUtil::SortCoursePointerArrayByTitle( vector<Course*> &vpCoursesInOut )
|
2005-03-12 03:18:11 +00:00
|
|
|
{
|
2005-04-25 22:44:32 +00:00
|
|
|
sort( vpCoursesInOut.begin(), vpCoursesInOut.end(), CompareCoursePointersByTitle );
|
2005-03-12 03:18:11 +00:00
|
|
|
}
|
|
|
|
|
|
2005-04-25 22:44:32 +00:00
|
|
|
void CourseUtil::SortCoursePointerArrayByAvgDifficulty( vector<Course*> &vpCoursesInOut )
|
2004-04-18 08:36:04 +00:00
|
|
|
{
|
|
|
|
|
RageTimer foo;
|
|
|
|
|
course_sort_val.clear();
|
2005-05-19 20:34:35 +00:00
|
|
|
for( unsigned i = 0; i < vpCoursesInOut.size(); ++i )
|
2004-06-03 08:22:02 +00:00
|
|
|
{
|
2005-04-25 22:44:32 +00:00
|
|
|
const Trail* pTrail = vpCoursesInOut[i]->GetTrail( GAMESTATE->GetCurrentStyle()->m_StepsType );
|
2005-04-26 10:33:12 +00:00
|
|
|
course_sort_val[vpCoursesInOut[i]] = ssprintf("%09.3f", pTrail != NULL? (float) pTrail->GetMeter(): 0.0f);
|
2004-06-03 08:22:02 +00:00
|
|
|
}
|
2005-04-25 22:44:32 +00:00
|
|
|
sort( vpCoursesInOut.begin(), vpCoursesInOut.end(), CompareCoursePointersByTitle );
|
|
|
|
|
stable_sort( vpCoursesInOut.begin(), vpCoursesInOut.end(), CompareCoursePointersBySortValueAscending );
|
2004-04-18 08:36:04 +00:00
|
|
|
|
2005-04-25 22:44:32 +00:00
|
|
|
stable_sort( vpCoursesInOut.begin(), vpCoursesInOut.end(), MovePlayersBestToEnd );
|
2004-04-18 08:36:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2005-04-25 22:44:32 +00:00
|
|
|
void CourseUtil::SortCoursePointerArrayByNumPlays( vector<Course*> &vpCoursesInOut, ProfileSlot slot, bool bDescending )
|
2004-04-18 08:36:04 +00:00
|
|
|
{
|
2005-05-09 08:44:01 +00:00
|
|
|
if( !PROFILEMAN->IsPersistentProfile(slot) )
|
2004-04-18 08:36:04 +00:00
|
|
|
return; // nothing to do since we don't have data
|
2005-05-01 06:42:30 +00:00
|
|
|
Profile* pProfile = PROFILEMAN->GetProfile(slot);
|
2005-04-25 22:44:32 +00:00
|
|
|
SortCoursePointerArrayByNumPlays( vpCoursesInOut, pProfile, bDescending );
|
2004-04-18 08:36:04 +00:00
|
|
|
}
|
|
|
|
|
|
2005-04-25 22:44:32 +00:00
|
|
|
void CourseUtil::SortCoursePointerArrayByNumPlays( vector<Course*> &vpCoursesInOut, const Profile* pProfile, bool bDescending )
|
2004-04-18 08:36:04 +00:00
|
|
|
{
|
|
|
|
|
ASSERT( pProfile );
|
2005-04-25 22:44:32 +00:00
|
|
|
for(unsigned i = 0; i < vpCoursesInOut.size(); ++i)
|
2005-04-26 10:33:12 +00:00
|
|
|
course_sort_val[vpCoursesInOut[i]] = ssprintf( "%09i", pProfile->GetCourseNumTimesPlayed(vpCoursesInOut[i]) );
|
2005-04-25 22:44:32 +00:00
|
|
|
stable_sort( vpCoursesInOut.begin(), vpCoursesInOut.end(), bDescending ? CompareCoursePointersBySortValueDescending : CompareCoursePointersBySortValueAscending );
|
2004-04-18 08:36:04 +00:00
|
|
|
course_sort_val.clear();
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-25 22:44:32 +00:00
|
|
|
void CourseUtil::SortByMostRecentlyPlayedForMachine( vector<Course*> &vpCoursesInOut )
|
|
|
|
|
{
|
|
|
|
|
Profile *pProfile = PROFILEMAN->GetMachineProfile();
|
|
|
|
|
|
|
|
|
|
FOREACH_CONST( Course*, vpCoursesInOut, c )
|
|
|
|
|
{
|
|
|
|
|
int iNumTimesPlayed = pProfile->GetCourseNumTimesPlayed( *c );
|
|
|
|
|
CString val = iNumTimesPlayed ? pProfile->GetCourseLastPlayedDateTime(*c).GetString() : "9999999999999";
|
|
|
|
|
course_sort_val[*c] = val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
stable_sort( vpCoursesInOut.begin(), vpCoursesInOut.end(), CompareCoursePointersBySortValueAscending );
|
|
|
|
|
course_sort_val.clear();
|
|
|
|
|
}
|
|
|
|
|
|
2005-08-03 03:28:13 +00:00
|
|
|
void CourseUtil::MakeDefaultEditCourseEntry( CourseEntry& out )
|
|
|
|
|
{
|
|
|
|
|
out.pSong = GAMESTATE->GetDefaultSong();
|
|
|
|
|
out.baseDifficulty = DIFFICULTY_MEDIUM;
|
|
|
|
|
}
|
2005-04-25 22:44:32 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////
|
|
|
|
|
// CourseID
|
|
|
|
|
//////////////////////////////////
|
|
|
|
|
|
2004-04-18 08:36:04 +00:00
|
|
|
void CourseID::FromCourse( const Course *p )
|
|
|
|
|
{
|
|
|
|
|
if( p )
|
|
|
|
|
{
|
2004-04-18 19:36:42 +00:00
|
|
|
if( p->m_bIsAutogen )
|
|
|
|
|
{
|
|
|
|
|
sPath = "";
|
2005-05-23 00:38:09 +00:00
|
|
|
sFullTitle = p->GetTranslitFullTitle();
|
2004-04-18 19:36:42 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
sPath = p->m_sPath;
|
2004-07-11 10:02:38 +00:00
|
|
|
sFullTitle = "";
|
2004-04-18 19:36:42 +00:00
|
|
|
}
|
2004-04-18 08:36:04 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
sPath = "";
|
2004-07-11 10:02:38 +00:00
|
|
|
sFullTitle = "";
|
2004-04-18 08:36:04 +00:00
|
|
|
}
|
2005-05-24 05:26:45 +00:00
|
|
|
|
|
|
|
|
// HACK for backwards compatibility:
|
|
|
|
|
// Strip off leading "/". 2005/05/21 file layer changes added a leading slash.
|
|
|
|
|
if( sPath.Left(1) == "/" )
|
|
|
|
|
sPath.erase( sPath.begin() );
|
2004-04-18 08:36:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Course *CourseID::ToCourse() const
|
|
|
|
|
{
|
2005-05-24 05:26:45 +00:00
|
|
|
// HACK for backwards compatibility:
|
|
|
|
|
// Re-add the leading "/". 2005/05/21 file layer changes added a leading slash.
|
|
|
|
|
CString sPath2 = sPath;
|
|
|
|
|
if( sPath2.Left(1) != "/" )
|
2005-06-08 05:12:11 +00:00
|
|
|
sPath2 = "/" + sPath2;
|
2005-05-24 05:26:45 +00:00
|
|
|
|
|
|
|
|
if( !sPath2.empty() )
|
2004-08-30 21:55:50 +00:00
|
|
|
{
|
2005-05-24 05:26:45 +00:00
|
|
|
Course *pCourse = SONGMAN->GetCourseFromPath( sPath2 );
|
2004-08-30 21:55:50 +00:00
|
|
|
if( pCourse )
|
|
|
|
|
return pCourse;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( !sFullTitle.empty() )
|
|
|
|
|
{
|
|
|
|
|
Course *pCourse = SONGMAN->GetCourseFromName( sFullTitle );
|
|
|
|
|
if( pCourse )
|
|
|
|
|
return pCourse;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
2004-04-18 08:36:04 +00:00
|
|
|
}
|
|
|
|
|
|
2004-04-18 19:36:42 +00:00
|
|
|
XNode* CourseID::CreateNode() const
|
|
|
|
|
{
|
|
|
|
|
XNode* pNode = new XNode;
|
2005-01-07 14:28:00 +00:00
|
|
|
pNode->m_sName = "Course";
|
2004-04-18 19:36:42 +00:00
|
|
|
|
|
|
|
|
if( !sPath.empty() )
|
|
|
|
|
pNode->AppendAttr( "Path", sPath );
|
2004-07-11 10:02:38 +00:00
|
|
|
if( !sFullTitle.empty() )
|
|
|
|
|
pNode->AppendAttr( "FullTitle", sFullTitle );
|
2004-04-18 19:36:42 +00:00
|
|
|
|
|
|
|
|
return pNode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CourseID::LoadFromNode( const XNode* pNode )
|
|
|
|
|
{
|
2005-01-07 14:28:00 +00:00
|
|
|
ASSERT( pNode->m_sName == "Course" );
|
2004-04-18 19:36:42 +00:00
|
|
|
pNode->GetAttrValue("Path", sPath);
|
2004-07-11 10:02:38 +00:00
|
|
|
pNode->GetAttrValue("FullTitle", sFullTitle);
|
2004-04-18 19:36:42 +00:00
|
|
|
}
|
|
|
|
|
|
2004-05-08 10:12:10 +00:00
|
|
|
CString CourseID::ToString() const
|
|
|
|
|
{
|
|
|
|
|
if( !sPath.empty() )
|
|
|
|
|
return sPath;
|
2004-07-11 10:02:38 +00:00
|
|
|
if( !sFullTitle.empty() )
|
|
|
|
|
return sFullTitle;
|
2005-09-04 16:55:21 +00:00
|
|
|
return CString();
|
2004-05-08 10:12:10 +00:00
|
|
|
}
|
|
|
|
|
|
2004-04-18 19:36:42 +00:00
|
|
|
bool CourseID::IsValid() const
|
|
|
|
|
{
|
2004-07-11 10:02:38 +00:00
|
|
|
return !sPath.empty() || !sFullTitle.empty();
|
2004-04-18 19:36:42 +00:00
|
|
|
}
|
2004-05-31 22:42:12 +00:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* (c) 2001-2004 Chris Danford
|
|
|
|
|
* All rights reserved.
|
|
|
|
|
*
|
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
|
* copy of this software and associated documentation files (the
|
|
|
|
|
* "Software"), to deal in the Software without restriction, including
|
|
|
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
|
|
|
* distribute, and/or sell copies of the Software, and to permit persons to
|
|
|
|
|
* whom the Software is furnished to do so, provided that the above
|
|
|
|
|
* copyright notice(s) and this permission notice appear in all copies of
|
|
|
|
|
* the Software and that both the above copyright notice(s) and this
|
|
|
|
|
* permission notice appear in supporting documentation.
|
|
|
|
|
*
|
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
|
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
|
|
|
|
|
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
|
|
|
|
|
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
|
|
|
|
|
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
|
|
|
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
|
|
|
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
|
|
|
* PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
|
*/
|