2003-07-09 03:10:01 +00:00
#include "global.h"
2006-01-28 21:37:13 +00:00
#include "UnlockManager.h"
2003-07-09 03:10:01 +00:00
#include "PrefsManager.h"
#include "RageLog.h"
2008-03-09 01:51:34 +00:00
#include "Song.h"
2003-07-11 18:08:57 +00:00
#include "Course.h"
2003-07-09 03:10:01 +00:00
#include "RageUtil.h"
2003-07-09 05:01:37 +00:00
#include "SongManager.h"
2003-07-11 18:08:57 +00:00
#include "GameState.h"
2004-02-22 08:16:49 +00:00
#include "ProfileManager.h"
2005-07-01 05:07:22 +00:00
#include "Profile.h"
2005-02-25 01:28:45 +00:00
#include "ThemeManager.h"
2005-03-29 00:31:57 +00:00
#include "Foreach.h"
2005-04-24 19:41:52 +00:00
#include "Steps.h"
2005-03-29 19:10:42 +00:00
#include <float.h>
2006-01-29 22:17:43 +00:00
#include "CommonMetrics.h"
2006-09-26 01:46:15 +00:00
#include "LuaManager.h"
2003-07-09 03:10:01 +00:00
2005-02-21 06:13:31 +00:00
UnlockManager * UNLOCKMAN = NULL ; // global and accessable from anywhere in our program
2003-09-19 07:02:53 +00:00
2006-07-27 06:45:47 +00:00
#define UNLOCK_NAMES THEME->GetMetric ("UnlockManager","UnlockNames")
2006-10-11 10:50:17 +00:00
#define UNLOCK(x) THEME->GetMetricR("UnlockManager", ssprintf("Unlock%sCommand",x.c_str()));
2003-12-10 09:26:05 +00:00
2008-05-15 09:57:29 +00:00
static ThemeMetric < bool > AUTO_LOCK_CHALLENGE_STEPS ( "UnlockManager" , "AutoLockChallengeSteps" );
2006-01-29 22:17:43 +00:00
static const char * UnlockRequirementNames [] =
2004-01-24 23:40:40 +00:00
{
2005-02-25 01:28:45 +00:00
"ArcadePoints" ,
"DancePoints" ,
"SongPoints" ,
"ExtraCleared" ,
"ExtraFailed" ,
"Toasties" ,
"StagesCleared"
2004-01-24 23:40:40 +00:00
};
2006-10-15 00:09:18 +00:00
XToString ( UnlockRequirement );
2006-01-29 22:17:43 +00:00
StringToX ( UnlockRequirement );
2006-09-26 07:13:54 +00:00
LuaXType ( UnlockRequirement );
2006-01-29 22:17:43 +00:00
static const char * UnlockRewardTypeNames [] =
{
"Song" ,
"Steps" ,
"Course" ,
"Modifier" ,
};
2006-10-15 00:09:18 +00:00
XToString ( UnlockRewardType );
2006-01-29 22:17:43 +00:00
XToLocalizedString ( UnlockRewardType );
2006-09-27 06:25:18 +00:00
LuaXType ( UnlockRewardType );
LuaFunction ( UnlockRewardTypeToLocalizedString , UnlockRewardTypeToLocalizedString ( Enum :: Check < UnlockRewardType > ( L , 1 )) );
2004-01-24 23:40:40 +00:00
2005-02-21 06:13:31 +00:00
UnlockManager :: UnlockManager ()
2003-07-09 03:10:01 +00:00
{
2006-09-21 04:27:45 +00:00
// Register with Lua.
{
Lua * L = LUA -> Get ();
lua_pushstring ( L , "UNLOCKMAN" );
this -> PushSelf ( L );
lua_settable ( L , LUA_GLOBALSINDEX );
LUA -> Release ( L );
}
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 ();
2003-07-09 03:10:01 +00:00
}
2006-09-21 04:27:45 +00:00
UnlockManager ::~ UnlockManager ()
{
// Unregister with Lua.
LUA -> UnsetGlobal ( "UNLOCKMAN" );
}
2005-02-21 06:13:31 +00:00
void UnlockManager :: UnlockSong ( const Song * song )
2003-07-09 11:38:50 +00:00
{
2004-01-25 16:24:34 +00:00
const UnlockEntry * p = FindSong ( song );
2004-01-24 19:39:18 +00:00
if ( ! p )
2003-07-18 08:04:47 +00:00
return ; // does not exist
2006-05-03 22:56:23 +00:00
if ( p -> m_sEntryID . empty () )
2004-01-25 16:24:34 +00:00
return ;
2003-07-09 11:38:50 +00:00
2006-05-03 22:56:23 +00:00
UnlockEntryID ( p -> m_sEntryID );
2003-07-09 11:38:50 +00:00
}
2006-05-03 22:56:23 +00:00
RString UnlockManager :: FindEntryID ( const RString & sName ) const
2005-04-24 00:07:12 +00:00
{
const UnlockEntry * pEntry = NULL ;
const Song * pSong = SONGMAN -> FindSong ( sName );
if ( pSong != NULL )
pEntry = FindSong ( pSong );
const Course * pCourse = SONGMAN -> FindCourse ( sName );
if ( pCourse != NULL )
pEntry = FindCourse ( pCourse );
if ( pEntry == NULL )
pEntry = FindModifier ( sName );
if ( pEntry == NULL )
{
LOG -> Warn ( "Couldn't find locked entry \" %s \" " , sName . c_str () );
2006-05-03 22:56:23 +00:00
return "" ;
2005-04-24 00:07:12 +00:00
}
2006-05-03 22:56:23 +00:00
return pEntry -> m_sEntryID ;
2005-04-24 00:07:12 +00:00
}
2007-08-15 20:31:47 +00:00
int UnlockManager :: CourseIsLocked ( const Course * pCourse ) const
2003-07-10 11:24:16 +00:00
{
2007-08-15 20:31:47 +00:00
int iRet = 0 ;
2008-05-15 02:22:14 +00:00
2007-08-15 20:31:47 +00:00
if ( PREFSMAN -> m_bUseUnlockSystem )
{
const UnlockEntry * p = FindCourse ( pCourse );
if ( p == NULL )
return false ;
if ( p -> IsLocked () )
iRet |= LOCKED_LOCK ;
}
2003-07-18 08:04:47 +00:00
2007-08-15 20:37:34 +00:00
/* If a course uses a song that is disabled, disable the course too. */
FOREACH_CONST ( CourseEntry , pCourse -> m_vEntries , e )
{
const CourseEntry & ce = * e ;
const Song * pSong = ce . songID . ToSong ();
if ( pSong == NULL )
continue ;
int iSongLock = SongIsLocked ( pSong );
if ( iSongLock & LOCKED_DISABLED )
iRet |= LOCKED_DISABLED ;
}
2007-08-15 20:31:47 +00:00
return iRet ;
2003-07-10 11:24:16 +00:00
}
2003-07-09 03:10:01 +00:00
2007-08-13 21:20:51 +00:00
int UnlockManager :: SongIsLocked ( const Song * pSong ) const
2003-07-09 04:46:24 +00:00
{
2007-08-13 21:20:51 +00:00
int iRet = 0 ;
if ( PREFSMAN -> m_bUseUnlockSystem )
{
const UnlockEntry * p = FindSong ( pSong );
if ( p != NULL && p -> IsLocked () )
2007-08-16 01:24:55 +00:00
{
2007-08-13 21:20:51 +00:00
iRet |= LOCKED_LOCK ;
2007-08-16 01:24:55 +00:00
if ( ! p -> m_sEntryID . empty () && m_RouletteCodes . find ( p -> m_sEntryID ) != m_RouletteCodes . end () )
iRet |= LOCKED_ROULETTE ;
}
2007-08-13 21:20:51 +00:00
}
if ( PREFSMAN -> m_bHiddenSongs && pSong -> m_SelectionDisplay == Song :: SHOW_NEVER )
iRet |= LOCKED_SELECTABLE ;
2008-05-15 02:22:14 +00:00
2007-08-13 21:20:51 +00:00
if ( ! pSong -> m_bEnabled )
iRet |= LOCKED_DISABLED ;
2008-05-15 02:22:14 +00:00
2007-08-13 21:20:51 +00:00
return iRet ;
2003-07-09 04:46:24 +00:00
}
2005-04-24 19:41:52 +00:00
bool UnlockManager :: StepsIsLocked ( const Song * pSong , const Steps * pSteps ) const
{
if ( ! PREFSMAN -> m_bUseUnlockSystem )
return false ;
const UnlockEntry * p = FindSteps ( pSong , pSteps );
if ( p == NULL )
return false ;
return p -> IsLocked ();
}
2006-01-22 01:00:06 +00:00
bool UnlockManager :: ModifierIsLocked ( const RString & sOneMod ) const
2005-03-29 01:44:36 +00:00
{
if ( ! PREFSMAN -> m_bUseUnlockSystem )
return false ;
const UnlockEntry * p = FindModifier ( sOneMod );
if ( p == NULL )
return false ;
return p -> IsLocked ();
}
2005-04-24 19:41:52 +00:00
const UnlockEntry * UnlockManager :: FindSong ( const Song * pSong ) const
2003-07-10 14:44:13 +00:00
{
2005-03-29 01:44:36 +00:00
FOREACH_CONST ( UnlockEntry , m_UnlockEntries , e )
2007-08-15 20:56:44 +00:00
if ( e -> m_Song . ToSong () == pSong && e -> m_dc == Difficulty_Invalid )
2005-03-29 01:44:36 +00:00
return & ( * e );
2003-07-10 14:44:13 +00:00
return NULL ;
}
2005-04-24 19:41:52 +00:00
const UnlockEntry * UnlockManager :: FindSteps ( const Song * pSong , const Steps * pSteps ) const
2003-07-10 11:24:16 +00:00
{
2005-05-26 08:07:42 +00:00
ASSERT ( pSong && pSteps );
2005-03-29 01:44:36 +00:00
FOREACH_CONST ( UnlockEntry , m_UnlockEntries , e )
2007-08-15 20:56:44 +00:00
if ( e -> m_Song . ToSong () == pSong && e -> m_dc == pSteps -> GetDifficulty () )
2005-03-29 01:44:36 +00:00
return & ( * e );
2003-07-10 11:24:16 +00:00
return NULL ;
}
2005-02-21 06:13:31 +00:00
const UnlockEntry * UnlockManager :: FindCourse ( const Course * pCourse ) const
2003-07-09 03:10:01 +00:00
{
2005-03-29 01:44:36 +00:00
FOREACH_CONST ( UnlockEntry , m_UnlockEntries , e )
2007-08-15 21:01:23 +00:00
if ( e -> m_Course . ToCourse () == pCourse )
2005-03-29 01:44:36 +00:00
return & ( * e );
return NULL ;
}
2003-07-09 13:54:23 +00:00
2006-01-22 01:00:06 +00:00
const UnlockEntry * UnlockManager :: FindModifier ( const RString & sOneMod ) const
2005-03-29 01:44:36 +00:00
{
FOREACH_CONST ( UnlockEntry , m_UnlockEntries , e )
2006-03-10 17:06:55 +00:00
if ( e -> GetModifier (). CompareNoCase ( sOneMod ) == 0 )
2005-03-29 01:44:36 +00:00
return & ( * e );
2003-07-09 05:01:37 +00:00
return NULL ;
2003-07-09 03:10:01 +00:00
}
2004-02-22 08:16:49 +00:00
static float GetArcadePoints ( const Profile * pProfile )
{
float fAP = 0 ;
2007-02-23 22:29:42 +00:00
FOREACH_ENUM ( Grade , g )
2004-02-22 08:16:49 +00:00
{
switch ( g )
{
2005-08-14 11:38:31 +00:00
case Grade_Tier01 :
case Grade_Tier02 : fAP += 9 * pProfile -> m_iNumStagesPassedByGrade [ g ]; break ;
2004-08-30 06:07:14 +00:00
default : fAP += 1 * pProfile -> m_iNumStagesPassedByGrade [ g ]; break ;
2004-02-22 08:16:49 +00:00
2005-08-14 11:38:31 +00:00
case Grade_Failed :
case Grade_NoData :
2004-02-22 08:16:49 +00:00
; // no points
break ;
}
}
2007-02-23 22:29:42 +00:00
FOREACH_ENUM ( PlayMode , pm )
2004-02-22 08:16:49 +00:00
{
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 ;
2007-02-23 22:29:42 +00:00
FOREACH_ENUM ( Grade , g )
2004-02-22 08:16:49 +00:00
{
switch ( g )
{
2005-08-14 11:38:31 +00:00
case Grade_Tier01 : /*AAAA*/ fSP += 20 * pProfile -> m_iNumStagesPassedByGrade [ g ]; break ;
case Grade_Tier02 : /*AAA*/ fSP += 10 * pProfile -> m_iNumStagesPassedByGrade [ g ]; break ;
case Grade_Tier03 : /*AA*/ fSP += 5 * pProfile -> m_iNumStagesPassedByGrade [ g ]; break ;
case Grade_Tier04 : /*A*/ fSP += 4 * pProfile -> m_iNumStagesPassedByGrade [ g ]; break ;
case Grade_Tier05 : /*B*/ fSP += 3 * pProfile -> m_iNumStagesPassedByGrade [ g ]; break ;
case Grade_Tier06 : /*C*/ fSP += 2 * pProfile -> m_iNumStagesPassedByGrade [ g ]; break ;
case Grade_Tier07 : /*D*/ fSP += 1 * pProfile -> m_iNumStagesPassedByGrade [ g ]; break ;
case Grade_Failed :
case Grade_NoData :
2004-02-22 08:16:49 +00:00
; // no points
break ;
}
}
2007-02-23 22:29:42 +00:00
FOREACH_ENUM ( PlayMode , pm )
2004-02-22 08:16:49 +00:00
{
switch ( pm )
{
case PLAY_MODE_NONSTOP :
case PLAY_MODE_ONI :
case PLAY_MODE_ENDLESS :
fSP += pProfile -> m_iNumSongsPlayedByPlayMode [ pm ];
break ;
}
}
return fSP ;
}
2006-01-29 22:17:43 +00:00
void UnlockManager :: GetPoints ( const Profile * pProfile , float fScores [ NUM_UnlockRequirement ] ) const
2004-02-22 08:16:49 +00:00
{
2006-01-29 22:17:43 +00:00
fScores [ UnlockRequirement_ArcadePoints ] = GetArcadePoints ( pProfile );
fScores [ UnlockRequirement_SongPoints ] = GetSongPoints ( pProfile );
fScores [ UnlockRequirement_DancePoints ] = ( float ) pProfile -> m_iTotalDancePoints ;
fScores [ UnlockRequirement_StagesCleared ] = ( float ) pProfile -> GetTotalNumSongsPassed ();
2004-02-22 08:16:49 +00:00
}
2003-07-09 03:10:01 +00:00
2005-04-30 04:11:55 +00:00
/* Return true if all songs and/or courses referenced by an unlock are available. */
bool UnlockEntry :: IsValid () const
{
switch ( m_Type )
{
2006-01-29 22:17:43 +00:00
case UnlockRewardType_Song :
2007-08-15 20:56:44 +00:00
return m_Song . IsValid ();
2005-04-30 04:11:55 +00:00
2006-01-29 22:17:43 +00:00
case UnlockRewardType_Steps :
2007-08-15 20:56:44 +00:00
return m_Song . IsValid () && m_dc != Difficulty_Invalid ;
2005-04-30 04:11:55 +00:00
2006-01-29 22:17:43 +00:00
case UnlockRewardType_Course :
2007-08-15 21:01:23 +00:00
return m_Course . IsValid ();
2005-04-30 04:11:55 +00:00
2006-01-29 22:17:43 +00:00
case UnlockRewardType_Modifier :
2005-04-30 04:11:55 +00:00
return true ;
default :
WARN ( ssprintf ( "%i" , m_Type ) );
return false ;
}
}
2006-05-03 21:34:05 +00:00
UnlockEntryStatus UnlockEntry :: GetUnlockEntryStatus () const
2003-07-09 03:10:01 +00:00
{
2006-05-03 22:56:23 +00:00
if ( ! m_sEntryID . empty () && PROFILEMAN -> GetMachineProfile () -> m_UnlockedEntryIDs . find ( m_sEntryID ) != PROFILEMAN -> GetMachineProfile () -> m_UnlockedEntryIDs . end () )
2006-05-03 21:34:05 +00:00
return UnlockEntryStatus_Unlocked ;
2006-01-29 22:17:43 +00:00
float fScores [ NUM_UnlockRequirement ];
2004-02-22 08:16:49 +00:00
UNLOCKMAN -> GetPoints ( PROFILEMAN -> GetMachineProfile (), fScores );
2006-01-29 22:17:43 +00:00
for ( int i = 0 ; i < NUM_UnlockRequirement ; ++ i )
if ( m_fRequirement [ i ] && fScores [ i ] >= m_fRequirement [ i ] )
2006-05-03 21:34:05 +00:00
return UnlockEntryStatus_RequirementsMet ;
2003-07-18 06:38:05 +00:00
2007-08-15 20:56:44 +00:00
if ( m_bRequirePassHardSteps && m_Song . IsValid () )
2006-03-20 22:41:41 +00:00
{
2007-08-15 20:56:44 +00:00
Song * pSong = m_Song . ToSong ();
2006-03-20 22:41:41 +00:00
vector < Steps *> vp ;
2006-06-13 01:10:37 +00:00
SongUtil :: GetSteps (
2007-08-15 20:56:44 +00:00
pSong ,
2006-03-20 22:41:41 +00:00
vp ,
2006-09-26 20:28:46 +00:00
StepsType_Invalid ,
2007-02-22 07:18:05 +00:00
Difficulty_Hard
2006-03-20 22:41:41 +00:00
);
FOREACH_CONST ( Steps * , vp , s )
2007-08-15 20:56:44 +00:00
if ( PROFILEMAN -> GetMachineProfile () -> HasPassedSteps ( pSong , * s ) )
2006-05-03 21:34:05 +00:00
return UnlockEntryStatus_RequirementsMet ;
2006-03-20 22:41:41 +00:00
}
2006-03-13 08:03:17 +00:00
2006-05-03 21:34:05 +00:00
return UnlockEntryStatus_RequrementsNotMet ;
2003-07-09 03:10:01 +00:00
}
2006-01-29 22:17:43 +00:00
RString UnlockEntry :: GetDescription () const
{
2007-08-15 20:56:44 +00:00
Song * pSong = m_Song . ToSong ();
2006-01-29 22:17:43 +00:00
switch ( m_Type )
{
default :
ASSERT ( 0 );
return "" ;
case UnlockRewardType_Song :
2007-08-15 20:56:44 +00:00
return pSong ? pSong -> GetDisplayFullTitle () : "" ;
2006-01-29 22:17:43 +00:00
case UnlockRewardType_Steps :
2008-03-24 12:00:51 +00:00
{
2008-11-28 22:02:28 +00:00
return ( pSong ? pSong -> GetDisplayFullTitle () : "" ) + ", " + GetLocalizedCustomDifficulty ( m_dc , StepsTypeCategory_Single ); // TODO: Is using "Single" the best thing we can do here?
2008-03-24 12:00:51 +00:00
}
2006-01-29 22:17:43 +00:00
case UnlockRewardType_Course :
2007-08-15 21:01:23 +00:00
return m_Course . IsValid () ? m_Course . ToCourse () -> GetDisplayFullTitle () : "" ;
2006-01-29 22:17:43 +00:00
case UnlockRewardType_Modifier :
return CommonMetrics :: LocalizeOptionItem ( GetModifier (), false );
2006-05-03 22:56:23 +00:00
}
2006-01-29 22:17:43 +00:00
}
RString UnlockEntry :: GetBannerFile () const
{
2007-08-15 20:56:44 +00:00
Song * pSong = m_Song . ToSong ();
2006-01-29 22:17:43 +00:00
switch ( m_Type )
{
default :
ASSERT ( 0 );
return "" ;
case UnlockRewardType_Song :
case UnlockRewardType_Steps :
2007-08-15 20:56:44 +00:00
return pSong ? pSong -> GetBannerPath () : "" ;
2006-01-29 22:17:43 +00:00
case UnlockRewardType_Course :
2007-08-15 21:01:23 +00:00
return m_Course . ToCourse () ? m_Course . ToCourse () -> GetBannerPath () : "" ;
2006-01-29 22:17:43 +00:00
case UnlockRewardType_Modifier :
return "" ;
}
}
RString UnlockEntry :: GetBackgroundFile () const
{
2007-08-15 20:56:44 +00:00
Song * pSong = m_Song . ToSong ();
2006-01-29 22:17:43 +00:00
switch ( m_Type )
{
default :
ASSERT ( 0 );
return "" ;
case UnlockRewardType_Song :
case UnlockRewardType_Steps :
2007-08-15 20:56:44 +00:00
return pSong ? pSong -> GetBackgroundPath () : "" ;
2006-01-29 22:17:43 +00:00
case UnlockRewardType_Course :
return "" ;
case UnlockRewardType_Modifier :
return "" ;
}
}
/////////////////////////////////////////////////////////
2005-02-25 01:28:45 +00:00
void UnlockManager :: Load ()
2004-02-22 05:16:12 +00:00
{
2005-02-21 06:13:31 +00:00
LOG -> Trace ( "UnlockManager::Load()" );
2004-02-22 05:16:12 +00:00
2006-01-22 01:00:06 +00:00
vector < RString > asUnlockNames ;
2005-02-25 01:28:45 +00:00
split ( UNLOCK_NAMES , "," , asUnlockNames );
2006-10-11 02:02:31 +00:00
Lua * L = LUA -> Get ();
2005-02-25 01:28:45 +00:00
for ( unsigned i = 0 ; i < asUnlockNames . size (); ++ i )
2003-07-09 03:10:01 +00:00
{
2006-01-22 01:00:06 +00:00
const RString & sUnlockName = asUnlockNames [ i ];
2003-07-09 03:10:01 +00:00
2006-10-11 02:02:31 +00:00
LuaReference cmds = UNLOCK ( sUnlockName );
2003-07-09 03:10:01 +00:00
2003-08-11 20:57:57 +00:00
UnlockEntry current ;
2006-10-11 02:02:31 +00:00
current . m_sEntryID = sUnlockName ; // default
2003-07-09 03:10:01 +00:00
2006-10-11 02:02:31 +00:00
// function
cmds . PushSelf ( L );
ASSERT ( ! lua_isnil ( L , - 1 ) );
2005-03-29 01:44:36 +00:00
2006-10-11 02:02:31 +00:00
// 1st parameter
current . PushSelf ( L );
// call function with 1 argument and 0 results
lua_call ( L , 1 , 0 );
2003-07-16 12:58:02 +00:00
2006-10-11 02:02:31 +00:00
if ( current . m_bRoulette )
2006-05-03 22:56:23 +00:00
m_RouletteCodes . insert ( current . m_sEntryID );
2005-02-25 01:28:45 +00:00
2005-03-29 01:44:36 +00:00
m_UnlockEntries . push_back ( current );
2003-07-09 03:10:01 +00:00
}
2006-10-11 02:02:31 +00:00
LUA -> Release ( L );
2003-07-15 00:52:01 +00:00
2006-03-20 22:41:41 +00:00
if ( AUTO_LOCK_CHALLENGE_STEPS )
{
2007-04-07 05:36:40 +00:00
FOREACH_CONST ( Song * , SONGMAN -> GetSongs (), s )
2006-03-20 22:41:41 +00:00
{
2006-05-25 18:46:40 +00:00
// If no hard steps to play to unlock, skip
2007-02-22 07:18:05 +00:00
if ( SongUtil :: GetOneSteps ( * s , StepsType_Invalid , Difficulty_Hard ) == NULL )
2006-03-20 22:41:41 +00:00
continue ;
2006-05-25 18:46:40 +00:00
// If no challenge steps to unlock, skip
2007-02-22 07:18:05 +00:00
if ( SongUtil :: GetOneSteps ( * s , StepsType_Invalid , Difficulty_Challenge ) == NULL )
2006-05-25 18:46:40 +00:00
continue ;
2006-05-03 22:56:23 +00:00
if ( SONGMAN -> WasLoadedFromAdditionalSongs ( * s ) )
continue ;
2006-03-20 22:41:41 +00:00
UnlockEntry ue ;
2006-10-11 02:02:31 +00:00
ue . m_sEntryID = "_challenge_" + ( * s ) -> GetSongDir ();
2006-03-20 22:41:41 +00:00
ue . m_Type = UnlockRewardType_Steps ;
2006-10-11 02:02:31 +00:00
ue . m_cmd . Load ( ( * s ) -> m_sGroupName + "/" + ( * s ) -> GetTranslitFullTitle () + ",expert" );
2006-03-24 18:29:40 +00:00
ue . m_bRequirePassHardSteps = true ;
2006-03-20 22:41:41 +00:00
m_UnlockEntries . push_back ( ue );
}
}
// Make sure that we don't have duplicate unlock IDs. This can cause problems
// with UnlockCelebrate and with codes.
FOREACH_CONST ( UnlockEntry , m_UnlockEntries , ue )
FOREACH_CONST ( UnlockEntry , m_UnlockEntries , ue2 )
if ( ue != ue2 )
2006-05-03 22:56:23 +00:00
ASSERT_M ( ue -> m_sEntryID != ue2 -> m_sEntryID , ssprintf ( "duplicate unlock entry id %s" , ue -> m_sEntryID . c_str ()) );
2006-03-20 22:41:41 +00:00
2007-08-15 23:35:48 +00:00
FOREACH ( UnlockEntry , m_UnlockEntries , e )
{
switch ( e -> m_Type )
{
case UnlockRewardType_Song :
e -> m_Song . FromSong ( SONGMAN -> FindSong ( e -> m_cmd . GetArg ( 0 ). s ) );
if ( ! e -> m_Song . IsValid () )
LOG -> Warn ( "Unlock: Cannot find song matching \" %s \" " , e -> m_cmd . GetArg ( 0 ). s . c_str () );
break ;
case UnlockRewardType_Steps :
e -> m_Song . FromSong ( SONGMAN -> FindSong ( e -> m_cmd . GetArg ( 0 ). s ) );
if ( ! e -> m_Song . IsValid () )
{
LOG -> Warn ( "Unlock: Cannot find song matching \" %s \" " , e -> m_cmd . GetArg ( 0 ). s . c_str () );
break ;
}
2008-11-28 21:10:41 +00:00
e -> m_dc = StringToDifficulty ( e -> m_cmd . GetArg ( 1 ). s );
2007-08-15 23:35:48 +00:00
if ( e -> m_dc == Difficulty_Invalid )
{
LOG -> Warn ( "Unlock: Invalid difficulty \" %s \" " , e -> m_cmd . GetArg ( 1 ). s . c_str () );
break ;
}
break ;
case UnlockRewardType_Course :
e -> m_Course . FromCourse ( SONGMAN -> FindCourse ( e -> m_cmd . GetArg ( 0 ). s ) );
if ( ! e -> m_Course . IsValid () )
LOG -> Warn ( "Unlock: Cannot find course matching \" %s \" " , e -> m_cmd . GetArg ( 0 ). s . c_str () );
break ;
case UnlockRewardType_Modifier :
// nothing to cache
break ;
default :
ASSERT ( 0 );
}
}
2004-02-22 05:16:12 +00:00
2006-03-20 22:41:41 +00:00
//
// Log unlocks
//
2005-03-29 01:44:36 +00:00
FOREACH_CONST ( UnlockEntry , m_UnlockEntries , e )
2003-07-09 11:38:50 +00:00
{
2006-01-22 01:00:06 +00:00
RString str = ssprintf ( "Unlock: %s; " , join ( " \n " , e -> m_cmd . m_vsArgs ). c_str () );
2006-10-07 08:56:58 +00:00
FOREACH_ENUM ( UnlockRequirement , j )
2006-01-29 22:17:43 +00:00
if ( e -> m_fRequirement [ j ] )
str += ssprintf ( "%s = %f; " , UnlockRequirementToString ( j ). c_str (), e -> m_fRequirement [ j ] );
2006-03-24 18:29:40 +00:00
if ( e -> m_bRequirePassHardSteps )
2006-10-11 02:02:31 +00:00
str += "RequirePassHardSteps; " ;
2004-02-22 05:16:12 +00:00
2006-05-03 22:56:23 +00:00
str += ssprintf ( "entryID = %s " , e -> m_sEntryID . c_str () );
2005-03-29 01:44:36 +00:00
str += e -> IsLocked () ? "locked" : "unlocked" ;
2007-08-15 20:56:44 +00:00
if ( e -> m_Song . IsValid () )
2004-08-05 20:15:54 +00:00
str += ( " (found song)" );
2007-08-15 21:01:23 +00:00
if ( e -> m_Course . IsValid () )
2004-08-05 20:15:54 +00:00
str += ( " (found course)" );
2004-08-05 17:50:30 +00:00
LOG -> Trace ( "%s" , str . c_str () );
2003-07-09 11:38:50 +00:00
}
2003-07-09 03:10:01 +00:00
2005-02-25 01:28:45 +00:00
return ;
2003-07-09 03:10:01 +00:00
}
2006-05-02 22:02:18 +00:00
void UnlockManager :: Reload ()
{
// clear old data, if any
m_UnlockEntries . clear ();
m_RouletteCodes . clear ();
Load ();
}
2006-01-29 22:17:43 +00:00
float UnlockManager :: PointsUntilNextUnlock ( UnlockRequirement t ) const
2003-07-09 03:10:01 +00:00
{
2006-01-29 22:17:43 +00:00
float fScores [ NUM_UnlockRequirement ];
2006-06-05 07:36:23 +00:00
ZERO ( fScores );
2007-05-05 11:13:24 +00:00
GetPoints ( PROFILEMAN -> GetMachineProfile (), fScores );
2004-02-22 08:16:49 +00:00
2005-03-29 19:10:42 +00:00
float fSmallestPoints = FLT_MAX ; // or an arbitrarily large value
2005-03-29 01:44:36 +00:00
for ( unsigned a = 0 ; a < m_UnlockEntries . size (); a ++ )
2006-01-29 22:17:43 +00:00
if ( m_UnlockEntries [ a ]. m_fRequirement [ t ] > fScores [ t ] )
fSmallestPoints = min ( fSmallestPoints , m_UnlockEntries [ a ]. m_fRequirement [ t ] );
2003-07-09 03:10:01 +00:00
2005-03-29 19:10:42 +00:00
if ( fSmallestPoints == FLT_MAX )
2004-01-24 19:39:18 +00:00
return 0 ; // no match found
2004-02-22 08:16:49 +00:00
return fSmallestPoints - fScores [ t ];
2003-07-09 06:05:43 +00:00
}
2006-05-03 22:56:23 +00:00
void UnlockManager :: UnlockEntryID ( RString sEntryID )
2004-01-25 16:24:34 +00:00
{
2006-05-03 22:56:23 +00:00
PROFILEMAN -> GetMachineProfile () -> m_UnlockedEntryIDs . insert ( sEntryID );
2006-06-12 10:49:44 +00:00
SONGMAN -> InvalidateCachedTrails ();
2003-07-11 18:08:57 +00:00
}
2003-07-25 00:03:05 +00:00
2006-03-20 22:41:41 +00:00
void UnlockManager :: UnlockEntryIndex ( int iEntryIndex )
{
2006-05-03 22:56:23 +00:00
RString sEntryID = m_UnlockEntries [ iEntryIndex ]. m_sEntryID ;
UnlockEntryID ( sEntryID );
2006-03-20 22:41:41 +00:00
}
2006-05-03 22:56:23 +00:00
void UnlockManager :: PreferUnlockEntryID ( RString sUnlockEntryID )
2005-02-24 22:34:54 +00:00
{
2005-03-29 01:44:36 +00:00
for ( unsigned i = 0 ; i < m_UnlockEntries . size (); ++ i )
2005-02-24 22:34:54 +00:00
{
2005-03-29 01:44:36 +00:00
UnlockEntry & pEntry = m_UnlockEntries [ i ];
2006-05-03 22:56:23 +00:00
if ( pEntry . m_sEntryID != sUnlockEntryID )
2005-02-24 22:34:54 +00:00
continue ;
2007-08-15 20:56:44 +00:00
if ( pEntry . m_Song . ToSong () != NULL )
GAMESTATE -> m_pPreferredSong = pEntry . m_Song . ToSong ();
2007-08-15 21:01:23 +00:00
if ( pEntry . m_Course . ToCourse () )
GAMESTATE -> m_pPreferredCourse = pEntry . m_Course . ToCourse ();
2005-02-24 22:34:54 +00:00
}
}
2005-02-21 06:13:31 +00:00
int UnlockManager :: GetNumUnlocks () const
2003-07-25 00:03:05 +00:00
{
2005-03-29 01:44:36 +00:00
return m_UnlockEntries . size ();
2003-08-10 03:23:17 +00:00
}
2004-06-08 01:24:17 +00:00
2006-05-03 21:34:05 +00:00
int UnlockManager :: GetNumUnlocked () const
2006-01-30 08:13:16 +00:00
{
2006-05-03 21:34:05 +00:00
int count = 0 ;
2006-01-30 08:13:16 +00:00
FOREACH_CONST ( UnlockEntry , m_UnlockEntries , ue )
{
2006-05-03 21:34:05 +00:00
if ( ue -> GetUnlockEntryStatus () == UnlockEntryStatus_Unlocked )
count ++ ;
2006-01-30 08:13:16 +00:00
}
2006-05-03 21:34:05 +00:00
return count ;
2006-01-30 08:13:16 +00:00
}
2006-03-13 08:03:17 +00:00
int UnlockManager :: GetUnlockEntryIndexToCelebrate () const
{
FOREACH_CONST ( UnlockEntry , m_UnlockEntries , ue )
{
2006-05-03 21:34:05 +00:00
if ( ue -> GetUnlockEntryStatus () == UnlockEntryStatus_RequirementsMet )
2006-01-30 08:13:16 +00:00
return ue - m_UnlockEntries . begin ();
}
return - 1 ;
}
bool UnlockManager :: AnyUnlocksToCelebrate () const
{
2006-03-20 22:41:41 +00:00
return GetUnlockEntryIndexToCelebrate () != - 1 ;
2006-01-30 08:13:16 +00:00
}
2006-01-29 22:17:43 +00:00
void UnlockManager :: GetUnlocksByType ( UnlockRewardType t , vector < UnlockEntry *> & apEntries )
2005-04-30 04:11:55 +00:00
{
for ( unsigned i = 0 ; i < m_UnlockEntries . size (); ++ i )
if ( m_UnlockEntries [ i ]. IsValid () && m_UnlockEntries [ i ]. m_Type == t )
apEntries . push_back ( & m_UnlockEntries [ i ] );
}
2006-05-03 22:56:23 +00:00
void UnlockManager :: GetSongsUnlockedByEntryID ( vector < Song *> & apSongsOut , RString sUnlockEntryID )
2005-04-30 04:11:55 +00:00
{
vector < UnlockEntry *> apEntries ;
2006-01-29 22:17:43 +00:00
GetUnlocksByType ( UnlockRewardType_Song , apEntries );
2005-04-30 04:11:55 +00:00
for ( unsigned i = 0 ; i < apEntries . size (); ++ i )
2006-05-03 22:56:23 +00:00
if ( apEntries [ i ] -> m_sEntryID == sUnlockEntryID )
2007-08-15 20:56:44 +00:00
apSongsOut . push_back ( apEntries [ i ] -> m_Song . ToSong () );
2005-04-30 04:11:55 +00:00
}
2006-05-03 22:56:23 +00:00
void UnlockManager :: GetStepsUnlockedByEntryID ( vector < Song *> & apSongsOut , vector < Difficulty > & apDifficultyOut , RString sUnlockEntryID )
2005-04-30 04:11:55 +00:00
{
vector < UnlockEntry *> apEntries ;
2006-01-29 22:17:43 +00:00
GetUnlocksByType ( UnlockRewardType_Steps , apEntries );
2005-04-30 04:11:55 +00:00
for ( unsigned i = 0 ; i < apEntries . size (); ++ i )
{
2006-05-03 22:56:23 +00:00
if ( apEntries [ i ] -> m_sEntryID == sUnlockEntryID )
2005-04-30 04:11:55 +00:00
{
2007-08-15 20:56:44 +00:00
apSongsOut . push_back ( apEntries [ i ] -> m_Song . ToSong () );
2005-04-30 04:11:55 +00:00
apDifficultyOut . push_back ( apEntries [ i ] -> m_dc );
}
}
}
2006-01-29 22:17:43 +00:00
// lua start
2005-02-21 06:51:04 +00:00
#include "LuaBinding.h"
2006-01-29 22:17:43 +00:00
class LunaUnlockEntry : public Luna < UnlockEntry >
{
public :
static int IsLocked ( T * p , lua_State * L ) { lua_pushboolean ( L , p -> IsLocked () ); return 1 ; }
static int GetDescription ( T * p , lua_State * L ) { lua_pushstring ( L , p -> GetDescription () ); return 1 ; }
static int GetUnlockRewardType ( T * p , lua_State * L ) { lua_pushnumber ( L , p -> m_Type ); return 1 ; }
2006-09-26 04:09:09 +00:00
static int GetRequirement ( T * p , lua_State * L ) { UnlockRequirement i = Enum :: Check < UnlockRequirement > ( L , 1 ); lua_pushnumber ( L , p -> m_fRequirement [ i ] ); return 1 ; }
2006-03-24 18:32:31 +00:00
static int GetRequirePassHardSteps ( T * p , lua_State * L ){ lua_pushboolean ( L , p -> m_bRequirePassHardSteps ); return 1 ; }
2008-09-18 07:55:29 +00:00
static int GetSong ( T * p , lua_State * L )
{
Song * pSong = p -> m_Song . ToSong ();
if ( pSong ) { pSong -> PushSelf ( L ); return 1 ; }
return 0 ;
}
2006-01-29 22:17:43 +00:00
2006-10-11 02:02:31 +00:00
static int GetArgs ( T * p , lua_State * L )
{
Command cmd ;
for ( int i = 1 ; i <= lua_gettop ( L ); ++ i )
cmd . m_vsArgs . push_back ( SArg ( i ) );
p -> m_cmd = cmd ;
return 0 ;
}
static int song ( T * p , lua_State * L ) { GetArgs ( p , L ); p -> m_Type = UnlockRewardType_Song ; return 0 ; }
static int steps ( T * p , lua_State * L ) { GetArgs ( p , L ); p -> m_Type = UnlockRewardType_Steps ; return 0 ; }
static int course ( T * p , lua_State * L ) { GetArgs ( p , L ); p -> m_Type = UnlockRewardType_Course ; return 0 ; }
static int mod ( T * p , lua_State * L ) { GetArgs ( p , L ); p -> m_Type = UnlockRewardType_Modifier ; return 0 ; }
static int code ( T * p , lua_State * L ) { p -> m_sEntryID = SArg ( 1 ); return 0 ; }
static int roulette ( T * p , lua_State * L ) { p -> m_bRoulette = true ; return 0 ; }
static int requirepasshardsteps ( T * p , lua_State * L ) { p -> m_bRequirePassHardSteps = true ; return 0 ; }
static int require ( T * p , lua_State * L )
{
const UnlockRequirement ut = Enum :: Check < UnlockRequirement > ( L , 1 );
if ( ut != UnlockRequirement_Invalid )
p -> m_fRequirement [ ut ] = FArg ( 2 );
return 0 ;
}
2006-09-27 20:30:29 +00:00
LunaUnlockEntry ()
2006-01-29 22:17:43 +00:00
{
ADD_METHOD ( IsLocked );
ADD_METHOD ( GetDescription );
ADD_METHOD ( GetUnlockRewardType );
ADD_METHOD ( GetRequirement );
2006-03-24 18:32:31 +00:00
ADD_METHOD ( GetRequirePassHardSteps );
2008-09-18 07:55:29 +00:00
ADD_METHOD ( GetSong );
2006-10-11 02:02:31 +00:00
ADD_METHOD ( song );
ADD_METHOD ( steps );
ADD_METHOD ( course );
ADD_METHOD ( mod );
ADD_METHOD ( code );
ADD_METHOD ( roulette );
ADD_METHOD ( requirepasshardsteps );
ADD_METHOD ( require );
2006-01-29 22:17:43 +00:00
}
};
LUA_REGISTER_CLASS ( UnlockEntry )
2005-06-20 05:02:03 +00:00
class LunaUnlockManager : public Luna < UnlockManager >
2005-02-21 06:51:04 +00:00
{
public :
2008-08-15 00:08:43 +00:00
static int GetPointsUntilNextUnlock ( T * p , lua_State * L )
{
const UnlockRequirement ut = Enum :: Check < UnlockRequirement > ( L , 1 );
lua_pushnumber ( L , p -> PointsUntilNextUnlock ( ut ) );
return 1 ;
}
2006-05-03 22:56:23 +00:00
static int FindEntryID ( T * p , lua_State * L ) { RString sName = SArg ( 1 ); RString s = p -> FindEntryID ( sName ); if ( s . empty () ) lua_pushnil ( L ); else lua_pushstring ( L , s ); return 1 ; }
static int UnlockEntryID ( T * p , lua_State * L ) { RString sUnlockEntryID = SArg ( 1 ); p -> UnlockEntryID ( sUnlockEntryID ); return 0 ; }
2006-03-26 07:14:44 +00:00
static int UnlockEntryIndex ( T * p , lua_State * L ) { int iUnlockEntryID = IArg ( 1 ); p -> UnlockEntryIndex ( iUnlockEntryID ); return 0 ; }
2006-05-03 22:56:23 +00:00
static int PreferUnlockEntryID ( T * p , lua_State * L ) { RString sUnlockEntryID = SArg ( 1 ); p -> PreferUnlockEntryID ( sUnlockEntryID ); return 0 ; }
2006-01-30 08:13:16 +00:00
static int GetNumUnlocks ( T * p , lua_State * L ) { lua_pushnumber ( L , p -> GetNumUnlocks () ); return 1 ; }
2006-05-03 21:34:05 +00:00
static int GetNumUnlocked ( T * p , lua_State * L ) { lua_pushnumber ( L , p -> GetNumUnlocked () ); return 1 ; }
2008-08-14 19:45:20 +00:00
static int GetUnlockEntryIndexToCelebrate ( T * p , lua_State * L ) { lua_pushnumber ( L , p -> GetUnlockEntryIndexToCelebrate () ); return 1 ; }
2006-01-30 08:13:16 +00:00
static int AnyUnlocksToCelebrate ( T * p , lua_State * L ) { lua_pushboolean ( L , p -> AnyUnlocksToCelebrate () ); return 1 ; }
2007-05-27 08:55:28 +00:00
static int GetUnlockEntry ( T * p , lua_State * L ) { unsigned iIndex = IArg ( 1 ); if ( iIndex >= p -> m_UnlockEntries . size () ) return 0 ; p -> m_UnlockEntries [ iIndex ]. PushSelf ( L ); return 1 ; }
2006-01-28 22:08:16 +00:00
static int GetSongsUnlockedByEntryID ( T * p , lua_State * L )
2005-04-30 04:11:55 +00:00
{
vector < Song *> apSongs ;
2006-05-03 22:56:23 +00:00
UNLOCKMAN -> GetSongsUnlockedByEntryID ( apSongs , SArg ( 1 ) );
2005-04-30 04:11:55 +00:00
LuaHelpers :: CreateTableFromArray ( apSongs , L );
return 1 ;
}
2006-01-28 22:08:16 +00:00
static int GetStepsUnlockedByEntryID ( T * p , lua_State * L )
2005-04-30 04:11:55 +00:00
{
// Return the song each steps are associated with, too.
vector < Song *> apSongs ;
vector < Difficulty > apDifficulty ;
2006-05-03 22:56:23 +00:00
UNLOCKMAN -> GetStepsUnlockedByEntryID ( apSongs , apDifficulty , SArg ( 1 ) );
2005-04-30 04:11:55 +00:00
LuaHelpers :: CreateTableFromArray ( apSongs , L );
LuaHelpers :: CreateTableFromArray ( apDifficulty , L );
return 2 ;
}
2005-02-21 06:51:04 +00:00
2006-09-27 20:30:29 +00:00
LunaUnlockManager ()
2005-02-21 06:51:04 +00:00
{
2008-08-15 00:08:43 +00:00
ADD_METHOD ( GetPointsUntilNextUnlock );
2006-01-28 22:08:16 +00:00
ADD_METHOD ( FindEntryID );
ADD_METHOD ( UnlockEntryID );
2006-03-26 07:14:44 +00:00
ADD_METHOD ( UnlockEntryIndex );
2006-01-28 22:08:16 +00:00
ADD_METHOD ( PreferUnlockEntryID );
2005-09-10 02:47:04 +00:00
ADD_METHOD ( GetNumUnlocks );
2006-05-03 21:34:05 +00:00
ADD_METHOD ( GetNumUnlocked );
2008-08-14 19:45:20 +00:00
ADD_METHOD ( GetUnlockEntryIndexToCelebrate );
2006-01-30 08:13:16 +00:00
ADD_METHOD ( AnyUnlocksToCelebrate );
2006-01-29 22:17:43 +00:00
ADD_METHOD ( GetUnlockEntry );
2006-01-28 22:08:16 +00:00
ADD_METHOD ( GetSongsUnlockedByEntryID );
ADD_METHOD ( GetStepsUnlockedByEntryID );
2005-02-21 06:51:04 +00:00
}
};
LUA_REGISTER_CLASS ( UnlockManager )
2006-01-29 22:17:43 +00:00
// lua end
2005-02-21 06:51:04 +00:00
2004-06-08 01:24:17 +00:00
/*
* (c) 2001-2004 Kevin Slaughter, Andrew Wong, Glenn Maynard
* 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.
*/