From c4f7aab9a14dfa7de18f0dbeb68b9aeff1f746a1 Mon Sep 17 00:00:00 2001 From: sigatrev Date: Wed, 23 Apr 2014 21:45:37 -0500 Subject: [PATCH] Attempted fix of Tick Holds NoteDataUtil::GetTotalHoldTicks() was not counting the last tick of holds which ended on the last row of the song. Extended the range to include the last row. NoteDataUtil::GetTotalHoldTicks() was counting number of rows held, when it should only count 1 regardless of number( at least to mimic pump ) Player::CrossedRows() was assuming a constant tick rate over the crossed rows, leading to potentially inaccurate tick counts. Pump holds were counting "HoldNote_Held" due to capitalization in the metrics. Fixed metrics and made "IsGame" function case insensitive. --- Themes/_fallback/Scripts/03 Gameplay.lua | 2 +- Themes/_fallback/metrics.ini | 8 ++-- src/NoteDataUtil.cpp | 8 ++-- src/Player.cpp | 55 +++++++----------------- 4 files changed, 25 insertions(+), 48 deletions(-) diff --git a/Themes/_fallback/Scripts/03 Gameplay.lua b/Themes/_fallback/Scripts/03 Gameplay.lua index c7cca5055e..25b7b2ecb6 100644 --- a/Themes/_fallback/Scripts/03 Gameplay.lua +++ b/Themes/_fallback/Scripts/03 Gameplay.lua @@ -8,7 +8,7 @@ local function CurGameName() end -- Check the active game mode against a string. Cut down typing this in metrics. -function IsGame(str) return CurGameName() == str end +function IsGame(str) return CurGameName():lower() == str:lower() end -- GetExtraColorThreshold() -- [en] returns the difficulty threshold in meter diff --git a/Themes/_fallback/metrics.ini b/Themes/_fallback/metrics.ini index 82a804fe48..636a89e158 100644 --- a/Themes/_fallback/metrics.ini +++ b/Themes/_fallback/metrics.ini @@ -642,8 +642,8 @@ LifePercentChangeW4=0.000 LifePercentChangeW5=-0.040 LifePercentChangeMiss=-0.080 LifePercentChangeHitMine=-0.160 -LifePercentChangeHeld=IsGame("Pump") and 0.000 or 0.008 -LifePercentChangeLetGo=IsGame("Pump") and 0.000 or -0.080 +LifePercentChangeHeld=IsGame("pump") and 0.000 or 0.008 +LifePercentChangeLetGo=IsGame("pump") and 0.000 or -0.080 LifePercentChangeMissedHold=0.000 LifePercentChangeCheckpointMiss=-0.080 LifePercentChangeCheckpointHit=0.008 @@ -1337,7 +1337,7 @@ FrameOverP2OffCommand= [ScoreKeeperNormal] PercentScoreWeightCheckpointHit=3 PercentScoreWeightCheckpointMiss=0 -PercentScoreWeightHeld=IsGame("Pump") and 0 or 3 +PercentScoreWeightHeld=IsGame("pump") and 0 or 3 PercentScoreWeightHitMine=-2 PercentScoreWeightMissedHold=0 PercentScoreWeightLetGo=0 @@ -1349,7 +1349,7 @@ PercentScoreWeightW4=0 PercentScoreWeightW5=0 GradeWeightCheckpointHit=2 GradeWeightCheckpointMiss=-8 -GradeWeightHeld=IsGame("Pump") and 0 or 6 +GradeWeightHeld=IsGame("pump") and 0 or 6 GradeWeightHitMine=-8 GradeWeightMissedHold=0 GradeWeightLetGo=0 diff --git a/src/NoteDataUtil.cpp b/src/NoteDataUtil.cpp index bd1b6d5797..8ad1e123da 100644 --- a/src/NoteDataUtil.cpp +++ b/src/NoteDataUtil.cpp @@ -2616,7 +2616,8 @@ 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(); + // Last row must be included. -- Matt + int end = nd->GetLastRow()+1; 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 @@ -2627,9 +2628,10 @@ unsigned int NoteDataUtil::GetTotalHoldTicks( NoteData* nd, const TimingData* td 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); + // 1 tick per row. + if( nd->GetNumTracksHeldAtRow(j) > 0 ) + ret++; } end = ts->GetRow(); } diff --git a/src/Player.cpp b/src/Player.cpp index 1e4618b464..511e995cdc 100644 --- a/src/Player.cpp +++ b/src/Player.cpp @@ -618,7 +618,7 @@ void Player::Load() // Figured this is probably a little expensive so let's cache it m_bTickHolds = GAMESTATE->GetCurrentGame()->m_bTickHolds; - + m_LastTapNoteScore = TNS_None; // The editor can start playing in the middle of the song. const int iNoteRow = BeatToNoteRowNotRounded( m_pPlayerState->m_Position.m_fSongBeat ); @@ -1289,7 +1289,7 @@ void Player::UpdateHoldNotes( int iSongRow, float fDeltaTime, vectorGetCurrentGame()->m_bTickHolds ) fLife = 0.0; + if( m_bTickHolds ) fLife = 0.0; else { // Decrease life @@ -3022,23 +3022,16 @@ void Player::CrossedRows( int iLastRowCrossed, const RageTimer &now ) * TODO: Move this to a separate function. */ if( m_bTickHolds && m_pPlayerState->m_PlayerController != PC_AUTOPLAY ) { - int tickCurrent = m_Timing->GetTickcountAtRow( iLastRowCrossed ); - // There are some charts that don't want tickcounts involved at all. - int iCheckpointFrequencyRows = ( tickCurrent > 0 ? ROWS_PER_BEAT / tickCurrent : 0 ); - - if( iCheckpointFrequencyRows > 0 ) + // Few rows typically cross per update. Easier to check all crossed rows + // than to calculate from timing segments. + for( int r = m_iFirstUncrossedRow; r <= iLastRowCrossed; ++r ) { - // "the first row after the start of the range that lands on a beat" - int iFirstCheckpointInRange = ((m_iFirstUncrossedRow+iCheckpointFrequencyRows-1) - /iCheckpointFrequencyRows) * iCheckpointFrequencyRows; + int tickCurrent = m_Timing->GetTickcountAtRow( r ); - // "the last row or first row earlier that lands on a beat" - int iLastCheckpointInRange = ((iLastRowCrossed)/iCheckpointFrequencyRows) - * iCheckpointFrequencyRows; - - for( int r = iFirstCheckpointInRange; r <= iLastCheckpointInRange; r += iCheckpointFrequencyRows ) + // There is a tick count at this row + if( tickCurrent > 0 && r % ( ROWS_PER_BEAT / tickCurrent ) == 0 ) { - //LOG->Trace( "%d...", r ); + vector viColsWithHold; int iNumHoldsHeldThisRow = 0; int iNumHoldsMissedThisRow = 0; @@ -3051,27 +3044,9 @@ void Player::CrossedRows( int iLastRowCrossed, const RageTimer &now ) if( tn.type != TapNote::hold_head ) continue; - int iStartRow = nIter.Row(); - int iEndRow = iStartRow + tn.iDuration; int iTrack = nIter.Track(); - - // "the first row after the hold head that lands on a beat" - int iFirstCheckpointOfHold = ((iStartRow+iCheckpointFrequencyRows)/iCheckpointFrequencyRows) - * iCheckpointFrequencyRows; - - // "the end row or the first earlier row that lands on a beat" - int iLastCheckpointOfHold = ((iEndRow)/iCheckpointFrequencyRows) - * iCheckpointFrequencyRows; - - // count the end of the hold as a checkpoint - bool bHoldOverlapsRow = iFirstCheckpointOfHold <= r && r <= iLastCheckpointOfHold; - if( !bHoldOverlapsRow ) - continue; - - - viColsWithHold.push_back( iTrack ); - + if( tn.HoldResult.fLife > 0 ) { ++iNumHoldsHeldThisRow; @@ -3086,12 +3061,12 @@ void Player::CrossedRows( int iLastRowCrossed, const RageTimer &now ) GAMESTATE->SetProcessedTimingData(this->m_Timing); // TODO: Find a better way of handling hold checkpoints with other taps. - if( !viColsWithHold.empty() && ( CHECKPOINTS_TAPS_SEPARATE_JUDGMENT || m_NoteData.GetNumTapNotesInRow( iLastRowCrossed ) == 0 ) ) + if( !viColsWithHold.empty() && ( CHECKPOINTS_TAPS_SEPARATE_JUDGMENT || m_NoteData.GetNumTapNotesInRow( r ) == 0 ) ) { - HandleHoldCheckpoint(r, - iNumHoldsHeldThisRow, - iNumHoldsMissedThisRow, - viColsWithHold ); + HandleHoldCheckpoint(r, + iNumHoldsHeldThisRow, + iNumHoldsMissedThisRow, + viColsWithHold ); } } }