experimental: combo checkpoints for holds
This commit is contained in:
@@ -2232,6 +2232,7 @@ TapJudgmentsUnderField=false
|
|||||||
HoldJudgmentsUnderField=false
|
HoldJudgmentsUnderField=false
|
||||||
PenalizeTapScoreNone=false
|
PenalizeTapScoreNone=false
|
||||||
JudgeHoldNotesOnSameRowTogether=false
|
JudgeHoldNotesOnSameRowTogether=false
|
||||||
|
HoldCheckpoints=false
|
||||||
|
|
||||||
[PlayerShared]
|
[PlayerShared]
|
||||||
Fallback="Player"
|
Fallback="Player"
|
||||||
|
|||||||
+89
-12
@@ -128,6 +128,7 @@ Preference<float> g_fTimingWindowHopo ( "TimingWindowHopo", 0.25 ); // max ti
|
|||||||
Preference<float> g_fTimingWindowStrum ( "TimingWindowStrum", 0.1f ); // max time between strum and when the frets must match
|
Preference<float> g_fTimingWindowStrum ( "TimingWindowStrum", 0.1f ); // max time between strum and when the frets must match
|
||||||
ThemeMetric<bool> PENALIZE_TAP_SCORE_NONE ( "Player", "PenalizeTapScoreNone" );
|
ThemeMetric<bool> PENALIZE_TAP_SCORE_NONE ( "Player", "PenalizeTapScoreNone" );
|
||||||
ThemeMetric<bool> JUDGE_HOLD_NOTES_ON_SAME_ROW_TOGETHER ( "Player", "JudgeHoldNotesOnSameRowTogether" );
|
ThemeMetric<bool> JUDGE_HOLD_NOTES_ON_SAME_ROW_TOGETHER ( "Player", "JudgeHoldNotesOnSameRowTogether" );
|
||||||
|
ThemeMetric<bool> HOLD_CHECKPOINTS ( "Player", "HoldCheckpoints" );
|
||||||
|
|
||||||
|
|
||||||
float Player::GetWindowSeconds( TimingWindow tw )
|
float Player::GetWindowSeconds( TimingWindow tw )
|
||||||
@@ -369,8 +370,8 @@ void Player::Load()
|
|||||||
m_LastTapNoteScore = TNS_None;
|
m_LastTapNoteScore = TNS_None;
|
||||||
// The editor can start playing in the middle of the song.
|
// The editor can start playing in the middle of the song.
|
||||||
const int iNoteRow = BeatToNoteRowNotRounded( GAMESTATE->m_fSongBeat );
|
const int iNoteRow = BeatToNoteRowNotRounded( GAMESTATE->m_fSongBeat );
|
||||||
m_iRowLastCrossed = iNoteRow - 1;
|
m_iFirstUncrossedRow = iNoteRow - 1;
|
||||||
m_iMineRowLastCrossed = iNoteRow - 1;
|
m_iFirstUncrossedMineRow = iNoteRow - 1;
|
||||||
m_iRowLastJudged = iNoteRow - 1;
|
m_iRowLastJudged = iNoteRow - 1;
|
||||||
m_iMineRowLastJudged = iNoteRow - 1;
|
m_iMineRowLastJudged = iNoteRow - 1;
|
||||||
m_pJudgedRows->Reset( iNoteRow );
|
m_pJudgedRows->Reset( iNoteRow );
|
||||||
@@ -708,11 +709,9 @@ void Player::Update( float fDeltaTime )
|
|||||||
const int iRowNow = BeatToNoteRowNotRounded( GAMESTATE->m_fSongBeat );
|
const int iRowNow = BeatToNoteRowNotRounded( GAMESTATE->m_fSongBeat );
|
||||||
if( iRowNow >= 0 )
|
if( iRowNow >= 0 )
|
||||||
{
|
{
|
||||||
// for each index we crossed since the last update
|
|
||||||
if( GAMESTATE->IsPlayerEnabled(m_pPlayerState) )
|
if( GAMESTATE->IsPlayerEnabled(m_pPlayerState) )
|
||||||
FOREACH_NONEMPTY_ROW_ALL_TRACKS_RANGE( m_NoteData, r, m_iRowLastCrossed, iRowNow+1 )
|
CrossedRows( m_iFirstUncrossedRow, iRowNow, now );
|
||||||
CrossedRow( r, now );
|
m_iFirstUncrossedRow = iRowNow+1;
|
||||||
m_iRowLastCrossed = iRowNow+1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -726,9 +725,9 @@ void Player::Update( float fDeltaTime )
|
|||||||
{
|
{
|
||||||
// for each index we crossed since the last update
|
// for each index we crossed since the last update
|
||||||
if( GAMESTATE->IsPlayerEnabled(m_pPlayerState) )
|
if( GAMESTATE->IsPlayerEnabled(m_pPlayerState) )
|
||||||
FOREACH_NONEMPTY_ROW_ALL_TRACKS_RANGE( m_NoteData, r, m_iMineRowLastCrossed, iRowNow+1 )
|
FOREACH_NONEMPTY_ROW_ALL_TRACKS_RANGE( m_NoteData, r, m_iFirstUncrossedMineRow, iRowNow+1 )
|
||||||
CrossedMineRow( r, now );
|
CrossedMineRow( r, now );
|
||||||
m_iMineRowLastCrossed = iRowNow+1;
|
m_iFirstUncrossedMineRow = iRowNow+1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2166,26 +2165,104 @@ void Player::FlashGhostRow( int iRow, PlayerNumber pn )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::CrossedRow( int iNoteRow, const RageTimer &now )
|
void Player::CrossedRows( int iFirstRowCrossed, int iLastRowCrossed, const RageTimer &now )
|
||||||
{
|
{
|
||||||
|
//LOG->Trace( "Player::CrossedRows %d %d", iFirstRowCrossed, iLastRowCrossed );
|
||||||
|
|
||||||
|
// for each index we crossed since the last update
|
||||||
|
FOREACH_NONEMPTY_ROW_ALL_TRACKS_RANGE( m_NoteData, r, m_iFirstUncrossedRow, iLastRowCrossed+1 )
|
||||||
|
{
|
||||||
// If we're doing random vanish, randomise notes on the fly.
|
// If we're doing random vanish, randomise notes on the fly.
|
||||||
if( m_pPlayerState->m_PlayerOptions.GetCurrent().m_fAppearances[PlayerOptions::APPEARANCE_RANDOMVANISH]==1 )
|
if( m_pPlayerState->m_PlayerOptions.GetCurrent().m_fAppearances[PlayerOptions::APPEARANCE_RANDOMVANISH]==1 )
|
||||||
RandomizeNotes( iNoteRow );
|
RandomizeNotes( r );
|
||||||
|
|
||||||
// check to see if there's a note at the crossed row
|
// check to see if there's a note at the crossed row
|
||||||
if( m_pPlayerState->m_PlayerController != PC_HUMAN )
|
if( m_pPlayerState->m_PlayerController != PC_HUMAN )
|
||||||
{
|
{
|
||||||
for( int t=0; t<m_NoteData.GetNumTracks(); t++ )
|
for( int t=0; t<m_NoteData.GetNumTracks(); t++ )
|
||||||
{
|
{
|
||||||
const TapNote &tn = m_NoteData.GetTapNote( t, iNoteRow );
|
const TapNote &tn = m_NoteData.GetTapNote( t, r );
|
||||||
if( tn.type != TapNote::empty && tn.result.tns == TNS_None )
|
if( tn.type != TapNote::empty && tn.result.tns == TNS_None )
|
||||||
{
|
{
|
||||||
Step( t, iNoteRow, now, false, false );
|
Step( t, r, now, false, false );
|
||||||
if( m_pPlayerState->m_PlayerController == PC_AUTOPLAY )
|
if( m_pPlayerState->m_PlayerController == PC_AUTOPLAY )
|
||||||
STATSMAN->m_CurStageStats.m_bUsedAutoplay = true;
|
STATSMAN->m_CurStageStats.m_bUsedAutoplay = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Update hold checkpoints
|
||||||
|
//
|
||||||
|
|
||||||
|
if( HOLD_CHECKPOINTS )
|
||||||
|
{
|
||||||
|
int iFirstCheckpointInRange = ((iFirstRowCrossed+ROWS_PER_BEAT-1)/ROWS_PER_BEAT) * ROWS_PER_BEAT;
|
||||||
|
int iLastCheckpointInRange = ((iLastRowCrossed)/ROWS_PER_BEAT) * ROWS_PER_BEAT;
|
||||||
|
|
||||||
|
for( int r = iFirstCheckpointInRange; r <= iLastCheckpointInRange; r += ROWS_PER_BEAT )
|
||||||
|
{
|
||||||
|
LOG->Trace( "%d...", r );
|
||||||
|
bool bAnyHoldsThisRow = false;
|
||||||
|
bool bAllHoldsHeldThisRow = true;
|
||||||
|
|
||||||
|
// start at r-1 so that we can count the tail of a hold as a checkpoint
|
||||||
|
NoteData::all_tracks_iterator iter = m_NoteData.GetTapNoteRangeAllTracks( r-1, r+1, NULL, true );
|
||||||
|
for( ; !iter.IsAtEnd(); ++iter )
|
||||||
|
{
|
||||||
|
TapNote &tn = *iter;
|
||||||
|
if( tn.type != TapNote::hold_head )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int iStartRow = iter.Row();
|
||||||
|
int iEndRow = iStartRow + tn.iDuration;
|
||||||
|
|
||||||
|
// First checkpoint is the first row after the hold head that lands on a beat.
|
||||||
|
int iFirstCheckpointOfHold = ((iStartRow+ROWS_PER_BEAT)/ROWS_PER_BEAT) * ROWS_PER_BEAT;
|
||||||
|
|
||||||
|
// The last checkpoint is the end row or the first earlier row that lands on a beat.
|
||||||
|
int iLastCheckpointOfHold = ((iEndRow)/ROWS_PER_BEAT) * ROWS_PER_BEAT;
|
||||||
|
|
||||||
|
// count the end of the hold as a checkpoint
|
||||||
|
|
||||||
|
bool bHoldOverlapsRow = iFirstCheckpointOfHold <= r && r <= iLastCheckpointOfHold;
|
||||||
|
if( !bHoldOverlapsRow )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bAnyHoldsThisRow = true;
|
||||||
|
bAllHoldsHeldThisRow &= tn.HoldResult.bHeld;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( bAnyHoldsThisRow )
|
||||||
|
{
|
||||||
|
if( m_pPlayerStageStats )
|
||||||
|
{
|
||||||
|
// increment combo
|
||||||
|
const int iOldCombo = m_pPlayerStageStats ? m_pPlayerStageStats->m_iCurCombo : 0;
|
||||||
|
const int iOldMissCombo = m_pPlayerStageStats ? m_pPlayerStageStats->m_iCurMissCombo : 0;
|
||||||
|
|
||||||
|
if( bAnyHoldsThisRow )
|
||||||
|
{
|
||||||
|
m_pPlayerStageStats->m_iCurCombo++;
|
||||||
|
m_pPlayerStageStats->m_iCurMissCombo = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_pPlayerStageStats->m_iCurCombo = 0;
|
||||||
|
m_pPlayerStageStats->m_iCurMissCombo++;
|
||||||
|
}
|
||||||
|
|
||||||
|
SendComboMessages( iOldCombo, iOldMissCombo );
|
||||||
|
if( m_pPlayerStageStats )
|
||||||
|
{
|
||||||
|
SetCombo( m_pPlayerStageStats->m_iCurCombo, m_pPlayerStageStats->m_iCurMissCombo );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::CrossedMineRow( int iNoteRow, const RageTimer &now )
|
void Player::CrossedMineRow( int iNoteRow, const RageTimer &now )
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ public:
|
|||||||
ScoreKeeper* pPrimaryScoreKeeper,
|
ScoreKeeper* pPrimaryScoreKeeper,
|
||||||
ScoreKeeper* pSecondaryScoreKeeper );
|
ScoreKeeper* pSecondaryScoreKeeper );
|
||||||
void Load();
|
void Load();
|
||||||
void CrossedRow( int iNoteRow, const RageTimer &now );
|
void CrossedRows( int iFirstRowCrossed, int iLastRowCrossed, const RageTimer &now );
|
||||||
void CrossedMineRow( int iNoteRow, const RageTimer &now );
|
void CrossedMineRow( int iNoteRow, const RageTimer &now );
|
||||||
bool IsOniDead() const;
|
bool IsOniDead() const;
|
||||||
|
|
||||||
@@ -167,8 +167,8 @@ protected:
|
|||||||
ScoreKeeper *m_pSecondaryScoreKeeper;
|
ScoreKeeper *m_pSecondaryScoreKeeper;
|
||||||
Inventory *m_pInventory;
|
Inventory *m_pInventory;
|
||||||
|
|
||||||
int m_iRowLastCrossed;
|
int m_iFirstUncrossedRow;
|
||||||
int m_iMineRowLastCrossed;
|
int m_iFirstUncrossedMineRow;
|
||||||
int m_iRowLastJudged; // Everything up to and including this row has been judged.
|
int m_iRowLastJudged; // Everything up to and including this row has been judged.
|
||||||
int m_iMineRowLastJudged;
|
int m_iMineRowLastJudged;
|
||||||
int m_iLastSeenCombo;
|
int m_iLastSeenCombo;
|
||||||
|
|||||||
Reference in New Issue
Block a user