diff --git a/Docs/Changelog_sm5.txt b/Docs/Changelog_sm5.txt index 254e40a4ce..065a9800f4 100644 --- a/Docs/Changelog_sm5.txt +++ b/Docs/Changelog_sm5.txt @@ -8,7 +8,14 @@ ________________________________________________________________________________ StepMania 5.0 Preview 2 | 201106?? -------------------------------------------------------------------------------- +2011/06/24 +---------- +* [UnlockManager] Add a new unlock reward: StepsType. This is similar to + unlocking Steps, but it is targeted for one step in one stepstype rather + than one step in all stepstypes. This needs testing. [Wolfman2000] + 2011/06/19 +---------- * [EditMenu] Allow all songs to work in Practice Mode, regardless of folder location. This fixes a crash if everyone had songs in AdditionalSongs. [Wolfman2000] diff --git a/Themes/_fallback/Languages/en.ini b/Themes/_fallback/Languages/en.ini index 1e0a33cef6..e730959267 100644 --- a/Themes/_fallback/Languages/en.ini +++ b/Themes/_fallback/Languages/en.ini @@ -1905,6 +1905,7 @@ P2=P2 [UnlockRewardType] Song=Song Steps=Steps +StepsType=StepsType Course=Course Modifier=Modifier diff --git a/src/UnlockManager.cpp b/src/UnlockManager.cpp index 18cee4407f..31394af280 100644 --- a/src/UnlockManager.cpp +++ b/src/UnlockManager.cpp @@ -7,6 +7,7 @@ #include "RageUtil.h" #include "SongManager.h" #include "GameState.h" +#include "GameConstantsAndTypes.h" // StepsTypeToString #include "ProfileManager.h" #include "Profile.h" #include "ThemeManager.h" @@ -44,6 +45,7 @@ static const char *UnlockRewardTypeNames[] = { "Song", "Steps", + "StepsType", "Course", "Modifier", }; @@ -171,6 +173,18 @@ bool UnlockManager::StepsIsLocked( const Song *pSong, const Steps *pSteps ) cons return p->IsLocked(); } +bool UnlockManager::StepsTypeIsLocked(const Song *pSong, const Steps *pSteps, const StepsType *pSType) const +{ + if( !PREFSMAN->m_bUseUnlockSystem ) + return false; + + const UnlockEntry *p = FindStepsType( pSong, pSteps, pSType ); + if( p == NULL ) + return false; + + return p->IsLocked(); +} + bool UnlockManager::ModifierIsLocked( const RString &sOneMod ) const { if( !PREFSMAN->m_bUseUnlockSystem ) @@ -200,6 +214,19 @@ const UnlockEntry *UnlockManager::FindSteps( const Song *pSong, const Steps *pSt return NULL; } +const UnlockEntry *UnlockManager::FindStepsType(const Song *pSong, + const Steps *pSteps, + const StepsType *pSType ) const +{ + ASSERT( pSong && pSteps && pSType ); + FOREACH_CONST( UnlockEntry, m_UnlockEntries, e ) + if(e->m_Song.ToSong() == pSong && + e->m_dc == pSteps->GetDifficulty() && + e->m_StepsType == pSteps->m_StepsType) + return &(*e); + return NULL; +} + const UnlockEntry *UnlockManager::FindCourse( const Course *pCourse ) const { FOREACH_CONST( UnlockEntry, m_UnlockEntries, e ) @@ -309,6 +336,11 @@ bool UnlockEntry::IsValid() const case UnlockRewardType_Steps: return m_Song.IsValid() && m_dc != Difficulty_Invalid; + case UnlockRewardType_Steps_Type: + { + return m_Song.IsValid() && m_dc != Difficulty_Invalid && m_StepsType != StepsType_Invalid; + } + case UnlockRewardType_Course: return m_Course.IsValid(); @@ -323,7 +355,9 @@ bool UnlockEntry::IsValid() const UnlockEntryStatus UnlockEntry::GetUnlockEntryStatus() const { - if( !m_sEntryID.empty() && PROFILEMAN->GetMachineProfile()->m_UnlockedEntryIDs.find(m_sEntryID) != PROFILEMAN->GetMachineProfile()->m_UnlockedEntryIDs.end() ) + set &ids = PROFILEMAN->GetMachineProfile()->m_UnlockedEntryIDs; + if(!m_sEntryID.empty() && + ids.find(m_sEntryID) != ids.end() ) return UnlockEntryStatus_Unlocked; float fScores[NUM_UnlockRequirement]; @@ -367,10 +401,16 @@ RString UnlockEntry::GetDescription() const case UnlockRewardType_Song: return pSong ? pSong->GetDisplayFullTitle() : ""; case UnlockRewardType_Steps: - { - StepsType st = GAMEMAN->GetHowToPlayStyleForGame( GAMESTATE->m_pCurGame )->m_StepsType; // TODO: Is this the best thing we can do here? - return (pSong ? pSong->GetDisplayFullTitle() : "") + ", " + CustomDifficultyToLocalizedString( GetCustomDifficulty(st, m_dc, CourseType_Invalid) ); - } + { + StepsType st = GAMEMAN->GetHowToPlayStyleForGame( GAMESTATE->m_pCurGame )->m_StepsType; // TODO: Is this the best thing we can do here? + return (pSong ? pSong->GetDisplayFullTitle() : "") + ", " + CustomDifficultyToLocalizedString( GetCustomDifficulty(st, m_dc, CourseType_Invalid) ); + } + case UnlockRewardType_Steps_Type: + { + RString ret = (pSong ? pSong->GetDisplayFullTitle() : ""); + ret += "," + CustomDifficultyToLocalizedString( GetCustomDifficulty(m_StepsType, m_dc, CourseType_Invalid) ); + return ret + "," + StringConversion::ToString(m_StepsType); // yeah, bit strange. + } case UnlockRewardType_Course: return m_Course.IsValid() ? m_Course.ToCourse()->GetDisplayFullTitle() : ""; case UnlockRewardType_Modifier: @@ -388,6 +428,7 @@ RString UnlockEntry::GetBannerFile() const return ""; case UnlockRewardType_Song: case UnlockRewardType_Steps: + case UnlockRewardType_Steps_Type: return pSong ? pSong->GetBannerPath() : ""; case UnlockRewardType_Course: return m_Course.ToCourse() ? m_Course.ToCourse()->GetBannerPath() : ""; @@ -406,6 +447,7 @@ RString UnlockEntry::GetBackgroundFile() const return ""; case UnlockRewardType_Song: case UnlockRewardType_Steps: + case UnlockRewardType_Steps_Type: return pSong ? pSong->GetBackgroundPath() : ""; case UnlockRewardType_Course: return ""; @@ -507,6 +549,30 @@ void UnlockManager::Load() } break; + case UnlockRewardType_Steps_Type: + { + 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; + } + + e->m_dc = StringToDifficulty( e->m_cmd.GetArg(1).s ); + if( e->m_dc == Difficulty_Invalid ) + { + LOG->Warn( "Unlock: Invalid difficulty \"%s\"", e->m_cmd.GetArg(1).s.c_str() ); + break; + } + + e->m_StepsType = GAMEMAN->StringToStepsType(e->m_cmd.GetArg(2).s); + if (e->m_StepsType == StepsType_Invalid) + { + LOG->Warn( "Unlock: Invalid steps type \"%s\"", e->m_cmd.GetArg(2).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() ) @@ -701,6 +767,7 @@ public: 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 steps_type(T* p, lua_State *L) { GetArgs(p, L); p->m_Type = UnlockRewardType_Steps_Type; 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; } @@ -726,6 +793,7 @@ public: ADD_METHOD( GetCourse ); ADD_METHOD( song ); ADD_METHOD( steps ); + ADD_METHOD( steps_type ); ADD_METHOD( course ); ADD_METHOD( mod ); ADD_METHOD( code ); diff --git a/src/UnlockManager.h b/src/UnlockManager.h index 6c085e6680..f1c2da3c55 100644 --- a/src/UnlockManager.h +++ b/src/UnlockManager.h @@ -16,16 +16,17 @@ class Steps; class Profile; struct lua_State; +/** @brief What is needed to unlock an item? */ enum UnlockRequirement { - UnlockRequirement_ArcadePoints, - UnlockRequirement_DancePoints, - UnlockRequirement_SongPoints, - UnlockRequirement_ExtraCleared, - UnlockRequirement_ExtraFailed, - UnlockRequirement_Toasties, - UnlockRequirement_StagesCleared, - UnlockRequirement_NumUnlocked, + UnlockRequirement_ArcadePoints, /**< Get a certain number of arcade points. */ + UnlockRequirement_DancePoints, /**< Get a certain number of dance points. */ + UnlockRequirement_SongPoints, /**< Get a certain number of song points. */ + UnlockRequirement_ExtraCleared, /**< Pass the extra stage. */ + UnlockRequirement_ExtraFailed, /**< Fail the extra stage. */ + UnlockRequirement_Toasties, /**< Get a number of toasties. */ + UnlockRequirement_StagesCleared, /**< Clear a number of stages. */ + UnlockRequirement_NumUnlocked, /**< Have a number of locked items already unlocked. */ NUM_UnlockRequirement, UnlockRequirement_Invalid, }; @@ -33,10 +34,11 @@ LuaDeclareType( UnlockRequirement ); enum UnlockRewardType { - UnlockRewardType_Song, - UnlockRewardType_Steps, - UnlockRewardType_Course, - UnlockRewardType_Modifier, + UnlockRewardType_Song, /**< A song is unlocked. */ + UnlockRewardType_Steps, /**< A step pattern for all styles is unlocked. */ + UnlockRewardType_Steps_Type, /**< A step pattern for a specific style is unlocked. */ + UnlockRewardType_Course, /**< A course is unlocked. */ + UnlockRewardType_Modifier, /**< A modifier is unlocked. */ NUM_UnlockRewardType, UnlockRewardType_Invalid }; @@ -60,8 +62,8 @@ public: * if not specified. */ UnlockEntry(): m_Type(UnlockRewardType_Invalid), m_cmd(), m_Song(), m_dc(Difficulty_Invalid), m_Course(), - m_bRequirePassHardSteps(false), m_bRoulette(false), - m_sEntryID(RString("")) + m_StepsType(StepsType_Invalid), m_bRequirePassHardSteps(false), + m_bRoulette(false), m_sEntryID(RString("")) { ZERO( m_fRequirement ); } @@ -74,6 +76,7 @@ public: SongID m_Song; Difficulty m_dc; CourseID m_Course; + StepsType m_StepsType; float m_fRequirement[NUM_UnlockRequirement]; // unlocked if any of of these are met bool m_bRequirePassHardSteps; @@ -117,6 +120,7 @@ public: float PointsUntilNextUnlock( UnlockRequirement t ) const; int SongIsLocked( const Song *pSong ) const; bool StepsIsLocked( const Song *pSong, const Steps *pSteps ) const; + bool StepsTypeIsLocked( const Song *pSong, const Steps *pSteps, const StepsType *pSType ) const; int CourseIsLocked( const Course *course ) const; bool ModifierIsLocked( const RString &sOneMod ) const; @@ -153,6 +157,7 @@ public: const UnlockEntry *FindSong( const Song *pSong ) const; const UnlockEntry *FindSteps( const Song *pSong, const Steps *pSteps ) const; + const UnlockEntry *FindStepsType( const Song *pSong, const Steps *pSteps, const StepsType *pSType ) const; const UnlockEntry *FindCourse( const Course *pCourse ) const; const UnlockEntry *FindModifier( const RString &sOneMod ) const;