diff --git a/src/NoteDataUtil.cpp b/src/NoteDataUtil.cpp index 0e730bbbe2..bd1b6d5797 100644 --- a/src/NoteDataUtil.cpp +++ b/src/NoteDataUtil.cpp @@ -9,6 +9,7 @@ #include "GameState.h" #include "RadarValues.h" #include "Foreach.h" +#include "TimingData.h" #include // TODO: Remove these constants that aren't time signature-aware @@ -2612,6 +2613,28 @@ void NoteDataUtil::SetHopoPossibleFlags( const Song *pSong, NoteData& ndInOut ) } } +unsigned int NoteDataUtil::GetTotalHoldTicks( NoteData* nd, const TimingData* td ) +{ + unsigned int ret = 0; + int end = nd->GetLastRow(); + vector segments = td->GetTimingSegments( SEGMENT_TICKCOUNT ); + // We start with the LAST TimingSegment and work our way backwards. + // This way we can continually update end instead of having to lookup when + // the next segment starts. + for(int i = segments.size() - 1; i >= 0; i--) + { + TickcountSegment *ts = (TickcountSegment*) segments[i]; + if( ts->GetTicks() > 0) + { + // Jump to each point where holds would tick and add the number of holds there to ret. + // XXX: Assuming each segment starts on the beat + for(int j = ts->GetRow(); j < end; j += ROWS_PER_BEAT / ts->GetTicks() ) + ret += nd->GetNumTracksHeldAtRow(j); + } + end = ts->GetRow(); + } + return ret; +} /* * (c) 2001-2004 Chris Danford, Glenn Maynard diff --git a/src/NoteDataUtil.h b/src/NoteDataUtil.h index 3aef94ca1a..c8d225fcbe 100644 --- a/src/NoteDataUtil.h +++ b/src/NoteDataUtil.h @@ -9,6 +9,7 @@ struct RadarValues; class NoteData; class Song; struct AttackArray; +class TimingData; /** @brief A limited selection of the RadarValues. */ struct RadarStats @@ -196,6 +197,10 @@ namespace NoteDataUtil bool GetPrevEditorPosition( const NoteData& in, int &rowInOut ); void SetHopoPossibleFlags( const Song *pSong, NoteData& ndInOut ); + + /** @brief Count the number of hold ticks that will fire, assuming that tickholds are on. + * @param td The TimingData from the relevant Steps. */ + unsigned int GetTotalHoldTicks( NoteData* nd, const TimingData* td ); }; #endif diff --git a/src/ScoreKeeperNormal.cpp b/src/ScoreKeeperNormal.cpp index 521791d69f..cef8072b72 100644 --- a/src/ScoreKeeperNormal.cpp +++ b/src/ScoreKeeperNormal.cpp @@ -115,16 +115,13 @@ void ScoreKeeperNormal::Load( pSteps->Compress(); const Style* pStyle = GAMESTATE->GetCurrentStyle(); - NoteData nd; - pStyle->GetTransformedNoteDataForStyle( m_pPlayerState->m_PlayerNumber, ndTemp, nd ); + NoteData ndPre; + pStyle->GetTransformedNoteDataForStyle( m_pPlayerState->m_PlayerNumber, ndTemp, ndPre ); /* Compute RadarValues before applying any user-selected mods. Apply * Course mods and count them in the "pre" RadarValues because they're * forced and not chosen by the user. */ - NoteDataUtil::TransformNoteData( nd, aa, pSteps->m_StepsType, pSong ); - RadarValues rvPre; - GAMESTATE->SetProcessedTimingData(pSteps->GetTimingData()); - NoteDataUtil::CalculateRadarValues( nd, pSong->m_fMusicLengthSeconds, rvPre ); + NoteDataUtil::TransformNoteData( ndPre, aa, pSteps->m_StepsType, pSong ); /* Apply user transforms to find out how the notes will really look. * @@ -133,13 +130,13 @@ void ScoreKeeperNormal::Load( * have eg. GAMESTATE->GetOptionsForCourse(po,so,pn) to get options based on * the last call to StoreSelectedOptions and the modifiers list, but that'd * mean moving the queues in ScreenGameplay to GameState ... */ - NoteDataUtil::TransformNoteData( nd, m_pPlayerState->m_PlayerOptions.GetStage(), pSteps->m_StepsType ); - RadarValues rvPost; - NoteDataUtil::CalculateRadarValues( nd, pSong->m_fMusicLengthSeconds, rvPost ); - GAMESTATE->SetProcessedTimingData(NULL); + NoteData ndPost = ndPre; + NoteDataUtil::TransformNoteData( ndPost, m_pPlayerState->m_PlayerOptions.GetStage(), pSteps->m_StepsType ); - iTotalPossibleDancePoints += this->GetPossibleDancePoints( rvPre, rvPost ); - iTotalPossibleGradePoints += this->GetPossibleGradePoints( rvPre, rvPost ); + GAMESTATE->SetProcessedTimingData(pSteps->GetTimingData()); // XXX: Not sure why but NoteDataUtil::CalculateRadarValues segfaults without this + iTotalPossibleDancePoints += this->GetPossibleDancePoints( &ndPre, &ndPost, pSteps->GetTimingData(), pSong->m_fMusicLengthSeconds ); + iTotalPossibleGradePoints += this->GetPossibleGradePoints( &ndPre, &ndPost, pSteps->GetTimingData(), pSong->m_fMusicLengthSeconds ); + GAMESTATE->SetProcessedTimingData(NULL); } m_pPlayerStageStats->m_iPossibleDancePoints = iTotalPossibleDancePoints; @@ -653,52 +650,60 @@ void ScoreKeeperNormal::HandleHoldScore( const TapNote &tn ) } -int ScoreKeeperNormal::GetPossibleDancePoints( const RadarValues& radars ) +int ScoreKeeperNormal::GetPossibleDancePoints( NoteData* nd, const TimingData* td, float fSongSeconds ) { /* Note: If W1 timing is disabled or not active (not course mode), * W2 will be used instead. */ - - int NumTaps = int(radars[RadarCategory_TapsAndHolds]); - int NumHolds = int(radars[RadarCategory_Holds]); - int NumRolls = int(radars[RadarCategory_Rolls]); - return - NumTaps*TapNoteScoreToDancePoints(TNS_W1, false) + - NumHolds*HoldNoteScoreToDancePoints(HNS_Held, false) + - NumRolls*HoldNoteScoreToDancePoints(HNS_Held, false); + // XXX: That's not actually implemented! + RadarValues radars; + NoteDataUtil::CalculateRadarValues( *nd, fSongSeconds, radars ); + + int ret = 0; + + ret += int(radars[RadarCategory_TapsAndHolds]) * TapNoteScoreToDancePoints(TNS_W1, false); + if( GAMESTATE->GetCurrentGame()->m_bTickHolds ) ret += NoteDataUtil::GetTotalHoldTicks( nd, td ) * g_iPercentScoreWeight[SE_CheckpointHit]; + ret += int(radars[RadarCategory_Holds]) * HoldNoteScoreToDancePoints(HNS_Held, false); + ret += int(radars[RadarCategory_Rolls]) * HoldNoteScoreToDancePoints(HNS_Held, false); + + return ret; } -int ScoreKeeperNormal::GetPossibleDancePoints( const RadarValues& fOriginalRadars, const RadarValues& fPostRadars ) +int ScoreKeeperNormal::GetPossibleDancePoints( NoteData* ndPre, NoteData* ndPost, const TimingData* td, float fSongSeconds ) { /* The logic here is that if you use a modifier that adds notes, you should * have to hit the new notes to get a high grade. However, if you use one * that removes notes, they should simply be counted as misses. */ return max( - GetPossibleDancePoints(fOriginalRadars), - GetPossibleDancePoints(fPostRadars) ); + GetPossibleDancePoints(ndPre, td, fSongSeconds), + GetPossibleDancePoints(ndPost, td, fSongSeconds) ); } -int ScoreKeeperNormal::GetPossibleGradePoints( const RadarValues& radars ) +int ScoreKeeperNormal::GetPossibleGradePoints( NoteData* nd, const TimingData* td, float fSongSeconds ) { /* Note: if W1 timing is disabled or not active (not course mode), * W2 will be used instead. */ + // XXX: That's not actually implemented! + RadarValues radars; + NoteDataUtil::CalculateRadarValues( *nd, fSongSeconds, radars ); - int NumTaps = int(radars[RadarCategory_TapsAndHolds]); - int NumHolds = int(radars[RadarCategory_Holds]); - int NumRolls = int(radars[RadarCategory_Rolls]); - return - NumTaps*TapNoteScoreToGradePoints(TNS_W1, false) + - NumHolds*HoldNoteScoreToGradePoints(HNS_Held, false) + - NumRolls*HoldNoteScoreToGradePoints(HNS_Held, false); + int ret = 0; + + ret += int(radars[RadarCategory_TapsAndHolds]) * TapNoteScoreToGradePoints(TNS_W1, false); + if( GAMESTATE->GetCurrentGame()->m_bTickHolds ) ret += NoteDataUtil::GetTotalHoldTicks( nd, td ) * g_iGradeWeight[SE_CheckpointHit]; + ret += int(radars[RadarCategory_Holds]) * HoldNoteScoreToGradePoints(HNS_Held, false); + ret += int(radars[RadarCategory_Rolls]) * HoldNoteScoreToGradePoints(HNS_Held, false); + + return ret; } -int ScoreKeeperNormal::GetPossibleGradePoints( const RadarValues& fOriginalRadars, const RadarValues& fPostRadars ) +int ScoreKeeperNormal::GetPossibleGradePoints( NoteData* ndPre, NoteData* ndPost, const TimingData* td, float fSongSeconds ) { /* The logic here is that if you use a modifier that adds notes, you should * have to hit the new notes to get a high grade. However, if you use one * that removes notes, they should simply be counted as misses. */ return max( - GetPossibleGradePoints(fOriginalRadars), - GetPossibleGradePoints(fPostRadars) ); + GetPossibleGradePoints( ndPre, td, fSongSeconds ), + GetPossibleGradePoints( ndPost, td, fSongSeconds ) ); } int ScoreKeeperNormal::TapNoteScoreToDancePoints( TapNoteScore tns ) const diff --git a/src/ScoreKeeperNormal.h b/src/ScoreKeeperNormal.h index 59da85f0d1..89e444f392 100644 --- a/src/ScoreKeeperNormal.h +++ b/src/ScoreKeeperNormal.h @@ -10,6 +10,7 @@ class Steps; class Song; struct RadarValues; +class TimingData; AutoScreenMessage( SM_PlayToasty ); @@ -76,10 +77,10 @@ public: // This must be calculated using only cached radar values so that we can // do it quickly. - static int GetPossibleDancePoints( const RadarValues& fRadars ); - static int GetPossibleDancePoints( const RadarValues& fOriginalRadars, const RadarValues& fPostRadars ); - static int GetPossibleGradePoints( const RadarValues& fRadars ); - static int GetPossibleGradePoints( const RadarValues& fOriginalRadars, const RadarValues& fPostRadars ); + static int GetPossibleDancePoints( NoteData* nd, const TimingData* td, float fSongSeconds ); + static int GetPossibleDancePoints( NoteData* ndPre, NoteData* ndPost, const TimingData* td, float fSongSeconds ); + static int GetPossibleGradePoints( NoteData* nd, const TimingData* td, float fSongSeconds ); + static int GetPossibleGradePoints( NoteData* ndPre, NoteData* ndPost, const TimingData* td, float fSongSeconds ); int TapNoteScoreToDancePoints( TapNoteScore tns ) const; int HoldNoteScoreToDancePoints( HoldNoteScore hns ) const; diff --git a/src/StepsUtil.cpp b/src/StepsUtil.cpp index b1bdf75d50..54866f0370 100644 --- a/src/StepsUtil.cpp +++ b/src/StepsUtil.cpp @@ -9,7 +9,8 @@ #include "XmlFile.h" #include "UnlockManager.h" #include "SongUtil.h" - +#include "NoteData.h" +#include "NoteTypes.h" // ROWS_PER_BEAT bool StepsCriteria::Matches( const Song *pSong, const Steps *pSteps ) const {