2002-05-20 08:59:37 +00:00
|
|
|
#include "stdafx.h"
|
|
|
|
|
/*
|
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
|
Class: Notes
|
|
|
|
|
|
2002-07-27 19:29:51 +00:00
|
|
|
Desc: See header.
|
2002-05-20 08:59:37 +00:00
|
|
|
|
|
|
|
|
Copyright (c) 2001-2002 by the person(s) listed below. All rights reserved.
|
2002-07-27 19:29:51 +00:00
|
|
|
Chris Danford
|
2003-01-02 22:10:51 +00:00
|
|
|
Glenn Maynard
|
2002-05-20 08:59:37 +00:00
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "Notes.h"
|
|
|
|
|
#include "Song.h"
|
|
|
|
|
#include "Notes.h"
|
|
|
|
|
#include "IniFile.h"
|
|
|
|
|
#include "math.h" // for fabs()
|
|
|
|
|
#include "RageUtil.h"
|
|
|
|
|
#include "RageLog.h"
|
2002-07-03 03:13:13 +00:00
|
|
|
#include "NoteData.h"
|
2002-05-20 08:59:37 +00:00
|
|
|
#include "GameInput.h"
|
2002-07-27 19:29:51 +00:00
|
|
|
#include "RageException.h"
|
2002-07-31 19:40:40 +00:00
|
|
|
#include "MsdFile.h"
|
2002-08-23 00:22:27 +00:00
|
|
|
#include "GameManager.h"
|
2002-10-06 16:56:58 +00:00
|
|
|
#include "ThemeManager.h"
|
2002-05-20 08:59:37 +00:00
|
|
|
|
|
|
|
|
|
2003-01-21 22:23:01 +00:00
|
|
|
#define COLOR_BEGINNER THEME->GetMetricC("Notes","ColorBeginner")
|
2002-10-06 16:56:58 +00:00
|
|
|
#define COLOR_EASY THEME->GetMetricC("Notes","ColorEasy")
|
|
|
|
|
#define COLOR_MEDIUM THEME->GetMetricC("Notes","ColorMedium")
|
|
|
|
|
#define COLOR_HARD THEME->GetMetricC("Notes","ColorHard")
|
|
|
|
|
#define COLOR_CHALLENGE THEME->GetMetricC("Notes","ColorChallenge")
|
2002-05-20 08:59:37 +00:00
|
|
|
|
|
|
|
|
Notes::Notes()
|
|
|
|
|
{
|
2002-08-23 00:22:27 +00:00
|
|
|
/* FIXME: should we init this to NOTES_TYPE_INVALID?
|
|
|
|
|
* I have a feeling that it's the right thing to do but that
|
|
|
|
|
* it'd trip obscure asserts all over the place, so I'll wait
|
|
|
|
|
* until after b6 to do this. -glenn */
|
2002-06-30 23:19:33 +00:00
|
|
|
m_NotesType = NOTES_TYPE_DANCE_SINGLE;
|
2003-01-21 22:23:01 +00:00
|
|
|
m_Difficulty = DIFFICULTY_INVALID;
|
2002-05-20 08:59:37 +00:00
|
|
|
m_iMeter = 0;
|
2003-01-30 07:18:33 +00:00
|
|
|
for(int i = 0; i < NUM_RADAR_CATEGORIES; ++i)
|
2002-12-14 06:20:25 +00:00
|
|
|
m_fRadarValues[i] = -1; /* unknown */
|
2002-06-30 23:19:33 +00:00
|
|
|
|
2002-12-14 21:43:00 +00:00
|
|
|
notes = NULL;
|
|
|
|
|
notes_comp = NULL;
|
2003-01-02 22:10:51 +00:00
|
|
|
parent = NULL;
|
2003-01-22 05:29:27 +00:00
|
|
|
|
2003-02-14 21:42:44 +00:00
|
|
|
for( int m=0; m<NUM_MEMORY_CARDS; m++ )
|
2003-01-22 05:29:27 +00:00
|
|
|
{
|
2003-02-14 21:42:44 +00:00
|
|
|
m_MemCardScores[m].iNumTimesPlayed = 0;
|
|
|
|
|
m_MemCardScores[m].grade = GRADE_NO_DATA;
|
|
|
|
|
m_MemCardScores[m].fScore = 0;
|
2003-01-22 05:29:27 +00:00
|
|
|
}
|
2002-05-20 08:59:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Notes::~Notes()
|
|
|
|
|
{
|
2002-12-14 21:43:00 +00:00
|
|
|
delete notes;
|
|
|
|
|
delete notes_comp;
|
2002-05-20 08:59:37 +00:00
|
|
|
}
|
|
|
|
|
|
2002-07-03 21:27:26 +00:00
|
|
|
void Notes::SetNoteData( NoteData* pNewNoteData )
|
|
|
|
|
{
|
2003-02-01 05:16:38 +00:00
|
|
|
ASSERT( pNewNoteData->GetNumTracks() == GameManager::NotesTypeToNumTracks(m_NotesType) );
|
2002-12-14 21:43:00 +00:00
|
|
|
|
2003-01-02 22:10:51 +00:00
|
|
|
DeAutogen();
|
|
|
|
|
|
2002-12-14 21:43:00 +00:00
|
|
|
delete notes_comp;
|
|
|
|
|
notes_comp = NULL;
|
|
|
|
|
|
|
|
|
|
delete notes;
|
|
|
|
|
notes = new NoteData(*pNewNoteData);
|
2002-07-03 21:27:26 +00:00
|
|
|
}
|
2002-05-20 08:59:37 +00:00
|
|
|
|
2002-09-07 05:04:04 +00:00
|
|
|
void Notes::GetNoteData( NoteData* pNoteDataOut ) const
|
2002-07-03 03:13:13 +00:00
|
|
|
{
|
2003-01-19 21:14:27 +00:00
|
|
|
ASSERT(this);
|
2003-01-19 21:13:00 +00:00
|
|
|
ASSERT(pNoteDataOut);
|
2002-12-14 21:43:00 +00:00
|
|
|
Decompress();
|
2003-02-01 05:16:38 +00:00
|
|
|
pNoteDataOut->SetNumTracks( notes->GetNumTracks() );
|
2002-12-14 21:43:00 +00:00
|
|
|
*pNoteDataOut = *notes;
|
2002-07-03 03:13:13 +00:00
|
|
|
}
|
2002-05-20 08:59:37 +00:00
|
|
|
|
2002-12-14 21:33:29 +00:00
|
|
|
void Notes::SetSMNoteData( const CString &out )
|
|
|
|
|
{
|
2002-12-14 21:43:00 +00:00
|
|
|
delete notes;
|
|
|
|
|
notes = NULL;
|
|
|
|
|
|
|
|
|
|
if(!notes_comp)
|
|
|
|
|
notes_comp = new CString;
|
|
|
|
|
|
|
|
|
|
*notes_comp = out;
|
2002-12-14 21:33:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CString Notes::GetSMNoteData() const
|
|
|
|
|
{
|
2002-12-14 21:43:00 +00:00
|
|
|
if(!notes_comp)
|
|
|
|
|
{
|
|
|
|
|
if(!notes) return ""; /* no data is no data */
|
|
|
|
|
notes_comp = new CString(NoteDataUtil::GetSMNoteDataString(*notes));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return *notes_comp;
|
2002-12-14 21:33:29 +00:00
|
|
|
}
|
|
|
|
|
|
2003-01-21 22:23:01 +00:00
|
|
|
RageColor Notes::GetColor() const
|
2002-09-08 22:02:39 +00:00
|
|
|
{
|
2003-01-23 05:51:09 +00:00
|
|
|
switch( GetDifficulty() )
|
2002-10-06 16:56:58 +00:00
|
|
|
{
|
2003-01-21 22:23:01 +00:00
|
|
|
case DIFFICULTY_BEGINNER: return COLOR_BEGINNER;
|
|
|
|
|
case DIFFICULTY_EASY: return COLOR_EASY;
|
|
|
|
|
case DIFFICULTY_MEDIUM: return COLOR_MEDIUM;
|
|
|
|
|
case DIFFICULTY_HARD: return COLOR_HARD;
|
|
|
|
|
case DIFFICULTY_CHALLENGE: return COLOR_CHALLENGE;
|
|
|
|
|
default: ASSERT(0); return COLOR_BEGINNER;
|
2002-10-06 16:56:58 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-21 22:23:01 +00:00
|
|
|
void Notes::TidyUpData()
|
2002-10-06 16:56:58 +00:00
|
|
|
{
|
2003-01-21 22:23:01 +00:00
|
|
|
if( GetDifficulty() == DIFFICULTY_INVALID )
|
2003-02-05 19:48:02 +00:00
|
|
|
SetDifficulty(StringToDifficulty(GetDescription()));
|
2003-01-21 22:23:01 +00:00
|
|
|
|
|
|
|
|
if( GetDifficulty() == DIFFICULTY_INVALID )
|
|
|
|
|
{
|
|
|
|
|
if( GetMeter() == 1 ) SetDifficulty(DIFFICULTY_BEGINNER);
|
|
|
|
|
else if( GetMeter() <= 3 ) SetDifficulty(DIFFICULTY_EASY);
|
|
|
|
|
else if( GetMeter() <= 6 ) SetDifficulty(DIFFICULTY_MEDIUM);
|
|
|
|
|
else SetDifficulty(DIFFICULTY_HARD);
|
2002-10-06 16:56:58 +00:00
|
|
|
}
|
2003-02-05 23:40:52 +00:00
|
|
|
// Meter is overflowing (invalid), but some files (especially maniac/smaniac steps) are purposefully set higher than 10.
|
|
|
|
|
// See: BMR's Gravity; we probably should keep those as difficult as we can represent.
|
2003-02-09 01:30:06 +00:00
|
|
|
/* Why? If the data file says a meter of 72, we should keep it as 72; if
|
|
|
|
|
* individual bits of code (eg. scoring, feet) have maximums, they should
|
|
|
|
|
* enforce it internally. Doing it here will make us lose the difficulty
|
|
|
|
|
* completely if the song is edited and written. -glenn */
|
|
|
|
|
/* if( GetMeter() >10 ) {
|
2003-02-05 23:40:52 +00:00
|
|
|
if( GetDifficulty() == DIFFICULTY_HARD || GetDifficulty() == DIFFICULTY_CHALLENGE)
|
|
|
|
|
SetMeter(10);
|
|
|
|
|
else
|
|
|
|
|
SetMeter(0);
|
2003-02-09 01:30:06 +00:00
|
|
|
} */
|
2003-02-05 23:40:52 +00:00
|
|
|
if( GetMeter() < 1) // meter is invalid
|
2002-07-03 03:13:13 +00:00
|
|
|
{
|
2003-01-21 22:23:01 +00:00
|
|
|
// guess meter from difficulty class
|
2003-01-02 22:10:51 +00:00
|
|
|
switch( GetDifficulty() )
|
2002-06-30 23:19:33 +00:00
|
|
|
{
|
2003-01-21 22:23:01 +00:00
|
|
|
case DIFFICULTY_BEGINNER: SetMeter(1); break;
|
|
|
|
|
case DIFFICULTY_EASY: SetMeter(3); break;
|
|
|
|
|
case DIFFICULTY_MEDIUM: SetMeter(5); break;
|
|
|
|
|
case DIFFICULTY_HARD: SetMeter(8); break;
|
|
|
|
|
case DIFFICULTY_CHALLENGE: SetMeter(8); break;
|
|
|
|
|
case DIFFICULTY_INVALID: SetMeter(5); break;
|
2002-07-03 03:13:13 +00:00
|
|
|
default: ASSERT(0);
|
2002-06-30 23:19:33 +00:00
|
|
|
}
|
|
|
|
|
}
|
2002-05-20 08:59:37 +00:00
|
|
|
}
|
|
|
|
|
|
2002-06-27 17:49:10 +00:00
|
|
|
|
2002-05-20 08:59:37 +00:00
|
|
|
//////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
//////////////////////////////////////////////
|
|
|
|
|
|
2002-10-24 08:17:09 +00:00
|
|
|
bool CompareNotesPointersByRadarValues(const Notes* pNotes1, const Notes* pNotes2)
|
2002-07-11 19:02:26 +00:00
|
|
|
{
|
|
|
|
|
float fScore1 = 0;
|
|
|
|
|
float fScore2 = 0;
|
|
|
|
|
|
2003-01-30 07:18:33 +00:00
|
|
|
for( int r=0; r<NUM_RADAR_CATEGORIES; r++ )
|
2002-07-11 19:02:26 +00:00
|
|
|
{
|
2003-01-02 22:10:51 +00:00
|
|
|
fScore1 += pNotes1->GetRadarValues()[r];
|
|
|
|
|
fScore2 += pNotes2->GetRadarValues()[r];
|
2002-07-11 19:02:26 +00:00
|
|
|
}
|
|
|
|
|
|
2002-10-24 08:17:09 +00:00
|
|
|
return fScore1 < fScore2;
|
2002-07-11 19:02:26 +00:00
|
|
|
}
|
|
|
|
|
|
2002-10-24 08:17:09 +00:00
|
|
|
bool CompareNotesPointersByMeter(const Notes *pNotes1, const Notes* pNotes2)
|
2002-05-20 08:59:37 +00:00
|
|
|
{
|
2003-02-05 00:33:14 +00:00
|
|
|
return pNotes1->GetMeter() < pNotes2->GetMeter();
|
2002-05-20 08:59:37 +00:00
|
|
|
}
|
|
|
|
|
|
2002-10-24 08:17:09 +00:00
|
|
|
bool CompareNotesPointersByDifficulty(const Notes *pNotes1, const Notes *pNotes2)
|
2002-05-20 08:59:37 +00:00
|
|
|
{
|
2003-02-05 00:33:14 +00:00
|
|
|
return pNotes1->GetDifficulty() < pNotes2->GetDifficulty();
|
2002-08-01 13:42:56 +00:00
|
|
|
}
|
|
|
|
|
|
2003-01-03 05:56:28 +00:00
|
|
|
void SortNotesArrayByDifficulty( vector<Notes*> &arraySteps )
|
2002-05-20 08:59:37 +00:00
|
|
|
{
|
2003-02-05 00:33:14 +00:00
|
|
|
/* Sort in reverse order of priority. */
|
|
|
|
|
stable_sort( arraySteps.begin(), arraySteps.end(), CompareNotesPointersByRadarValues );
|
|
|
|
|
stable_sort( arraySteps.begin(), arraySteps.end(), CompareNotesPointersByMeter );
|
|
|
|
|
stable_sort( arraySteps.begin(), arraySteps.end(), CompareNotesPointersByDifficulty );
|
2002-05-20 08:59:37 +00:00
|
|
|
}
|
|
|
|
|
|
2002-12-14 21:43:00 +00:00
|
|
|
void Notes::Decompress() const
|
|
|
|
|
{
|
|
|
|
|
if(notes) return;
|
|
|
|
|
|
2003-01-02 22:10:51 +00:00
|
|
|
if(parent)
|
|
|
|
|
{
|
|
|
|
|
NoteData pdata;
|
|
|
|
|
parent->GetNoteData(&pdata);
|
|
|
|
|
|
|
|
|
|
notes = new NoteData;
|
2003-02-01 05:16:38 +00:00
|
|
|
notes->SetNumTracks( GameManager::NotesTypeToNumTracks(m_NotesType) );
|
|
|
|
|
if(pdata.GetNumTracks() == notes->GetNumTracks())
|
2003-01-02 22:10:51 +00:00
|
|
|
notes->CopyRange( &pdata, 0, pdata.GetLastRow(), 0 );
|
|
|
|
|
else
|
2003-02-01 05:16:38 +00:00
|
|
|
notes->LoadTransformedSlidingWindow( &pdata, notes->GetNumTracks() );
|
2003-01-02 22:10:51 +00:00
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(!notes_comp) return; /* no data is no data */
|
|
|
|
|
|
2002-12-14 21:43:00 +00:00
|
|
|
notes = new NoteData;
|
2003-02-01 05:16:38 +00:00
|
|
|
notes->SetNumTracks( GameManager::NotesTypeToNumTracks(m_NotesType) );
|
2002-12-14 21:43:00 +00:00
|
|
|
|
|
|
|
|
NoteDataUtil::LoadFromSMNoteDataString(*notes, *notes_comp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Notes::Compress() const
|
|
|
|
|
{
|
|
|
|
|
if(!notes_comp)
|
|
|
|
|
{
|
|
|
|
|
if(!notes) return; /* no data is no data */
|
|
|
|
|
notes_comp = new CString(NoteDataUtil::GetSMNoteDataString(*notes));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delete notes;
|
|
|
|
|
notes = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-02 22:10:51 +00:00
|
|
|
/* Copy our parent's data. This is done when we're being changed from autogen
|
|
|
|
|
* to normal. (needed?) */
|
|
|
|
|
void Notes::DeAutogen()
|
|
|
|
|
{
|
|
|
|
|
if(!parent)
|
|
|
|
|
return; /* OK */
|
|
|
|
|
|
|
|
|
|
m_iMeter = Real()->m_iMeter;
|
|
|
|
|
m_sDescription = Real()->m_sDescription;
|
|
|
|
|
m_Difficulty = Real()->m_Difficulty;
|
2003-01-30 07:18:33 +00:00
|
|
|
for(int i = 0; i < NUM_RADAR_CATEGORIES; ++i)
|
2003-01-02 22:10:51 +00:00
|
|
|
m_fRadarValues[i] = Real()->m_fRadarValues[i];
|
|
|
|
|
|
|
|
|
|
delete notes;
|
|
|
|
|
notes = NULL;
|
|
|
|
|
|
|
|
|
|
if(!notes_comp)
|
|
|
|
|
notes_comp = new CString;
|
|
|
|
|
|
|
|
|
|
*notes_comp = parent->GetSMNoteData();
|
|
|
|
|
|
|
|
|
|
parent = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Notes::AutogenFrom( Notes *parent_, NotesType ntTo )
|
|
|
|
|
{
|
|
|
|
|
parent = parent_;
|
|
|
|
|
m_NotesType = ntTo;
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-30 07:18:33 +00:00
|
|
|
void Notes::BakeAutoGen()
|
|
|
|
|
{
|
2003-02-11 21:41:43 +00:00
|
|
|
Decompress();
|
2003-01-30 07:18:33 +00:00
|
|
|
parent = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Notes::CopyFrom( Notes* pSource, NotesType ntTo ) // pSource does not have to be of the same NotesType!
|
|
|
|
|
{
|
|
|
|
|
m_NotesType = ntTo;
|
|
|
|
|
NoteData noteData;
|
|
|
|
|
pSource->GetNoteData( ¬eData );
|
2003-02-01 05:16:38 +00:00
|
|
|
noteData.SetNumTracks( GameManager::NotesTypeToNumTracks(ntTo) );
|
2003-01-30 07:18:33 +00:00
|
|
|
this->SetNoteData( ¬eData );
|
|
|
|
|
this->SetDescription( "Copied from "+pSource->GetDescription() );
|
|
|
|
|
this->SetDifficulty( pSource->GetDifficulty() );
|
|
|
|
|
this->SetMeter( pSource->GetMeter() );
|
|
|
|
|
|
|
|
|
|
const float* radarValues = pSource->GetRadarValues();
|
|
|
|
|
for( int r=0; r<NUM_RADAR_CATEGORIES; r++ )
|
|
|
|
|
this->SetRadarValue( (RadarCategory)r, radarValues[r] );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Notes::CreateBlank( NotesType ntTo )
|
|
|
|
|
{
|
|
|
|
|
m_NotesType = ntTo;
|
|
|
|
|
NoteData noteData;
|
2003-02-01 05:16:38 +00:00
|
|
|
noteData.SetNumTracks( GameManager::NotesTypeToNumTracks(ntTo) );
|
2003-01-30 07:18:33 +00:00
|
|
|
this->SetNoteData( ¬eData );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-01-02 22:10:51 +00:00
|
|
|
const Notes *Notes::Real() const
|
|
|
|
|
{
|
|
|
|
|
if(parent) return parent;
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Notes::IsAutogen() const
|
|
|
|
|
{
|
|
|
|
|
return parent != NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Notes::SetDescription(CString desc)
|
|
|
|
|
{
|
|
|
|
|
DeAutogen();
|
|
|
|
|
m_sDescription = desc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Notes::SetDifficulty(Difficulty d)
|
|
|
|
|
{
|
|
|
|
|
DeAutogen();
|
|
|
|
|
m_Difficulty = d;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Notes::SetMeter(int meter)
|
|
|
|
|
{
|
|
|
|
|
DeAutogen();
|
|
|
|
|
m_iMeter = meter;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Notes::SetRadarValue(int r, float val)
|
|
|
|
|
{
|
|
|
|
|
DeAutogen();
|
2003-01-30 07:18:33 +00:00
|
|
|
ASSERT(r < NUM_RADAR_CATEGORIES);
|
2003-01-02 22:10:51 +00:00
|
|
|
m_fRadarValues[r] = val;
|
|
|
|
|
}
|
|
|
|
|
|
2003-02-14 21:42:44 +00:00
|
|
|
void Notes::AddScore( PlayerNumber pn, Grade grade, float fScore, bool& bNewRecordOut )
|
2003-01-22 05:29:27 +00:00
|
|
|
{
|
2003-02-14 21:42:44 +00:00
|
|
|
bNewRecordOut = false;
|
|
|
|
|
|
|
|
|
|
m_MemCardScores[MEMORY_CARD_MACHINE].iNumTimesPlayed++;
|
|
|
|
|
m_MemCardScores[pn].iNumTimesPlayed++;
|
|
|
|
|
|
2003-01-24 02:43:07 +00:00
|
|
|
if( fScore > m_MemCardScores[pn].fScore )
|
2003-01-22 05:29:27 +00:00
|
|
|
{
|
2003-01-24 02:43:07 +00:00
|
|
|
m_MemCardScores[pn].fScore = fScore;
|
2003-01-22 05:29:27 +00:00
|
|
|
m_MemCardScores[pn].grade = grade;
|
2003-02-14 21:42:44 +00:00
|
|
|
bNewRecordOut = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( fScore > m_MemCardScores[MEMORY_CARD_MACHINE].fScore )
|
|
|
|
|
{
|
|
|
|
|
m_MemCardScores[MEMORY_CARD_MACHINE].fScore = fScore;
|
|
|
|
|
m_MemCardScores[MEMORY_CARD_MACHINE].grade = grade;
|
2003-01-22 05:29:27 +00:00
|
|
|
}
|
|
|
|
|
}
|