diff --git a/stepmania/Themes/default/metrics.ini b/stepmania/Themes/default/metrics.ini index 89ea07a460..e45afdb704 100644 --- a/stepmania/Themes/default/metrics.ini +++ b/stepmania/Themes/default/metrics.ini @@ -1147,6 +1147,7 @@ Class=ScreenEvaluation FailedSoundTime=0 PassedSoundTime=0 NumSequenceSounds=0 +PeakComboAwardCommand= [ScreenEvaluationStage] Fallback=ScreenEvaluation @@ -1177,7 +1178,7 @@ ShowScoreArea=1 ShowTimeArea=0 ShowGraphArea=0 ShowComboArea=0 -ShowFullCombo=0 +ShowPerDifficultyAward=0 TimerSeconds=15 StyleIcon=1 MemoryCardIcons=1 @@ -1481,7 +1482,7 @@ ShowScoreArea=1 ShowTimeArea=0 ShowGraphArea=0 ShowComboArea=0 -ShowFullCombo=0 +ShowPerDifficultyAward=0 TimerSeconds=30 StyleIcon=1 MemoryCardIcons=1 @@ -1786,7 +1787,7 @@ ShowScoreArea=1 ShowTimeArea=0 ShowGraphArea=0 ShowComboArea=0 -ShowFullCombo=0 +ShowPerDifficultyAward=0 TimerSeconds=30 StyleIcon=1 ShowTotalScoreArea=0 @@ -1999,7 +2000,7 @@ ShowScoreArea=0 ShowTimeArea=1 ShowGraphArea=0 ShowComboArea=0 -ShowFullCombo=0 +ShowPerDifficultyAward=0 TimerSeconds=30 StyleIcon=1 ShowTotalScoreArea=0 @@ -2212,7 +2213,7 @@ ShowScoreArea=0 ShowTimeArea=1 ShowGraphArea=0 ShowComboArea=0 -ShowFullCombo=0 +ShowPerDifficultyAward=0 TimerSeconds=30 StyleIcon=1 ShowTotalScoreArea=0 @@ -2437,7 +2438,7 @@ ShowScoreArea=1 ShowTimeArea=0 ShowGraphArea=0 ShowComboArea=0 -ShowFullCombo=0 +ShowPerDifficultyAward=0 TimerSeconds=15 StyleIcon=1 ShowTotalScoreArea=0 diff --git a/stepmania/src/GameConstantsAndTypes.cpp b/stepmania/src/GameConstantsAndTypes.cpp index 3ea0c07123..f8fa17775f 100644 --- a/stepmania/src/GameConstantsAndTypes.cpp +++ b/stepmania/src/GameConstantsAndTypes.cpp @@ -13,6 +13,7 @@ #include "GameConstantsAndTypes.h" #include "GameState.h" #include "RageUtil.h" +#include "ThemeManager.h" CString RadarCategoryToString( RadarCategory cat ) @@ -224,3 +225,63 @@ CString MemoryCardStateToString( MemoryCardState mcs ) } } + + +#define XToString(X) \ + CString X##ToString( X x ) \ + { \ + ASSERT(x < ARRAYSIZE(X##Names)); \ + return X##Names[x]; \ + } + +#define XToThemedString(X) \ + CString X##ToThemedString( X x ) \ + { \ + return THEME->GetMetric( #X, X##ToString(x) ); \ + } + +#define StringToX(X) \ + X StringTo##X( CString s ) \ + { \ + unsigned i; \ + for( i = 0; i < ARRAYSIZE(X##Names); ++i ) \ + if( !s.CompareNoCase(X##Names[i]) ) \ + return (X)i; \ + return (X)i; \ + } + + +static const char *PerDifficultyAwardNames[NUM_PER_DIFFICULTY_AWARDS] = { + "FullComboGreats", + "FullComboPerfects", + "FullComboMarvelouses", + "SingleDigitGreats", + "SingleDigitPerfects", + "Greats80Percent", + "Greats90Percent", + "Greats100Percent", +}; + +XToString( PerDifficultyAward ); +XToThemedString( PerDifficultyAward ); +StringToX( PerDifficultyAward ); + +// The number is not at the front so that these strings can be used as XML entity names +// The number is not at the back so that "1000" and "10000" don't conflict when +// searching for theme elements. +static const char *PeakComboAwardNames[NUM_PEAK_COMBO_AWARDS] = { + "Peak1000Combo", + "Peak2000Combo", + "Peak3000Combo", + "Peak4000Combo", + "Peak5000Combo", + "Peak6000Combo", + "Peak7000Combo", + "Peak8000Combo", + "Peak9000Combo", + "Peak10000Combo", +}; + +XToString( PeakComboAward ); +XToThemedString( PeakComboAward ); +StringToX( PeakComboAward ); diff --git a/stepmania/src/GameConstantsAndTypes.h b/stepmania/src/GameConstantsAndTypes.h index 267ac89ef0..aa68154885 100644 --- a/stepmania/src/GameConstantsAndTypes.h +++ b/stepmania/src/GameConstantsAndTypes.h @@ -327,4 +327,48 @@ enum CoinMode { COIN_HOME, COIN_PAY, COIN_FREE, NUM_COIN_MODES }; CString CoinModeToString( CoinMode cm ); +// +// Award stuff +// + +enum PerDifficultyAward +{ + AWARD_FULL_COMBO_GREATS, + AWARD_FULL_COMBO_PERFECTS, + AWARD_FULL_COMBO_MARVELOUSES, + AWARD_SINGLE_DIGIT_GREATS, + AWARD_SINGLE_DIGIT_PERFECTS, + AWARD_GREATS_80_PERCENT, + AWARD_GREATS_90_PERCENT, + AWARD_GREATS_100_PERCENT, + NUM_PER_DIFFICULTY_AWARDS, + PER_DIFFICULTY_AWARD_INVALID, +}; +#define FOREACH_PerDifficultyAward( pma ) FOREACH_ENUM( PerDifficultyAward, NUM_PER_DIFFICULTY_AWARDS, pma ) +CString PerDifficultyAwardToString( PerDifficultyAward pma ); +CString PerDifficultyAwardToThemedString( PerDifficultyAward pma ); +PerDifficultyAward StringToPerDifficultyAward( CString pma ); + + +enum PeakComboAward +{ + AWARD_1000_PEAK_COMBO, + AWARD_2000_PEAK_COMBO, + AWARD_3000_PEAK_COMBO, + AWARD_4000_PEAK_COMBO, + AWARD_5000_PEAK_COMBO, + AWARD_6000_PEAK_COMBO, + AWARD_7000_PEAK_COMBO, + AWARD_8000_PEAK_COMBO, + AWARD_9000_PEAK_COMBO, + AWARD_10000_PEAK_COMBO, + NUM_PEAK_COMBO_AWARDS, + PEAK_COMBO_AWARD_INVALID, +}; +#define FOREACH_PeakComboAward( pca ) FOREACH_ENUM( PeakComboAward, NUM_PEAK_COMBO_AWARDS, pca ) +CString PeakComboAwardToString( PeakComboAward pma ); +CString PeakComboAwardToThemedString( PeakComboAward pma ); +PeakComboAward StringToPeakComboAward( CString pma ); + + #endif diff --git a/stepmania/src/GameState.cpp b/stepmania/src/GameState.cpp index c031c496c2..50118710fa 100644 --- a/stepmania/src/GameState.cpp +++ b/stepmania/src/GameState.cpp @@ -409,6 +409,15 @@ void GameState::ResetStageStatistics() m_iLastPositiveSumOfAttackLevels[p] = 0; m_fSecondsUntilAttacksPhasedOut[p] = 0; // PlayerAI not affected } + + + { + for( int p=0; p +#include class Song; class Steps; @@ -247,6 +248,15 @@ public: void StoreRankingName( PlayerNumber pn, CString name ); // Called by name entry screens vector m_vpsNamesThatWereFilled; // filled on StoreRankingName, + + // + // Award stuff + // + // lowest priority in front, highest priority at the back. + deque m_vLastPerDifficultyAwards[NUM_PLAYERS]; + deque m_vLastPeakComboAwards[NUM_PLAYERS]; + + // // Arrow positioning // diff --git a/stepmania/src/Makefile.am b/stepmania/src/Makefile.am index b904d0cae0..fe170d6227 100644 --- a/stepmania/src/Makefile.am +++ b/stepmania/src/Makefile.am @@ -35,7 +35,7 @@ $(srcdir)/libresample/libresample.a: cd $(srcdir)/libresample && autoconf && sh ./configure && make Screens = \ -Screen.cpp Screen.h ScreenAttract.cpp ScreenAttract.h ScreenBookkeeping.h ScreenBookkeeping.cpp \ +Screen.cpp Screen.h ScreenAttract.cpp ScreenAttract.h ScreenAward.cpp ScreenAward.h ScreenBookkeeping.h ScreenBookkeeping.cpp \ ScreenBranch.cpp ScreenBranch.h ScreenCaution.cpp ScreenCaution.h ScreencenterImage.h ScreenCenterImage.cpp ScreenCredits.cpp ScreenCredits.h ScreenDemonstration.cpp ScreenDemonstration.h \ ScreenDimensions.h ScreenEdit.cpp ScreenEdit.h ScreenEditCoursesMenu.cpp ScreenEditCoursesMenu.h \ ScreenEditMenu.cpp ScreenEditMenu.h ScreenEnding.cpp ScreenEnding.h ScreenEndlessBreak.cpp ScreenEndlessBreak.h ScreenEvaluation.cpp ScreenEvaluation.h \ diff --git a/stepmania/src/MemoryCardManager.cpp b/stepmania/src/MemoryCardManager.cpp index d7c23b943e..b68d70cce0 100644 --- a/stepmania/src/MemoryCardManager.cpp +++ b/stepmania/src/MemoryCardManager.cpp @@ -133,6 +133,7 @@ CString MemoryCardManager::GetOsMountDir( PlayerNumber pn ) else { CString sDir = m_Device[pn].sOsMountDir; + FixSlashesInPlace( sDir ); if( !sDir.empty() && sDir.Right(1)!="/" ) sDir += '/'; return sDir; diff --git a/stepmania/src/Profile.cpp b/stepmania/src/Profile.cpp index 936433a0d0..030bb2361d 100644 --- a/stepmania/src/Profile.cpp +++ b/stepmania/src/Profile.cpp @@ -124,6 +124,20 @@ void Profile::InitCalorieData() m_mapDayToCaloriesBurned.clear(); } +void Profile::InitAwards() +{ + FOREACH_StepsType( st ) + { + FOREACH_Difficulty( dc ) + FOREACH_PerDifficultyAward( pda ) + m_PerDifficultyAwards[st][dc][pda].Unset(); + } + FOREACH_PeakComboAward( pca ) + { + m_PeakComboAwards[pca].Unset(); + } +} + CString Profile::GetDisplayName() const { if( !m_sDisplayName.empty() ) @@ -390,6 +404,7 @@ bool Profile::LoadAllFromDir( CString sDir ) LOAD_NODE( CategoryScores ); LOAD_NODE( ScreenshotData ); LOAD_NODE( CalorieData ); + LOAD_NODE( Awards ); } return true; // FIXME? Investigate what happens if we always return true. @@ -414,6 +429,7 @@ bool Profile::SaveAllToDir( CString sDir ) const xml.AppendChild( SaveCategoryScoresCreateNode() ); xml.AppendChild( SaveScreenshotDataCreateNode() ); xml.AppendChild( SaveCalorieDataCreateNode() ); + xml.AppendChild( SaveAwardsCreateNode() ); bool bSaved = xml.SaveToFile(fn); if( bSaved && PREFSMAN->m_bSignProfileData ) { @@ -1531,3 +1547,154 @@ float Profile::GetCaloriesBurnedForDay( Day day ) const else return i->second; } + +XNode* Profile::AwardRecord::CreateNode() const +{ + XNode* pNode = new XNode; + pNode->name = "AwardRecord"; + + pNode->AppendChild( "FirstTime", first ); + pNode->AppendChild( "LastTime", last ); + pNode->AppendChild( "Count", iCount ); + + return pNode; +} + +void Profile::AwardRecord::LoadFromNode( const XNode* pNode ) +{ + Unset(); + + ASSERT( pNode->name == "AwardRecord" ); + pNode->GetChildValue( "FirstTime", (int&)first ); // time_t is a signed long in Win32. Is this OK on other platforms? + pNode->GetChildValue( "LastTime", (int&)last ); + pNode->GetChildValue( "Count", iCount ); +} + +void Profile::LoadAwardsFromNode( const XNode* pNode ) +{ + CHECKPOINT; + + ASSERT( pNode->name == "Awards" ); + for( XNodes::const_iterator pAward = pNode->childs.begin(); + pAward != pNode->childs.end(); + pAward++ ) + { + if( (*pAward)->name == "PerDifficultyAward" ) + { + CString sStepsType; + if( !(*pAward)->GetAttrValue( "StepsType", sStepsType ) ) + WARN_AND_CONTINUE; + StepsType st = GameManager::StringToNotesType( sStepsType ); + if( st == STEPS_TYPE_INVALID ) + WARN_AND_CONTINUE; + + CString sDifficulty; + if( !(*pAward)->GetAttrValue( "Difficulty", sDifficulty ) ) + WARN_AND_CONTINUE; + Difficulty dc = StringToDifficulty( sDifficulty ); + if( dc == DIFFICULTY_INVALID ) + WARN_AND_CONTINUE; + + CString sPerDifficultyAward; + if( !(*pAward)->GetAttrValue( "PerDifficultyAward", sPerDifficultyAward ) ) + WARN_AND_CONTINUE; + PerDifficultyAward pda = StringToPerDifficultyAward( sPerDifficultyAward ); + if( pda == PER_DIFFICULTY_AWARD_INVALID ) + WARN_AND_CONTINUE; + + AwardRecord &ar = m_PerDifficultyAwards[st][dc][pda]; + + XNode* pAwardRecord = (*pAward)->GetChild("AwardRecord"); + if( pAwardRecord == NULL ) + WARN_AND_CONTINUE; + + ar.LoadFromNode( pAwardRecord ); + } + else if( (*pAward)->name == "PeakComboAward" ) + { + CString sPeakComboAward; + if( !(*pAward)->GetAttrValue( "PerDifficultyAward", sPeakComboAward ) ) + WARN_AND_CONTINUE; + PeakComboAward pca = StringToPeakComboAward( sPeakComboAward ); + if( pca == PEAK_COMBO_AWARD_INVALID ) + WARN_AND_CONTINUE; + + AwardRecord &ar = m_PeakComboAwards[pca]; + + XNode* pAwardRecord = (*pAward)->GetChild("AwardRecord"); + if( pAwardRecord == NULL ) + WARN_AND_CONTINUE; + + ar.LoadFromNode( pAwardRecord ); + } + else + WARN_AND_CONTINUE; + } +} + +XNode* Profile::SaveAwardsCreateNode() const +{ + CHECKPOINT; + + const Profile* pProfile = this; + ASSERT( pProfile ); + + XNode* pNode = new XNode; + pNode->name = "Awards"; + + FOREACH_StepsType( st ) + { + FOREACH_Difficulty( dc ) + { + FOREACH_PerDifficultyAward( pda ) + { + const AwardRecord &ar = m_PerDifficultyAwards[st][dc][pda]; + if( !ar.IsSet() ) + continue; + + XNode* pAward = pNode->AppendChild( "PerDifficultyAward" ); + + pAward->AppendAttr( "StepsType", GameManager::NotesTypeToString(st) ); + pAward->AppendAttr( "Difficulty", DifficultyToString(dc) ); + pAward->AppendAttr( "PerDifficultyAward", PerDifficultyAwardToString(pda) ); + + pAward->AppendChild( ar.CreateNode() ); + } + } + } + + FOREACH_PeakComboAward( pca ) + { + const AwardRecord &ar = m_PeakComboAwards[pca]; + if( !ar.IsSet() ) + continue; + + XNode* pAward = pNode->AppendChild( "PeakComboAward" ); + + pAward->AppendAttr( "PeakComboAward", PeakComboAwardToString(pca) ); + + pAward->AppendChild( ar.CreateNode() ); + } + + return pNode; +} + +void Profile::AddPerDifficultyAward( StepsType st, Difficulty dc, PerDifficultyAward pda ) +{ + m_PerDifficultyAwards[st][dc][pda].Set( time(NULL) ); +} + +void Profile::AddPeakComboAward( PeakComboAward pca ) +{ + m_PeakComboAwards[pca].Set( time(NULL) ); +} + +bool Profile::HasPerDifficultyAward( StepsType st, Difficulty dc, PerDifficultyAward pda ) +{ + return m_PerDifficultyAwards[st][dc][pda].IsSet(); +} + +bool Profile::HasPeakComboAward( PeakComboAward pca ) +{ + return m_PeakComboAwards[pca].IsSet(); +} diff --git a/stepmania/src/Profile.h b/stepmania/src/Profile.h index b8ff547994..cee586ae5a 100644 --- a/stepmania/src/Profile.h +++ b/stepmania/src/Profile.h @@ -198,6 +198,31 @@ public: map m_mapDayToCaloriesBurned; float GetCaloriesBurnedForDay( Day day ) const; + // + // Awards + // + struct AwardRecord + { + time_t first; + time_t last; + int iCount; // num times achieved + + AwardRecord() { Unset(); } + + bool IsSet() const { return iCount>0; } + void Set(time_t t) { if (iCount==0) first = t; last = t; iCount++; } + void Unset() { iCount = 0; first = -1; last = -1; } + + XNode* CreateNode() const; + void LoadFromNode( const XNode* pNode ); + }; + AwardRecord m_PerDifficultyAwards[NUM_STEPS_TYPES][NUM_DIFFICULTIES][NUM_PER_DIFFICULTY_AWARDS]; + AwardRecord m_PeakComboAwards[NUM_PEAK_COMBO_AWARDS]; + void AddPerDifficultyAward( StepsType st, Difficulty dc, PerDifficultyAward pda ); + void AddPeakComboAward( PeakComboAward pca ); + bool HasPerDifficultyAward( StepsType st, Difficulty dc, PerDifficultyAward pda ); + bool HasPeakComboAward( PeakComboAward pca ); + // // Init'ing // @@ -210,6 +235,7 @@ public: InitCategoryScores(); InitScreenshotData(); InitCalorieData(); + InitAwards(); } void InitEditableData(); void InitGeneralData(); @@ -218,6 +244,7 @@ public: void InitCategoryScores(); void InitScreenshotData(); void InitCalorieData(); + void InitAwards(); // // Loading and saving @@ -237,6 +264,7 @@ public: void LoadCategoryScoresFromNode( const XNode* pNode ); void LoadScreenshotDataFromNode( const XNode* pNode ); void LoadCalorieDataFromNode( const XNode* pNode ); + void LoadAwardsFromNode( const XNode* pNode ); void SaveEditableDataToDir( CString sDir ) const; XNode* SaveGeneralDataCreateNode() const; @@ -245,6 +273,7 @@ public: XNode* SaveCategoryScoresCreateNode() const; XNode* SaveScreenshotDataCreateNode() const; XNode* SaveCalorieDataCreateNode() const; + XNode* SaveAwardsCreateNode() const; void DeleteProfileDataFromDirSM390a12( CString sDir ) const; void DeleteSongScoresFromDirSM390a12( CString sDir ) const; diff --git a/stepmania/src/ProfileManager.cpp b/stepmania/src/ProfileManager.cpp index 4aacb562ff..ab83b62064 100644 --- a/stepmania/src/ProfileManager.cpp +++ b/stepmania/src/ProfileManager.cpp @@ -154,15 +154,15 @@ bool ProfileManager::LoadProfileFromMemoryCard( PlayerNumber pn ) // moust slot if( MEMCARDMAN->GetCardState(pn) == MEMORY_CARD_STATE_READY ) { - // XXX: Remounting the same mount point is broken. Investigate this later... + // XXX: Remounting a different OS directory to the same mount point + // seems to be broken. Investigate this later... + FILEMAN->Mount( "dir", MEMCARDMAN->GetOsMountDir(pn), MEM_CARD_DIR[pn] ); + LOG->Trace( "mount %s %s", MEMCARDMAN->GetOsMountDir(pn).c_str(), MEM_CARD_DIR[pn] ); + CString sDir = MEM_CARD_DIR[pn]; -// FILEMAN->Mount( "dir", MEMCARDMAN->GetOsMountDir(pn), MEM_CARD_DIR[pn] ); -// LOG->Trace( "mount %s %s", MEMCARDMAN->GetOsMountDir(pn).c_str(), MEM_CARD_DIR[pn] ); -// CString sDir = MEM_CARD_DIR[pn]; +// CString sDir = MEMCARDMAN->GetOsMountDir(pn); - CString sDir = MEMCARDMAN->GetOsMountDir(pn); - - DEBUG_ASSERT( FILEMAN->IsMounted(sDir) ); // should be called only if we've already mounted + DEBUG_ASSERT( MEMCARDMAN->GetOsMountDir(pn) ); // should be called only if we've already mounted // tack on a subdirectory so that we don't write everything to the root sDir += PREFSMAN->m_sMemoryCardProfileSubdir; diff --git a/stepmania/src/Screen.cpp b/stepmania/src/Screen.cpp index e1675e194f..f25d081cf3 100644 --- a/stepmania/src/Screen.cpp +++ b/stepmania/src/Screen.cpp @@ -291,6 +291,7 @@ void Screen::ClearMessageQueue( const ScreenMessage SM ) #include "ScreenBookkeeping.h" #include "ScreenBranch.h" #include "ScreenEnding.h" +#include "ScreenAward.h" Screen* Screen::Create( CString sClassName ) { @@ -353,6 +354,7 @@ Screen* Screen::Create( CString sClassName ) IF_RETURN( ScreenBookkeeping ); IF_RETURN( ScreenBranch ); IF_RETURN( ScreenEnding ); + IF_RETURN( ScreenAward ); RageException::Throw( "Invalid Screen class name '%s'", sClassName.c_str() ); } diff --git a/stepmania/src/ScreenAward.cpp b/stepmania/src/ScreenAward.cpp new file mode 100644 index 0000000000..f78c531bc2 --- /dev/null +++ b/stepmania/src/ScreenAward.cpp @@ -0,0 +1,149 @@ +#include "global.h" +/* +----------------------------------------------------------------------------- + Class: ScreenAward + + Desc: See header. + + Copyright (c) 2001-2002 by the person(s) listed below. All rights reserved. + Chris Danford +----------------------------------------------------------------------------- +*/ + +#include "ScreenAward.h" +#include "ScreenManager.h" +#include "AnnouncerManager.h" +#include "RageSounds.h" +#include "ThemeManager.h" +#include "GameState.h" +#include "SongManager.h" +#include "Steps.h" + + +#define NEXT_SCREEN THEME->GetMetric (m_sName,"NextScreen") + + +ScreenAward::ScreenAward( CString sName ) : Screen( sName ) +{ + bool bEitherPlayerHasAward = false; + + for( int p=0; pIsHumanPlayer(p) ) + continue; + + CString sAward; + CString sDescription; + if( !GAMESTATE->m_vLastPerDifficultyAwards[p].empty() ) + { + PerDifficultyAward pda = GAMESTATE->m_vLastPerDifficultyAwards[p].front(); + GAMESTATE->m_vLastPerDifficultyAwards[p].pop_front(); + sAward = PerDifficultyAwardToString( pda ); + sDescription = + PerDifficultyAwardToThemedString( pda ) + "\n" + + SONGMAN->GetDifficultyThemeName( GAMESTATE->m_pCurNotes[p]->GetDifficulty() ); + } + else if( !GAMESTATE->m_vLastPeakComboAwards[p].empty() ) + { + PeakComboAward pca = GAMESTATE->m_vLastPeakComboAwards[p].front(); + GAMESTATE->m_vLastPeakComboAwards[p].pop_front(); + sAward = PeakComboAwardToString( pca ); + sDescription = PeakComboAwardToThemedString( pca ); + } + + if( sAward.empty() ) + continue; // skip this player + + bEitherPlayerHasAward = true; + + m_Received[p].Load( THEME->GetPathG(m_sName,"received") ); + m_Received[p]->SetName( ssprintf("ReceivedP%d",p+1) ); + SET_XY_AND_ON_COMMAND( m_Received[p] ); + this->AddChild( m_Received[p] ); + + m_Trophy[p].Load( THEME->GetPathG(m_sName,"trophy "+sAward) ); + m_Trophy[p]->SetName( ssprintf("TrophyP%d",p+1) ); + SET_XY_AND_ON_COMMAND( m_Trophy[p] ); + this->AddChild( m_Trophy[p] ); + + m_textDescription[p].LoadFromFont( THEME->GetPathF(m_sName,"description") ); + m_textDescription[p].SetName( ssprintf("DescriptionP%d",p+1) ); + m_textDescription[p].SetText( sDescription ); + SET_XY_AND_ON_COMMAND( m_textDescription[p] ); + this->AddChild( &m_textDescription[p] ); + } + + if( !bEitherPlayerHasAward ) + { + HandleScreenMessage( SM_GoToNextScreen ); + return; + } + + m_Menu.Load( m_sName ); + this->AddChild( &m_Menu ); + + SOUND->PlayMusic( THEME->GetPathToS( m_sName + " music") ); +} + +void ScreenAward::DrawPrimitives() +{ + m_Menu.DrawBottomLayer(); + + Screen::DrawPrimitives(); + + m_Menu.DrawTopLayer(); +} + +void ScreenAward::Input( const DeviceInput& DeviceI, const InputEventType type, const GameInput &GameI, const MenuInput &MenuI, const StyleInput &StyleI ) +{ +// LOG->Trace( "ScreenAward::Input()" ); + + if( m_Menu.IsTransitioning() ) + return; + + Screen::Input( DeviceI, type, GameI, MenuI, StyleI ); +} + +void ScreenAward::HandleScreenMessage( const ScreenMessage SM ) +{ + switch( SM ) + { + case SM_MenuTimer: + MenuStart( PLAYER_INVALID ); + break; + case SM_GoToNextScreen: + // TRICKY: Keep looping on this screen until all awards are shown + bool bMoreAwardsLeft = false; + for( int p=0; pIsHumanPlayer(p) ) + continue; + + if( !GAMESTATE->m_vLastPerDifficultyAwards[p].empty() || + !GAMESTATE->m_vLastPeakComboAwards[p].empty() ) + { + bMoreAwardsLeft = true; + } + } + if( bMoreAwardsLeft ) + SCREENMAN->SetNewScreen( m_sName ); + else + SCREENMAN->SetNewScreen( NEXT_SCREEN ); + break; + } +} + +void ScreenAward::MenuStart( PlayerNumber pn ) +{ + for( int p=0; pIsHumanPlayer(p) ) + continue; + + OFF_COMMAND( m_Received[p] ); + OFF_COMMAND( m_Trophy[p] ); + OFF_COMMAND( m_textDescription[p] ); + } + + m_Menu.StartTransitioning( SM_GoToNextScreen ); +} diff --git a/stepmania/src/ScreenAward.h b/stepmania/src/ScreenAward.h new file mode 100644 index 0000000000..38c64717d3 --- /dev/null +++ b/stepmania/src/ScreenAward.h @@ -0,0 +1,38 @@ +/* +----------------------------------------------------------------------------- + Class: ScreenAward + + Desc: . + + Copyright (c) 2001-2002 by the person(s) listed below. All rights reserved. + Chris Danford +----------------------------------------------------------------------------- +*/ + +#include "Screen.h" +#include "MenuElements.h" +#include "BitmapText.h" +#include "ActorUtil.h" + + +class ScreenAward : public Screen +{ +public: + ScreenAward( CString sName ); + + virtual void DrawPrimitives(); + virtual void Input( const DeviceInput& DeviceI, const InputEventType type, const GameInput &GameI, const MenuInput &MenuI, const StyleInput &StyleI ); + virtual void HandleScreenMessage( const ScreenMessage SM ); + + virtual void MenuStart( PlayerNumber pn ); + +private: + + AutoActor m_Received[NUM_PLAYERS]; + AutoActor m_Trophy[NUM_PLAYERS]; + BitmapText m_textDescription[NUM_PLAYERS]; + + MenuElements m_Menu; +}; + + diff --git a/stepmania/src/ScreenEvaluation.cpp b/stepmania/src/ScreenEvaluation.cpp index 5e7050ac5f..324f0dbbf2 100644 --- a/stepmania/src/ScreenEvaluation.cpp +++ b/stepmania/src/ScreenEvaluation.cpp @@ -75,7 +75,7 @@ const char* STATS_STRING[NUM_STATS_LINES] = #define SHOW_TIME_AREA THEME->GetMetricB(m_sName,"ShowTimeArea") #define SHOW_GRAPH_AREA THEME->GetMetricB(m_sName,"ShowGraphArea") #define SHOW_COMBO_AREA THEME->GetMetricB(m_sName,"ShowComboArea") -#define SHOW_FULL_COMBO THEME->GetMetricB(m_sName,"ShowFullCombo") +#define SHOW_PER_DIFFICULTY_AWARD THEME->GetMetricB(m_sName,"ShowPerDifficultyAward") #define GRAPH_START_HEIGHT THEME->GetMetricF(m_sName,"GraphStartHeight") #define TYPE THEME->GetMetric (m_sName,"Type") #define PASSED_SOUND_TIME THEME->GetMetricF(m_sName,"PassedSoundTime") @@ -83,6 +83,7 @@ const char* STATS_STRING[NUM_STATS_LINES] = #define NUM_SEQUENCE_SOUNDS THEME->GetMetricI(m_sName,"NumSequenceSounds") #define SOUNDSEQ_TIME( i ) THEME->GetMetricF(m_sName,ssprintf("SoundSeqTime%d", i+1)) #define SOUNDSEQ_NAME( i ) THEME->GetMetric (m_sName,ssprintf("SoundSeqName%d", i+1)) +#define PEAK_COMBO_AWARD_COMMAND THEME->GetMetric (m_sName,"PeakComboAwardCommand") static const int NUM_SHOWN_RADAR_CATEGORIES = 5; @@ -734,13 +735,15 @@ void ScreenEvaluation::Init() this->AddChild( &m_sprPersonalRecord[p] ); } - if( SHOW_FULL_COMBO && stageStats.FullCombo( (PlayerNumber) p ) ) + if( SHOW_PER_DIFFICULTY_AWARD && !GAMESTATE->m_vLastPerDifficultyAwards[p].empty() ) { - LOG->Trace( "Full combo for P%i", p+1 ); - m_FullCombo[p].Load( THEME->GetPathToG(ssprintf("ScreenEvaluation full combo P%i",p+1)) ); - m_FullCombo[p]->SetName( ssprintf("FullComboP%d",p+1) ); - SET_XY_AND_ON_COMMAND( m_FullCombo[p] ); - this->AddChild( m_FullCombo[p] ); + PerDifficultyAward pda = GAMESTATE->m_vLastPerDifficultyAwards[p].front(); + CString sAward = PerDifficultyAwardToString( pda ); + + m_PerDifficultyAward[p].Load( THEME->GetPathToG(ssprintf("ScreenEvaluation award %s",sAward.c_str(),p+1)) ); + m_PerDifficultyAward[p]->SetName( ssprintf("PerDifficultyAwardP%d",p+1) ); + SET_XY_AND_ON_COMMAND( m_PerDifficultyAward[p] ); + this->AddChild( m_PerDifficultyAward[p] ); } } @@ -874,6 +877,68 @@ void ScreenEvaluation::CommitScores( const StageStats &stageStats, int iPersonal if( hs.fPercentDP > PREFSMAN->m_fMinPercentageForHighScore ) PROFILEMAN->AddStepsHighScore( GAMESTATE->m_pCurNotes[p], (PlayerNumber)p, hs, iPersonalHighScoreIndex[p], iMachineHighScoreIndex[p] ); + + if( PROFILEMAN->IsUsingProfile((PlayerNumber)p) ) + { + // check for awards + Profile* pProfile = PROFILEMAN->GetProfile((PlayerNumber)p); + + if( stageStats.FullComboOfScore( (PlayerNumber)p, TNS_GREAT ) ) + GAMESTATE->m_vLastPerDifficultyAwards[p].push_back( AWARD_FULL_COMBO_GREATS ); + if( stageStats.FullComboOfScore( (PlayerNumber)p, TNS_PERFECT ) ) + GAMESTATE->m_vLastPerDifficultyAwards[p].push_back( AWARD_FULL_COMBO_PERFECTS ); + if( stageStats.FullComboOfScore( (PlayerNumber)p, TNS_MARVELOUS ) ) + GAMESTATE->m_vLastPerDifficultyAwards[p].push_back( AWARD_FULL_COMBO_MARVELOUSES ); + + if( stageStats.SingleDigitsOfScore( (PlayerNumber)p, TNS_GREAT ) ) + GAMESTATE->m_vLastPerDifficultyAwards[p].push_back( AWARD_SINGLE_DIGIT_GREATS ); + if( stageStats.SingleDigitsOfScore( (PlayerNumber)p, TNS_PERFECT ) ) + GAMESTATE->m_vLastPerDifficultyAwards[p].push_back( AWARD_SINGLE_DIGIT_PERFECTS ); + + float fPercentGreats = stageStats.GetPercentageOfTaps((PlayerNumber)p, TNS_GREAT); + if( fPercentGreats >= 0.8f ) + GAMESTATE->m_vLastPerDifficultyAwards[p].push_back( AWARD_GREATS_80_PERCENT ); + if( fPercentGreats >= 0.9f ) + GAMESTATE->m_vLastPerDifficultyAwards[p].push_back( AWARD_GREATS_90_PERCENT ); + if( fPercentGreats >= 1.f ) + GAMESTATE->m_vLastPerDifficultyAwards[p].push_back( AWARD_GREATS_100_PERCENT ); + + int iComboAtStartOfStage = stageStats.GetComboAtStartOfStage( (PlayerNumber)p ); + int iPeakCombo = stageStats.GetMaxCombo((PlayerNumber)p).cnt; + + FOREACH_PeakComboAward( pca ) + { + int iLevel = 100/*0*/ * (pca+1); + bool bCrossedLevel = iComboAtStartOfStage < iLevel && iPeakCombo >= iLevel; + if( bCrossedLevel ) + { + GAMESTATE->m_vLastPeakComboAwards[p].push_back( pca ); + m_textJudgeNumbers[max_combo][p].Command( PEAK_COMBO_AWARD_COMMAND ); + } + } + + { + for( int i=GAMESTATE->m_vLastPerDifficultyAwards[p].size()-1; i>=0; i-- ) + { + PerDifficultyAward pda = GAMESTATE->m_vLastPerDifficultyAwards[p][i]; + Steps* pSteps = stageStats.pSteps[p]; + bool bAlreadyHad = pProfile->HasPerDifficultyAward( pSteps->m_StepsType, pSteps->GetDifficulty(), pda ); + pProfile->AddPerDifficultyAward( pSteps->m_StepsType, pSteps->GetDifficulty(), pda ); + if( bAlreadyHad ) + GAMESTATE->m_vLastPerDifficultyAwards[p].erase( GAMESTATE->m_vLastPerDifficultyAwards[p].begin()+i ); + } + } + { + for( int i=GAMESTATE->m_vLastPeakComboAwards[p].size()-1; i>=0; i-- ) + { + PeakComboAward pca = GAMESTATE->m_vLastPeakComboAwards[p][i]; + bool bAlreadyHad = pProfile->HasPeakComboAward( pca ); + pProfile->AddPeakComboAward( pca ); + if( bAlreadyHad ) + GAMESTATE->m_vLastPeakComboAwards[p].erase( GAMESTATE->m_vLastPeakComboAwards[p].begin()+i ); + } + } + } } break; @@ -1147,8 +1212,8 @@ void ScreenEvaluation::TweenOffScreen() continue; OFF_COMMAND( m_sprMachineRecord[p] ); OFF_COMMAND( m_sprPersonalRecord[p] ); - if( m_FullCombo[p].IsLoaded() ) - OFF_COMMAND( m_FullCombo[p] ); + if( m_PerDifficultyAward[p].IsLoaded() ) + OFF_COMMAND( m_PerDifficultyAward[p] ); } OFF_COMMAND( m_sprTryExtraStage ); } diff --git a/stepmania/src/ScreenEvaluation.h b/stepmania/src/ScreenEvaluation.h index 83e13edbd3..993d1752cd 100644 --- a/stepmania/src/ScreenEvaluation.h +++ b/stepmania/src/ScreenEvaluation.h @@ -31,8 +31,8 @@ #include "HighScore.h" const int MAX_SONGS_TO_SHOW = 5; // In summary, we show last 3 stages, plus extra stages if passed -const int NUM_JUDGE_LINES = 9; // marvelous, perfect, great, good, boo, miss, ok, max_combo, error -const int NUM_STATS_LINES = 4; // jumps, holds, mines, hands +enum JudgeLine { marvelous, perfect, great, good, boo, miss, ok, max_combo, error, NUM_JUDGE_LINES }; +enum StatsLine { jumps, holds, mines, hands, NUM_STATS_LINES }; // sound sequences for the evaluation screen struct EvalSoundSequence @@ -136,7 +136,7 @@ protected: Sprite m_sprPersonalRecord[NUM_PLAYERS]; bool m_bTryExtraStage; Sprite m_sprTryExtraStage; - AutoActor m_FullCombo[NUM_PLAYERS]; + AutoActor m_PerDifficultyAward[NUM_PLAYERS]; bool m_bFailed; RageSound m_soundStart; // sound played if the player passes or fails diff --git a/stepmania/src/ScreenGameplay.cpp b/stepmania/src/ScreenGameplay.cpp index b1f1916833..22e6063bc7 100644 --- a/stepmania/src/ScreenGameplay.cpp +++ b/stepmania/src/ScreenGameplay.cpp @@ -1536,6 +1536,9 @@ void ScreenGameplay::Input( const DeviceInput& DeviceI, const InputEventType typ { switch( DeviceI.button ) { + case SDLK_F5: + this->HandleScreenMessage( SM_NotesEnded ); + break; case SDLK_F6: m_bChangedOffsetOrBPM = true; GAMESTATE->m_SongOptions.m_bAutoSync = !GAMESTATE->m_SongOptions.m_bAutoSync; // toggle diff --git a/stepmania/src/StageStats.cpp b/stepmania/src/StageStats.cpp index 7015a096f8..acf3e5e7c4 100644 --- a/stepmania/src/StageStats.cpp +++ b/stepmania/src/StageStats.cpp @@ -389,23 +389,51 @@ StageStats::Combo_t StageStats::GetMaxCombo( PlayerNumber pn ) const return ComboList[pn][m]; } -bool StageStats::FullCombo( PlayerNumber pn ) const +int StageStats::GetComboAtStartOfStage( PlayerNumber pn ) const { - if( ComboList[pn].size() != 1 ) - { - LOG->Trace("FullCombo(%i): %i != 1", pn, (int)ComboList[pn].size()); - return false; - } + if( ComboList[pn].empty() ) + return 0; + else + return ComboList[pn][0].rollover; +} - const float ComboStart = ComboList[pn][0].start; - const float ComboEnd = ComboList[pn][0].start + ComboList[pn][0].size; - - const bool ComboStartsAtBeginning = fabs( ComboStart - fFirstPos[pn] ) < 0.001f; - const bool ComboEndsAtEnd = fabs( ComboEnd - fLastPos[pn] ) < 0.001f; +bool StageStats::FullComboOfScore( PlayerNumber pn, TapNoteScore tnsAllGreaterOrEqual ) const +{ + ASSERT( tnsAllGreaterOrEqual >= TNS_GREAT ); + ASSERT( tnsAllGreaterOrEqual <= TNS_MARVELOUS ); - LOG->Trace("FullCombo(%i): %f .. %f, %f .. %f, %i, %i", - pn, ComboStart, ComboEnd, fFirstPos[pn], fLastPos[pn], ComboStartsAtBeginning, ComboEndsAtEnd ); - return ComboStartsAtBeginning && ComboEndsAtEnd; + for( int i=TNS_MISS; i 0 ) + return false; + } + return true; +} + +bool StageStats::SingleDigitsOfScore( PlayerNumber pn, TapNoteScore tnsAllGreaterOrEqual ) const +{ + return FullComboOfScore( pn, tnsAllGreaterOrEqual ) && + iTapNoteScores[pn][tnsAllGreaterOrEqual] < 10; +} + +int StageStats::GetTotalTaps( PlayerNumber pn ) const +{ + int iTotalTaps = 0; + for( int i=TNS_MISS; i ComboList[NUM_PLAYERS]; float fFirstPos[NUM_PLAYERS], fLastPos[NUM_PLAYERS]; - bool FullCombo( PlayerNumber pn ) const; + int GetComboAtStartOfStage( PlayerNumber pn ) const; + bool FullComboOfScore( PlayerNumber pn, TapNoteScore tnsAllGreaterOrEqual ) const; + bool FullCombo( PlayerNumber pn ) const { return FullComboOfScore(pn,TNS_GREAT); } + bool SingleDigitsOfScore( PlayerNumber pn, TapNoteScore tnsAllGreaterOrEqual ) const; + int GetTotalTaps( PlayerNumber pn ) const; + float GetPercentageOfTaps( PlayerNumber pn, TapNoteScore tns ) const; void UpdateComboList( PlayerNumber pn, float pos, bool rollover ); Combo_t GetMaxCombo( PlayerNumber pn ) const; }; diff --git a/stepmania/src/StepMania.dsp b/stepmania/src/StepMania.dsp index d82fae2735..711333cee1 100644 --- a/stepmania/src/StepMania.dsp +++ b/stepmania/src/StepMania.dsp @@ -58,14 +58,14 @@ BSC32=bscmake.exe LINK32=link.exe # ADD BASE LINK32 $(intdir)\verstub.obj kernel32.lib shell32.lib user32.lib gdi32.lib advapi32.lib winmm.lib /nologo /subsystem:windows /pdb:"../debug6/StepMania-debug.pdb" /map /debug /machine:I386 /nodefaultlib:"libcmtd.lib" /out:"../StepMania-debug.exe" # SUBTRACT BASE LINK32 /verbose /profile /pdb:none /incremental:no /nodefaultlib -# ADD LINK32 $(intdir)\verstub.obj kernel32.lib gdi32.lib shell32.lib user32.lib advapi32.lib winmm.lib /nologo /subsystem:windows /map /debug /machine:I386 /nodefaultlib:"msvcrt.lib" /out:"../Program/StepMania-debug.exe" +# ADD LINK32 $(intdir)\verstub.obj kernel32.lib gdi32.lib shell32.lib user32.lib advapi32.lib winmm.lib /nologo /subsystem:windows /map /debug /machine:I386 /nodefaultlib:"msvcrt.lib" /out:"../../itg/Program/StepMania-debug.exe" # SUBTRACT LINK32 /verbose /profile /pdb:none /incremental:no /nodefaultlib # Begin Special Build Tool IntDir=.\../Debug6 -TargetDir=\stepmania\stepmania\Program +TargetDir=\stepmania\itg\Program TargetName=StepMania-debug SOURCE="$(InputPath)" -PreLink_Cmds=disasm\verinc cl /Zl /nologo /c verstub.cpp /Fo$(IntDir)\ +PreLink_Cmds=disasm\verinc cl /Zl /nologo /c verstub.cpp /Fo$(IntDir)\ PostBuild_Cmds=disasm\mapconv $(IntDir)\$(TargetName).map $(TargetDir)\StepMania.vdi # End Special Build Tool @@ -142,7 +142,7 @@ IntDir=.\../Release6 TargetDir=\stepmania\stepmania\Program TargetName=StepMania SOURCE="$(InputPath)" -PreLink_Cmds=disasm\verinc cl /Zl /nologo /c verstub.cpp /Fo$(IntDir)\ +PreLink_Cmds=disasm\verinc cl /Zl /nologo /c verstub.cpp /Fo$(IntDir)\ PostBuild_Cmds=disasm\mapconv $(IntDir)\$(TargetName).map $(TargetDir)\StepMania.vdi # End Special Build Tool @@ -4725,6 +4725,25 @@ SOURCE=.\ScreenAttract.h # End Source File # Begin Source File +SOURCE=.\ScreenAward.cpp + +!IF "$(CFG)" == "StepMania - Win32 Debug" + +!ELSEIF "$(CFG)" == "StepMania - Xbox Debug" + +!ELSEIF "$(CFG)" == "StepMania - Win32 Release" + +!ELSEIF "$(CFG)" == "StepMania - Xbox Release" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\ScreenAward.h +# End Source File +# Begin Source File + SOURCE=.\ScreenBookkeeping.cpp !IF "$(CFG)" == "StepMania - Win32 Debug" diff --git a/stepmania/src/StepMania.vcproj b/stepmania/src/StepMania.vcproj index 0b1816fe27..f08d34d054 100644 --- a/stepmania/src/StepMania.vcproj +++ b/stepmania/src/StepMania.vcproj @@ -82,7 +82,7 @@ cl /Zl /nologo /c verstub.cpp /Fo"$(IntDir)"\ + + + +