add Player::UpdateHoldNotes, score groups of hold notes together if JudgeHoldNotesOnSameRowTogether (experimental)
This commit is contained in:
+142
-111
@@ -650,8 +650,10 @@ void Player::Update( float fDeltaTime )
|
|||||||
// update HoldNotes logic
|
// update HoldNotes logic
|
||||||
//
|
//
|
||||||
{
|
{
|
||||||
|
// Check only 1 beat back for holds. Even 1 beat is overkill.
|
||||||
const int iStartCheckingAt = max( 0, iSongRow-BeatToNoteRow(1) );
|
const int iStartCheckingAt = max( 0, iSongRow-BeatToNoteRow(1) );
|
||||||
vector<TrackRowTapNote> vHoldNotesToGradeTogether;
|
vector<TrackRowTapNote> vHoldNotesToGradeTogether;
|
||||||
|
int iRowOfLastHoldNote = -1;
|
||||||
NoteData::all_tracks_iterator iter = m_NoteData.GetTapNoteRangeAllTracks( iStartCheckingAt, iSongRow+1, NULL, true );
|
NoteData::all_tracks_iterator iter = m_NoteData.GetTapNoteRangeAllTracks( iStartCheckingAt, iSongRow+1, NULL, true );
|
||||||
for( ; !iter.IsAtEnd(); ++iter )
|
for( ; !iter.IsAtEnd(); ++iter )
|
||||||
{
|
{
|
||||||
@@ -661,123 +663,25 @@ void Player::Update( float fDeltaTime )
|
|||||||
|
|
||||||
int iTrack = iter.Track();
|
int iTrack = iter.Track();
|
||||||
int iRow = iter.Row();
|
int iRow = iter.Row();
|
||||||
int iEndRow = iRow + tn.iDuration;
|
TrackRowTapNote trtn = { iTrack, iRow, &tn };
|
||||||
|
|
||||||
// set hold flags so NoteField can do intelligent drawing
|
if( iRow != iRowOfLastHoldNote )//|| !JUDGE_HOLD_NOTES_ON_SAME_ROW_TOGETHER )
|
||||||
tn.HoldResult.bHeld = false;
|
|
||||||
tn.HoldResult.bActive = false;
|
|
||||||
|
|
||||||
// If the song beat is in the range of this hold:
|
|
||||||
if( iRow <= iSongRow && iRow <= iEndRow )
|
|
||||||
tn.HoldResult.fOverlappedTime += fDeltaTime;
|
|
||||||
else
|
|
||||||
tn.HoldResult.fOverlappedTime = 0;
|
|
||||||
|
|
||||||
HoldNoteScore hns = tn.HoldResult.hns;
|
|
||||||
if( hns != HNS_None ) // if this HoldNote already has a result
|
|
||||||
continue; // we don't need to update the logic for this one
|
|
||||||
|
|
||||||
// TODO: Remove use of PlayerNumber.
|
|
||||||
PlayerNumber pn = m_pPlayerState->m_PlayerNumber;
|
|
||||||
|
|
||||||
// if they got a bad score or haven't stepped on the corresponding tap yet
|
|
||||||
const TapNoteScore tns = tn.result.tns;
|
|
||||||
const bool bSteppedOnTapNote = tns != TNS_None && tns != TNS_Miss; // did they step on the start of this hold?
|
|
||||||
|
|
||||||
bool bIsHoldingButton = false;
|
|
||||||
if( m_pPlayerState->m_PlayerController != PC_HUMAN )
|
|
||||||
{
|
{
|
||||||
// TODO: Make the CPU miss sometimes.
|
if( !vHoldNotesToGradeTogether.empty() )
|
||||||
bIsHoldingButton = true;
|
|
||||||
if( m_pPlayerState->m_PlayerController == PC_AUTOPLAY )
|
|
||||||
STATSMAN->m_CurStageStats.m_bUsedAutoplay = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
GameInput GameI = GAMESTATE->GetCurrentStyle()->StyleInputToGameInput( iTrack, pn );
|
|
||||||
bIsHoldingButton = INPUTMAPPER->IsBeingPressed( GameI, m_pPlayerState->m_mp );
|
|
||||||
}
|
|
||||||
|
|
||||||
float fLife = tn.HoldResult.fLife;
|
|
||||||
if( bSteppedOnTapNote && fLife != 0 )
|
|
||||||
{
|
|
||||||
/* This hold note is not judged and we stepped on its head. Update iLastHeldRow.
|
|
||||||
* Do this even if we're a little beyond the end of the hold note, to make sure
|
|
||||||
* iLastHeldRow is clamped to iEndRow if the hold note is held all the way. */
|
|
||||||
tn.HoldResult.iLastHeldRow = min( iSongRow, iEndRow );
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the song beat is in the range of this hold:
|
|
||||||
if( iRow <= iSongRow && iRow <= iEndRow )
|
|
||||||
{
|
|
||||||
switch( tn.subType )
|
|
||||||
{
|
{
|
||||||
case TapNote::hold_head_hold:
|
UpdateHoldNotes( iSongRow, fDeltaTime, vHoldNotesToGradeTogether );
|
||||||
// set hold flag so NoteField can do intelligent drawing
|
vHoldNotesToGradeTogether.clear();
|
||||||
tn.HoldResult.bHeld = bIsHoldingButton && bSteppedOnTapNote;
|
|
||||||
tn.HoldResult.bActive = bSteppedOnTapNote;
|
|
||||||
|
|
||||||
if( bSteppedOnTapNote && bIsHoldingButton )
|
|
||||||
{
|
|
||||||
// Increase life
|
|
||||||
fLife = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Decrease life
|
|
||||||
fLife -= fDeltaTime/GetWindowSeconds(TW_Hold);
|
|
||||||
fLife = max( fLife, 0 ); // clamp
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TapNote::hold_head_roll:
|
|
||||||
tn.HoldResult.bHeld = true;
|
|
||||||
tn.HoldResult.bActive = bSteppedOnTapNote;
|
|
||||||
|
|
||||||
// give positive life in Step(), not here.
|
|
||||||
|
|
||||||
// Decrease life
|
|
||||||
fLife -= fDeltaTime/GetWindowSeconds(TW_Roll);
|
|
||||||
fLife = max( fLife, 0 ); // clamp
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ASSERT(0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
iRowOfLastHoldNote = iRow;
|
||||||
// TODO: Cap the active time passed to the score keeper to the actual start time and end time of the hold.
|
vHoldNotesToGradeTogether.push_back( trtn );
|
||||||
if( tn.HoldResult.bActive )
|
|
||||||
{
|
|
||||||
float fSecondsActiveSinceLastUpdate = fDeltaTime * GAMESTATE->m_SongOptions.GetCurrent().m_fMusicRate;
|
|
||||||
if( m_pPrimaryScoreKeeper )
|
|
||||||
m_pPrimaryScoreKeeper->HandleHoldActiveSeconds( fSecondsActiveSinceLastUpdate );
|
|
||||||
if( m_pSecondaryScoreKeeper )
|
|
||||||
m_pSecondaryScoreKeeper->HandleHoldActiveSeconds( fSecondsActiveSinceLastUpdate );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* check for LetGo. If the head was missed completely, don't count an LetGo. */
|
|
||||||
if( bSteppedOnTapNote && fLife == 0 ) // the player has not pressed the button for a long time!
|
|
||||||
hns = HNS_LetGo;
|
|
||||||
|
|
||||||
// check for OK
|
|
||||||
if( iSongRow >= iEndRow && bSteppedOnTapNote && fLife > 0 ) // if this HoldNote is in the past
|
|
||||||
{
|
|
||||||
fLife = 1;
|
|
||||||
hns = HNS_Held;
|
|
||||||
bool bBright = m_pPlayerStageStats && m_pPlayerStageStats->m_iCurCombo>(int)BRIGHT_GHOST_COMBO_THRESHOLD;
|
|
||||||
if( m_pNoteField )
|
|
||||||
m_pNoteField->DidHoldNote( iTrack, HNS_Held, bBright ); // bright ghost flash
|
|
||||||
}
|
|
||||||
|
|
||||||
tn.HoldResult.fLife = fLife;
|
|
||||||
tn.HoldResult.hns = hns;
|
|
||||||
|
|
||||||
if( hns != HNS_None )
|
|
||||||
{
|
|
||||||
/* this note has been judged */
|
|
||||||
HandleHoldScore( tn );
|
|
||||||
SetHoldJudgment( tn.result.tns, tn.HoldResult.hns, iTrack );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( !vHoldNotesToGradeTogether.empty() )
|
||||||
|
{
|
||||||
|
UpdateHoldNotes( iSongRow, fDeltaTime, vHoldNotesToGradeTogether );
|
||||||
|
vHoldNotesToGradeTogether.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -819,6 +723,133 @@ void Player::Update( float fDeltaTime )
|
|||||||
ApplyWaitingTransforms();
|
ApplyWaitingTransforms();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Update every hold in TrackRowTapNote, but require that all holds in */
|
||||||
|
void Player::UpdateHoldNotes( int iSongRow, float fDeltaTime, vector<TrackRowTapNote> &vTN )
|
||||||
|
{
|
||||||
|
FOREACH( TrackRowTapNote, vTN, trtn )
|
||||||
|
{
|
||||||
|
int iTrack = trtn->iTrack;
|
||||||
|
int iRow = trtn->iRow;
|
||||||
|
TapNote &tn = *trtn->pTN;
|
||||||
|
int iEndRow = iRow + tn.iDuration;
|
||||||
|
|
||||||
|
// set hold flags so NoteField can do intelligent drawing
|
||||||
|
tn.HoldResult.bHeld = false;
|
||||||
|
tn.HoldResult.bActive = false;
|
||||||
|
|
||||||
|
// If the song beat is in the range of this hold:
|
||||||
|
if( iRow <= iSongRow && iRow <= iEndRow )
|
||||||
|
tn.HoldResult.fOverlappedTime += fDeltaTime;
|
||||||
|
else
|
||||||
|
tn.HoldResult.fOverlappedTime = 0;
|
||||||
|
|
||||||
|
HoldNoteScore hns = tn.HoldResult.hns;
|
||||||
|
if( hns != HNS_None ) // if this HoldNote already has a result
|
||||||
|
continue; // we don't need to update the logic for this one
|
||||||
|
|
||||||
|
// TODO: Remove use of PlayerNumber.
|
||||||
|
PlayerNumber pn = m_pPlayerState->m_PlayerNumber;
|
||||||
|
|
||||||
|
// if they got a bad score or haven't stepped on the corresponding tap yet
|
||||||
|
const TapNoteScore tns = tn.result.tns;
|
||||||
|
const bool bSteppedOnTapNote = tns != TNS_None && tns != TNS_Miss; // did they step on the start of this hold?
|
||||||
|
|
||||||
|
bool bIsHoldingButton = false;
|
||||||
|
if( m_pPlayerState->m_PlayerController != PC_HUMAN )
|
||||||
|
{
|
||||||
|
// TODO: Make the CPU miss sometimes.
|
||||||
|
bIsHoldingButton = true;
|
||||||
|
if( m_pPlayerState->m_PlayerController == PC_AUTOPLAY )
|
||||||
|
STATSMAN->m_CurStageStats.m_bUsedAutoplay = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GameInput GameI = GAMESTATE->GetCurrentStyle()->StyleInputToGameInput( iTrack, pn );
|
||||||
|
bIsHoldingButton = INPUTMAPPER->IsBeingPressed( GameI, m_pPlayerState->m_mp );
|
||||||
|
}
|
||||||
|
|
||||||
|
float fLife = tn.HoldResult.fLife;
|
||||||
|
if( bSteppedOnTapNote && fLife != 0 )
|
||||||
|
{
|
||||||
|
/* This hold note is not judged and we stepped on its head. Update iLastHeldRow.
|
||||||
|
* Do this even if we're a little beyond the end of the hold note, to make sure
|
||||||
|
* iLastHeldRow is clamped to iEndRow if the hold note is held all the way. */
|
||||||
|
tn.HoldResult.iLastHeldRow = min( iSongRow, iEndRow );
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the song beat is in the range of this hold:
|
||||||
|
if( iRow <= iSongRow && iRow <= iEndRow )
|
||||||
|
{
|
||||||
|
switch( tn.subType )
|
||||||
|
{
|
||||||
|
case TapNote::hold_head_hold:
|
||||||
|
// set hold flag so NoteField can do intelligent drawing
|
||||||
|
tn.HoldResult.bHeld = bIsHoldingButton && bSteppedOnTapNote;
|
||||||
|
tn.HoldResult.bActive = bSteppedOnTapNote;
|
||||||
|
|
||||||
|
if( bSteppedOnTapNote && bIsHoldingButton )
|
||||||
|
{
|
||||||
|
// Increase life
|
||||||
|
fLife = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Decrease life
|
||||||
|
fLife -= fDeltaTime/GetWindowSeconds(TW_Hold);
|
||||||
|
fLife = max( fLife, 0 ); // clamp
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TapNote::hold_head_roll:
|
||||||
|
tn.HoldResult.bHeld = true;
|
||||||
|
tn.HoldResult.bActive = bSteppedOnTapNote;
|
||||||
|
|
||||||
|
// give positive life in Step(), not here.
|
||||||
|
|
||||||
|
// Decrease life
|
||||||
|
fLife -= fDeltaTime/GetWindowSeconds(TW_Roll);
|
||||||
|
fLife = max( fLife, 0 ); // clamp
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ASSERT(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Cap the active time passed to the score keeper to the actual start time and end time of the hold.
|
||||||
|
if( tn.HoldResult.bActive )
|
||||||
|
{
|
||||||
|
float fSecondsActiveSinceLastUpdate = fDeltaTime * GAMESTATE->m_SongOptions.GetCurrent().m_fMusicRate;
|
||||||
|
if( m_pPrimaryScoreKeeper )
|
||||||
|
m_pPrimaryScoreKeeper->HandleHoldActiveSeconds( fSecondsActiveSinceLastUpdate );
|
||||||
|
if( m_pSecondaryScoreKeeper )
|
||||||
|
m_pSecondaryScoreKeeper->HandleHoldActiveSeconds( fSecondsActiveSinceLastUpdate );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check for LetGo. If the head was missed completely, don't count an LetGo. */
|
||||||
|
if( bSteppedOnTapNote && fLife == 0 ) // the player has not pressed the button for a long time!
|
||||||
|
hns = HNS_LetGo;
|
||||||
|
|
||||||
|
// check for OK
|
||||||
|
if( iSongRow >= iEndRow && bSteppedOnTapNote && fLife > 0 ) // if this HoldNote is in the past
|
||||||
|
{
|
||||||
|
fLife = 1;
|
||||||
|
hns = HNS_Held;
|
||||||
|
bool bBright = m_pPlayerStageStats && m_pPlayerStageStats->m_iCurCombo>(int)BRIGHT_GHOST_COMBO_THRESHOLD;
|
||||||
|
if( m_pNoteField )
|
||||||
|
m_pNoteField->DidHoldNote( iTrack, HNS_Held, bBright ); // bright ghost flash
|
||||||
|
}
|
||||||
|
|
||||||
|
tn.HoldResult.fLife = fLife;
|
||||||
|
tn.HoldResult.hns = hns;
|
||||||
|
|
||||||
|
if( hns != HNS_None )
|
||||||
|
{
|
||||||
|
/* this note has been judged */
|
||||||
|
HandleHoldScore( tn );
|
||||||
|
SetHoldJudgment( tn.result.tns, tn.HoldResult.hns, iTrack );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Player::ApplyWaitingTransforms()
|
void Player::ApplyWaitingTransforms()
|
||||||
{
|
{
|
||||||
for( unsigned j=0; j<m_pPlayerState->m_ModsToApply.size(); j++ )
|
for( unsigned j=0; j<m_pPlayerState->m_ModsToApply.size(); j++ )
|
||||||
|
|||||||
@@ -86,7 +86,6 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class Player: public ActorFrame
|
class Player: public ActorFrame
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -97,6 +96,14 @@ public:
|
|||||||
virtual void Update( float fDeltaTime );
|
virtual void Update( float fDeltaTime );
|
||||||
virtual void DrawPrimitives();
|
virtual void DrawPrimitives();
|
||||||
|
|
||||||
|
struct TrackRowTapNote
|
||||||
|
{
|
||||||
|
int iTrack;
|
||||||
|
int iRow;
|
||||||
|
TapNote *pTN;
|
||||||
|
};
|
||||||
|
void UpdateHoldNotes( int iSongRow, float fDeltaTime, vector<TrackRowTapNote> &vTN );
|
||||||
|
|
||||||
void Init(
|
void Init(
|
||||||
const RString &sType,
|
const RString &sType,
|
||||||
PlayerState* pPlayerState,
|
PlayerState* pPlayerState,
|
||||||
|
|||||||
Reference in New Issue
Block a user