Files
itgmania212121/stepmania/src/UnlockSystem.cpp
T

452 lines
11 KiB
C++
Raw Normal View History

/*
-----------------------------------------------------------------------------
Class: UnlockSystem
Desc: See header.
Copyright (c) 2001-2003 by the person(s) listed below. All rights reserved.
Kevin Slaughter
Andrew Wong
-----------------------------------------------------------------------------
*/
#include "global.h"
#include "PrefsManager.h"
#include "RageLog.h"
2003-07-09 05:57:09 +00:00
#include "song.h"
2003-07-11 18:08:57 +00:00
#include "Course.h"
#include "RageUtil.h"
#include "UnlockSystem.h"
2003-07-09 05:01:37 +00:00
#include "SongManager.h"
2003-07-11 18:08:57 +00:00
#include "GameState.h"
#include "IniFile.h"
#include "MsdFile.h"
2003-09-19 07:02:53 +00:00
UnlockSystem* UNLOCKSYS = NULL; // global and accessable from anywhere in our program
#define UNLOCKS_PATH "Data/Unlocks.dat"
2003-12-10 09:26:05 +00:00
#define MEMCARD_PATH "Data/MemCard.ini"
2004-01-24 23:40:40 +00:00
static const char *g_UnlockNames[NUM_UNLOCK_TYPES] =
{
2004-01-24 23:40:40 +00:00
"ArcadePointsAccumulated",
"DancePointsAccumulated",
"SongPointsAccumulated",
"ExtraStagesCleared",
"ExtraStagesFailed",
"TotalToastysSeen",
"TotalStagesCleared"
};
2003-09-19 07:02:53 +00:00
2004-01-24 23:40:40 +00:00
UnlockSystem::UnlockSystem()
{
2004-01-25 16:24:34 +00:00
UNLOCKSYS = this;
LoadFromDATFile();
2004-01-24 23:40:40 +00:00
memset( m_fScores, 0, sizeof(m_fScores) );
2004-01-25 16:24:34 +00:00
ReadValues(); // in case its ever accessed,
// we want the values to be available
2004-01-25 16:24:34 +00:00
WriteValues(); // create if it does not exist
}
2004-01-25 16:24:34 +00:00
void UnlockSystem::UnlockSong( const Song *song )
{
2004-01-25 16:24:34 +00:00
const UnlockEntry *p = FindSong( song );
if( !p )
2003-07-18 08:04:47 +00:00
return; // does not exist
2004-01-25 16:24:34 +00:00
if( p->m_iCode == -1 )
return;
2004-01-25 16:24:34 +00:00
UnlockCode( p->m_iCode );
}
bool UnlockSystem::CourseIsLocked( const Course *course )
{
2003-07-18 08:04:47 +00:00
if( !PREFSMAN->m_bUseUnlockSystem )
return false;
2003-08-11 20:57:57 +00:00
UnlockEntry *p = FindCourse( course );
if( p == NULL )
return false;
2004-01-25 16:24:34 +00:00
return p->IsLocked();
}
2003-07-09 04:46:24 +00:00
bool UnlockSystem::SongIsLocked( const Song *song )
{
2003-07-18 08:04:47 +00:00
if( !PREFSMAN->m_bUseUnlockSystem )
return false;
2003-08-11 20:57:57 +00:00
UnlockEntry *p = FindSong( song );
2003-07-12 20:16:07 +00:00
if( p == NULL )
return false;
2004-01-25 16:24:34 +00:00
return p->IsLocked();
2003-07-09 04:46:24 +00:00
}
2004-01-25 16:24:34 +00:00
/* Return true if the song is available in roulette (overriding #SELECTABLE). */
2003-07-09 04:46:24 +00:00
bool UnlockSystem::SongIsRoulette( const Song *song )
{
2004-01-24 22:55:59 +00:00
if( !PREFSMAN->m_bUseUnlockSystem )
return false;
const UnlockEntry *p = FindSong( song );
2004-01-25 16:24:34 +00:00
if( !p )
return false;
2004-01-25 16:24:34 +00:00
/* If the song is locked by a code, and it's a roulette code, honor IsLocked. */
if( p->m_iCode != -1 &&
m_RouletteCodes.find( p->m_iCode ) != m_RouletteCodes.end() )
return p->IsLocked();
return true;
2003-07-09 04:46:24 +00:00
}
2003-08-11 20:57:57 +00:00
UnlockEntry *UnlockSystem::FindLockEntry( CString songname )
{
for( unsigned i = 0; i < m_SongEntries.size(); i++ )
if( !songname.CompareNoCase(m_SongEntries[i].m_sSongName) )
return &m_SongEntries[i];
return NULL;
}
2003-08-11 20:57:57 +00:00
UnlockEntry *UnlockSystem::FindSong( const Song *pSong )
{
for( unsigned i = 0; i < m_SongEntries.size(); i++ )
if( m_SongEntries[i].m_pSong == pSong )
return &m_SongEntries[i];
return NULL;
}
2003-08-11 20:57:57 +00:00
UnlockEntry *UnlockSystem::FindCourse( const Course *pCourse )
{
for(unsigned i = 0; i < m_SongEntries.size(); i++)
2003-07-18 06:38:05 +00:00
if (m_SongEntries[i].m_pCourse== pCourse )
2003-07-09 05:01:37 +00:00
return &m_SongEntries[i];
2003-07-09 05:01:37 +00:00
return NULL;
}
2003-08-11 20:57:57 +00:00
UnlockEntry::UnlockEntry()
{
2004-01-24 23:40:40 +00:00
memset( m_fRequired, 0, sizeof(m_fRequired) );
2004-01-25 16:24:34 +00:00
m_iCode = -1;
2003-07-18 06:38:05 +00:00
m_pSong = NULL;
m_pCourse = NULL;
}
2004-01-25 16:24:34 +00:00
bool UnlockEntry::IsLocked() const
{
2004-01-24 23:40:40 +00:00
for( int i = 0; i < NUM_UNLOCK_TYPES; ++i )
if( m_fRequired[i] && UNLOCKSYS->m_fScores[i] >= m_fRequired[i] )
2004-01-25 16:24:34 +00:00
return false;
2004-01-25 16:24:34 +00:00
if( m_iCode != -1 && UNLOCKSYS->m_UnlockedCodes.find(m_iCode) != UNLOCKSYS->m_UnlockedCodes.end() )
return false;
2004-01-25 16:24:34 +00:00
return true;
}
bool UnlockSystem::LoadFromDATFile()
{
LOG->Trace( "UnlockSystem::LoadFromDATFile()" );
MsdFile msd;
if( !msd.ReadFile( UNLOCKS_PATH ) )
{
LOG->Warn( "Error opening file '%s' for reading: %s.", UNLOCKS_PATH, msd.GetError().c_str() );
return false;
}
2003-07-16 12:58:02 +00:00
unsigned i, j;
for( i=0; i<msd.GetNumValues(); i++ )
{
int iNumParams = msd.GetNumParams(i);
const MsdFile::value_t &sParams = msd.GetValue(i);
CString sValueName = sParams[0];
if( iNumParams < 1 )
{
LOG->Warn("Got \"%s\" tag with no parameters", sValueName.c_str());
continue;
}
2004-01-26 06:47:06 +00:00
if( !stricmp(sParams[0],"ROULETTE") )
2004-01-25 16:24:34 +00:00
{
for( unsigned j = 1; j < sParams.params.size(); ++j )
m_RouletteCodes.insert( atoi(sParams[j]) );
continue;
}
if( stricmp(sParams[0],"UNLOCK") )
{
2003-07-15 10:11:22 +00:00
LOG->Warn("Unrecognized unlock tag \"%s\", ignored.", sValueName.c_str());
continue;
}
2003-08-11 20:57:57 +00:00
UnlockEntry current;
current.m_sSongName = sParams[1];
LOG->Trace("Song entry: %s", current.m_sSongName.c_str() );
CStringArray UnlockTypes;
split( sParams[2], ",", UnlockTypes );
2003-07-16 12:58:02 +00:00
for( j=0; j<UnlockTypes.size(); ++j )
{
CStringArray readparam;
split(UnlockTypes[j], "=", readparam);
CString unlock_type = readparam[0];
float datavalue = (float) atof(readparam[1]);
LOG->Trace("UnlockTypes line: %s", UnlockTypes[j].c_str() );
LOG->Trace("Unlock info: %s %f", unlock_type.c_str(), datavalue);
if( unlock_type == "AP" )
2004-01-24 23:40:40 +00:00
current.m_fRequired[UNLOCK_ARCADE_POINTS] = datavalue;
if( unlock_type == "DP" )
2004-01-24 23:40:40 +00:00
current.m_fRequired[UNLOCK_DANCE_POINTS] = datavalue;
if( unlock_type == "SP" )
2004-01-24 23:40:40 +00:00
current.m_fRequired[UNLOCK_SONG_POINTS] = datavalue;
if( unlock_type == "EC" )
2004-01-24 23:40:40 +00:00
current.m_fRequired[UNLOCK_EXTRA_CLEARED] = datavalue;
if( unlock_type == "EF" )
2004-01-24 23:40:40 +00:00
current.m_fRequired[UNLOCK_EXTRA_CLEARED] = datavalue;
if( unlock_type == "!!" )
2004-01-24 23:40:40 +00:00
current.m_fRequired[UNLOCK_TOASTY] = datavalue;
if( unlock_type == "CS" )
current.m_fRequired[UNLOCK_CLEARED] = datavalue;
2004-01-25 16:24:34 +00:00
if( unlock_type == "CODE" )
current.m_iCode = (int) datavalue;
if( unlock_type == "RO" )
{
2004-01-25 16:24:34 +00:00
m_UnlockedCodes.insert( (int)datavalue );
m_RouletteCodes.insert( (int)datavalue );
}
}
2003-07-16 12:58:02 +00:00
m_SongEntries.push_back(current);
}
2003-07-18 06:38:05 +00:00
UpdateSongs();
for(i=0; i < m_SongEntries.size(); i++)
{
CString tmp = " ";
2004-01-25 16:24:34 +00:00
if (!m_SongEntries[i].IsLocked()) tmp = "un";
LOG->Trace( "UnlockSystem Entry %s", m_SongEntries[i].m_sSongName.c_str() );
2003-07-18 06:38:05 +00:00
if (m_SongEntries[i].m_pSong != NULL)
LOG->Trace( " Translit %s", m_SongEntries[i].m_pSong->GetTranslitMainTitle().c_str() );
2004-01-24 23:40:40 +00:00
LOG->Trace( " AP %f", m_SongEntries[i].m_fRequired[UNLOCK_ARCADE_POINTS] );
LOG->Trace( " DP %f", m_SongEntries[i].m_fRequired[UNLOCK_DANCE_POINTS] );
LOG->Trace( " SP %f", m_SongEntries[i].m_fRequired[UNLOCK_SONG_POINTS] );
LOG->Trace( " CS %f", m_SongEntries[i].m_fRequired[UNLOCK_CLEARED] );
2004-01-25 16:24:34 +00:00
LOG->Trace( " CODE %i", m_SongEntries[i].m_iCode );
LOG->Trace( " Status %slocked", tmp.c_str() );
2003-07-24 14:04:13 +00:00
if (m_SongEntries[i].m_pSong)
LOG->Trace( " Found matching song entry" );
if (m_SongEntries[i].m_pCourse)
LOG->Trace( " Found matching course entry" );
}
return true;
}
2004-01-24 23:40:40 +00:00
float UnlockSystem::PointsUntilNextUnlock( UnlockType t ) const
{
float fSmallestPoints = 400000000; // or an arbitrarily large value
for( unsigned a=0; a<m_SongEntries.size(); a++ )
2004-01-24 23:40:40 +00:00
if( m_SongEntries[a].m_fRequired[t] > m_fScores[t] )
fSmallestPoints = min( fSmallestPoints, m_SongEntries[a].m_fRequired[t] );
if( fSmallestPoints == 400000000 )
return 0; // no match found
2004-01-24 23:40:40 +00:00
return fSmallestPoints - m_fScores[t];
}
2003-07-18 06:38:05 +00:00
/* Update the song pointer. Only call this when it's likely to have changed,
* such as on load, or when a song title changes in the editor. */
void UnlockSystem::UpdateSongs()
2003-07-09 05:01:37 +00:00
{
2003-07-18 06:38:05 +00:00
for( unsigned i = 0; i < m_SongEntries.size(); ++i )
{
m_SongEntries[i].m_pSong = NULL;
m_SongEntries[i].m_pCourse = NULL;
m_SongEntries[i].m_pSong = SONGMAN->FindSong( m_SongEntries[i].m_sSongName );
2003-07-18 06:38:05 +00:00
if( m_SongEntries[i].m_pSong == NULL )
m_SongEntries[i].m_pCourse = SONGMAN->FindCourse( m_SongEntries[i].m_sSongName );
// display warning on invalid song entry
if (m_SongEntries[i].m_pSong == NULL &&
m_SongEntries[i].m_pCourse == NULL)
{
2004-01-25 16:24:34 +00:00
LOG->Warn("Unlock: Cannot find a matching entry for \"%s\"", m_SongEntries[i].m_sSongName.c_str() );
m_SongEntries.erase(m_SongEntries.begin() + i);
2004-01-25 16:24:34 +00:00
--i;
}
2003-07-18 06:38:05 +00:00
}
2003-07-09 05:01:37 +00:00
}
2004-01-25 16:24:34 +00:00
bool UnlockSystem::ReadValues()
{
IniFile data;
2004-01-25 16:24:34 +00:00
data.SetPath( MEMCARD_PATH );
if( !data.ReadFile() )
return false;
2004-01-24 23:40:40 +00:00
for( int i = 0; i < NUM_UNLOCK_TYPES; ++i )
data.GetValue( "Unlock", g_UnlockNames[i], m_fScores[i] );
2004-01-25 16:24:34 +00:00
m_UnlockedCodes.clear();
CString s;
if( data.GetValue( "Unlock", "UnlockedCodes", s ) )
{
vector<CString> sCodes;
split( s, ",", sCodes, true );
for( unsigned c = 0; c < sCodes.size(); ++c )
{
const int n = atoi( sCodes[c] );
m_UnlockedCodes.insert( n );
}
}
return true;
}
2004-01-25 16:24:34 +00:00
bool UnlockSystem::WriteValues() const
{
IniFile data;
2004-01-25 16:24:34 +00:00
data.SetPath( MEMCARD_PATH );
2004-01-24 23:40:40 +00:00
for( int i = 0; i < NUM_UNLOCK_TYPES; ++i )
data.SetValue( "Unlock", g_UnlockNames[i], m_fScores[i] );
2004-01-25 16:24:34 +00:00
vector<CString> sCodes;
for( set<int>::const_iterator it = m_UnlockedCodes.begin(); it != m_UnlockedCodes.end(); ++it )
sCodes.push_back( ssprintf("%i", *it) );
const CString list = join( ",", sCodes );
data.SetValue( "Unlock", "UnlockedCodes", list );
data.WriteFile();
return true;
}
2004-01-24 23:40:40 +00:00
void UnlockSystem::UnlockAddAP(float credit)
{
2004-01-25 16:24:34 +00:00
ReadValues();
2004-01-24 23:40:40 +00:00
m_fScores[UNLOCK_ARCADE_POINTS] += credit;
2004-01-25 16:24:34 +00:00
WriteValues();
}
2004-01-24 23:40:40 +00:00
void UnlockSystem::UnlockAddAP(Grade grade)
{
2004-01-25 16:24:34 +00:00
ReadValues();
2004-01-20 03:32:48 +00:00
switch( grade )
{
case GRADE_FAILED:
; // no points
break;
case GRADE_TIER_1:
case GRADE_TIER_2:
2004-01-24 23:40:40 +00:00
m_fScores[UNLOCK_ARCADE_POINTS] += 9;
2004-01-20 03:32:48 +00:00
break;
case GRADE_NO_DATA:
ASSERT(0);
break;
default:
2004-01-24 23:40:40 +00:00
m_fScores[UNLOCK_ARCADE_POINTS] += 1;
2004-01-20 03:32:48 +00:00
break;
}
2004-01-25 16:24:34 +00:00
WriteValues();
}
2004-01-24 23:40:40 +00:00
void UnlockSystem::UnlockAddDP(float credit)
{
2004-01-25 16:24:34 +00:00
ReadValues();
// we don't want to ever take away dance points
if( credit > 0 )
2004-01-24 23:40:40 +00:00
m_fScores[UNLOCK_DANCE_POINTS] += credit;
2004-01-25 16:24:34 +00:00
WriteValues();
}
2004-01-24 23:40:40 +00:00
void UnlockSystem::UnlockAddSP(float credit)
{
2004-01-25 16:24:34 +00:00
ReadValues();
2004-01-24 23:40:40 +00:00
m_fScores[UNLOCK_SONG_POINTS] += credit;
2004-01-25 16:24:34 +00:00
WriteValues();
}
2004-01-24 23:40:40 +00:00
void UnlockSystem::UnlockAddSP( Grade grade )
{
2004-01-25 16:24:34 +00:00
ReadValues();
2003-07-12 21:41:12 +00:00
2004-01-20 03:32:48 +00:00
// TODO: move these to PREFS
switch( grade )
{
2004-01-24 23:40:40 +00:00
case GRADE_TIER_1:/*AAAA*/ m_fScores[UNLOCK_SONG_POINTS] += 20; break;
case GRADE_TIER_2:/*AAA*/ m_fScores[UNLOCK_SONG_POINTS] += 10; break;
case GRADE_TIER_3:/*AA*/ m_fScores[UNLOCK_SONG_POINTS] += 5; break;
case GRADE_TIER_4:/*A*/ m_fScores[UNLOCK_SONG_POINTS] += 4; break;
case GRADE_TIER_5:/*B*/ m_fScores[UNLOCK_SONG_POINTS] += 3; break;
case GRADE_TIER_6:/*C*/ m_fScores[UNLOCK_SONG_POINTS] += 2; break;
case GRADE_TIER_7:/*D*/ m_fScores[UNLOCK_SONG_POINTS] += 1; break;
2004-01-20 03:32:48 +00:00
}
2004-01-25 16:24:34 +00:00
WriteValues();
}
2004-01-24 23:40:40 +00:00
void UnlockSystem::UnlockClearExtraStage()
{
2004-01-25 16:24:34 +00:00
ReadValues();
2004-01-24 23:40:40 +00:00
++m_fScores[UNLOCK_EXTRA_CLEARED];
2004-01-25 16:24:34 +00:00
WriteValues();
}
2004-01-24 23:40:40 +00:00
void UnlockSystem::UnlockFailExtraStage()
{
2004-01-25 16:24:34 +00:00
ReadValues();
2004-01-24 23:40:40 +00:00
++m_fScores[UNLOCK_EXTRA_FAILED];
2004-01-25 16:24:34 +00:00
WriteValues();
}
2004-01-24 23:40:40 +00:00
void UnlockSystem::UnlockClearStage()
{
2004-01-25 16:24:34 +00:00
ReadValues();
2004-01-24 23:40:40 +00:00
++m_fScores[UNLOCK_CLEARED];
2004-01-25 16:24:34 +00:00
WriteValues();
}
2004-01-24 23:40:40 +00:00
void UnlockSystem::UnlockToasty()
{
2004-01-25 16:24:34 +00:00
ReadValues();
2004-01-24 23:40:40 +00:00
++m_fScores[UNLOCK_TOASTY];
2004-01-25 16:24:34 +00:00
WriteValues();
}
void UnlockSystem::UnlockCode( int num )
{
ReadValues();
m_UnlockedCodes.insert( num );
WriteValues();
2003-07-11 18:08:57 +00:00
}
int UnlockSystem::GetNumUnlocks() const
{
return m_SongEntries.size();
2003-08-10 03:23:17 +00:00
}