Files
itgmania212121/stepmania/src/UnlockSystem.cpp
T

401 lines
9.6 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 "MsdFile.h"
#include "ProfileManager.h"
2004-02-21 01:06:35 +00:00
UnlockSystem* UNLOCKMAN = NULL; // global and accessable from anywhere in our program
2003-09-19 07:02:53 +00:00
#define UNLOCKS_PATH "Data/Unlocks.dat"
2003-12-10 09:26:05 +00:00
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-02-21 01:06:35 +00:00
UNLOCKMAN = this;
2004-01-25 16:24:34 +00:00
2004-02-22 05:16:12 +00:00
Load();
}
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 );
}
2004-02-22 21:25:22 +00:00
bool UnlockSystem::CourseIsLocked( const Course *course ) const
{
2003-07-18 08:04:47 +00:00
if( !PREFSMAN->m_bUseUnlockSystem )
return false;
2004-02-22 21:25:22 +00:00
const UnlockEntry *p = FindCourse( course );
if( p == NULL )
return false;
2004-01-25 16:24:34 +00:00
return p->IsLocked();
}
2004-02-22 21:25:22 +00:00
bool UnlockSystem::SongIsLocked( const Song *song ) const
2003-07-09 04:46:24 +00:00
{
2003-07-18 08:04:47 +00:00
if( !PREFSMAN->m_bUseUnlockSystem )
return false;
2004-02-22 21:25:22 +00:00
const 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-02-26 20:35:46 +00:00
/* Return true if the song is *only* available in roulette. */
bool UnlockSystem::SongIsRouletteOnly( const Song *song ) const
2003-07-09 04:46:24 +00:00
{
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. */
2004-02-26 20:35:46 +00:00
if( p->m_iCode == -1 || m_RouletteCodes.find( p->m_iCode ) == m_RouletteCodes.end() )
return false;
return p->IsLocked();
2003-07-09 04:46:24 +00:00
}
2004-02-22 21:25:22 +00:00
const UnlockEntry *UnlockSystem::FindLockEntry( CString songname ) const
{
for( unsigned i = 0; i < m_SongEntries.size(); i++ )
if( !songname.CompareNoCase(m_SongEntries[i].m_sSongName) )
return &m_SongEntries[i];
return NULL;
}
2004-02-22 21:25:22 +00:00
const UnlockEntry *UnlockSystem::FindSong( const Song *pSong ) const
{
for( unsigned i = 0; i < m_SongEntries.size(); i++ )
if( m_SongEntries[i].m_pSong == pSong )
return &m_SongEntries[i];
return NULL;
}
2004-02-22 21:25:22 +00:00
const UnlockEntry *UnlockSystem::FindCourse( const Course *pCourse ) const
{
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;
}
static float GetArcadePoints( const Profile *pProfile )
{
float fAP = 0;
FOREACH_Grade(g)
{
switch(g)
{
case GRADE_TIER_1:
case GRADE_TIER_2: fAP += 9 * pProfile->m_iNumSongsPassedByGrade[g]; break;
default: fAP += 1 * pProfile->m_iNumSongsPassedByGrade[g]; break;
case GRADE_FAILED:
case GRADE_NO_DATA:
; // no points
break;
}
}
FOREACH_PlayMode(pm)
{
switch(pm)
{
case PLAY_MODE_NONSTOP:
case PLAY_MODE_ONI:
case PLAY_MODE_ENDLESS:
fAP += pProfile->m_iNumSongsPlayedByPlayMode[pm];
break;
}
}
return fAP;
}
static float GetSongPoints( const Profile *pProfile )
{
float fSP = 0;
FOREACH_Grade(g)
{
switch( g )
{
case GRADE_TIER_1:/*AAAA*/ fSP += 20 * pProfile->m_iNumSongsPassedByGrade[g]; break;
case GRADE_TIER_2:/*AAA*/ fSP += 10* pProfile->m_iNumSongsPassedByGrade[g]; break;
case GRADE_TIER_3:/*AA*/ fSP += 5* pProfile->m_iNumSongsPassedByGrade[g]; break;
case GRADE_TIER_4:/*A*/ fSP += 4* pProfile->m_iNumSongsPassedByGrade[g]; break;
case GRADE_TIER_5:/*B*/ fSP += 3* pProfile->m_iNumSongsPassedByGrade[g]; break;
case GRADE_TIER_6:/*C*/ fSP += 2* pProfile->m_iNumSongsPassedByGrade[g]; break;
case GRADE_TIER_7:/*D*/ fSP += 1* pProfile->m_iNumSongsPassedByGrade[g]; break;
case GRADE_FAILED:
case GRADE_NO_DATA:
; // no points
break;
}
}
FOREACH_PlayMode(pm)
{
switch(pm)
{
case PLAY_MODE_NONSTOP:
case PLAY_MODE_ONI:
case PLAY_MODE_ENDLESS:
fSP += pProfile->m_iNumSongsPlayedByPlayMode[pm];
break;
}
}
return fSP;
}
void UnlockSystem::GetPoints( const Profile *pProfile, float fScores[NUM_UNLOCK_TYPES] ) const
{
fScores[UNLOCK_ARCADE_POINTS] = GetArcadePoints( pProfile );
fScores[UNLOCK_SONG_POINTS] = GetSongPoints( pProfile );
fScores[UNLOCK_DANCE_POINTS] = (float) pProfile->m_iTotalDancePoints;
fScores[UNLOCK_CLEARED] = (float) pProfile->GetTotalNumSongsPassed();
}
2004-01-25 16:24:34 +00:00
bool UnlockEntry::IsLocked() const
{
float fScores[NUM_UNLOCK_TYPES];
UNLOCKMAN->GetPoints( PROFILEMAN->GetMachineProfile(), fScores );
2004-01-24 23:40:40 +00:00
for( int i = 0; i < NUM_UNLOCK_TYPES; ++i )
if( m_fRequired[i] && fScores[i] >= m_fRequired[i] )
2004-01-25 16:24:34 +00:00
return false;
if( m_iCode != -1 && PROFILEMAN->GetMachineProfile()->m_UnlockedSongs.find(m_iCode) != PROFILEMAN->GetMachineProfile()->m_UnlockedSongs.end() )
2004-01-25 16:24:34 +00:00
return false;
2004-01-25 16:24:34 +00:00
return true;
}
2004-02-22 05:16:12 +00:00
static const char *g_ShortUnlockNames[NUM_UNLOCK_TYPES] =
{
2004-02-22 05:16:12 +00:00
"AP",
"DP",
"SP",
"EC",
"EF",
"!!",
"CS"
};
static UnlockType StringToUnlockType( const CString &s )
{
for( int i = 0; i < NUM_UNLOCK_TYPES; ++i )
if( g_ShortUnlockNames[i] == s )
return (UnlockType) i;
return UNLOCK_INVALID;
}
bool UnlockSystem::Load()
{
LOG->Trace( "UnlockSystem::Load()" );
2004-02-22 05:16:12 +00:00
if( !IsAFile(UNLOCKS_PATH) )
return false;
MsdFile msd;
if( !msd.ReadFile( UNLOCKS_PATH ) )
{
LOG->Warn( "Error opening file '%s' for reading: %s.", UNLOCKS_PATH, msd.GetError().c_str() );
return false;
}
2004-02-22 05:16:12 +00:00
unsigned i;
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 );
2004-02-22 05:16:12 +00:00
for( unsigned j=0; j<UnlockTypes.size(); ++j )
{
CStringArray readparam;
2004-02-22 05:16:12 +00:00
split( UnlockTypes[j], "=", readparam );
const CString &unlock_type = readparam[0];
LOG->Trace("UnlockTypes line: %s", UnlockTypes[j].c_str() );
2004-02-22 05:16:12 +00:00
const float fVal = (float) atof( readparam[1] );
const int iVal = atoi( readparam[1] );
2004-02-22 05:16:12 +00:00
const UnlockType ut = StringToUnlockType( unlock_type );
if( ut != UNLOCK_INVALID )
current.m_fRequired[ut] = fVal;
2004-01-25 16:24:34 +00:00
if( unlock_type == "CODE" )
current.m_iCode = iVal;
if( unlock_type == "RO" )
{
current.m_iCode = iVal;
m_RouletteCodes.insert( iVal );
}
}
2003-07-16 12:58:02 +00:00
m_SongEntries.push_back(current);
}
2003-07-18 06:38:05 +00:00
UpdateSongs();
2004-02-22 05:16:12 +00:00
for(i=0; i < m_SongEntries.size(); i++)
{
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-02-22 05:16:12 +00:00
for( int j = 0; j < NUM_UNLOCK_TYPES; ++j )
if( m_SongEntries[i].m_fRequired[j] )
LOG->Trace( " %s %f", g_UnlockNames[j], m_SongEntries[i].m_fRequired[j] );
2004-01-25 16:24:34 +00:00
LOG->Trace( " CODE %i", m_SongEntries[i].m_iCode );
2004-02-22 05:16:12 +00:00
LOG->Trace( " Status %s", m_SongEntries[i].IsLocked()? "locked":"unlocked" );
if( m_SongEntries[i].m_pSong )
2003-07-24 14:04:13 +00:00
LOG->Trace( " Found matching song entry" );
2004-02-22 05:16:12 +00:00
if( m_SongEntries[i].m_pCourse )
2003-07-24 14:04:13 +00:00
LOG->Trace( " Found matching course entry" );
}
return true;
}
2004-01-24 23:40:40 +00:00
float UnlockSystem::PointsUntilNextUnlock( UnlockType t ) const
{
float fScores[NUM_UNLOCK_TYPES];
UNLOCKMAN->GetPoints( PROFILEMAN->GetMachineProfile(), fScores );
float fSmallestPoints = 400000000; // or an arbitrarily large value
for( unsigned a=0; a<m_SongEntries.size(); a++ )
if( m_SongEntries[a].m_fRequired[t] > fScores[t] )
2004-01-24 23:40:40 +00:00
fSmallestPoints = min( fSmallestPoints, m_SongEntries[a].m_fRequired[t] );
if( fSmallestPoints == 400000000 )
return 0; // no match found
return fSmallestPoints - 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
void UnlockSystem::UnlockCode( int num )
{
FOREACH_PlayerNumber( pn )
if( PROFILEMAN->IsUsingProfile(pn) )
PROFILEMAN->GetProfile(pn)->m_UnlockedSongs.insert( num );
PROFILEMAN->GetMachineProfile()->m_UnlockedSongs.insert( num );
2003-07-11 18:08:57 +00:00
}
int UnlockSystem::GetNumUnlocks() const
{
return m_SongEntries.size();
2003-08-10 03:23:17 +00:00
}