expand Boo window in MercifulBeginner. If step is early and stepped in Boo window, show judgment but don't grade.
This commit is contained in:
+94
-52
@@ -45,11 +45,44 @@ CString ATTACK_DISPLAY_X_NAME( size_t p, size_t both_sides ){ return "AttackDisp
|
|||||||
/* Distance to search for a note in Step(), in seconds. */
|
/* Distance to search for a note in Step(), in seconds. */
|
||||||
static const float StepSearchDistance = 1.0f;
|
static const float StepSearchDistance = 1.0f;
|
||||||
|
|
||||||
#define ADJUSTED_WINDOW_HOLD( judge ) ( \
|
enum HoldWindow { HW_OK, HW_Roll };
|
||||||
(PREFSMAN->m_fJudgeWindowSeconds##judge * PREFSMAN->m_fJudgeWindowScale) + \
|
enum TapWindow { TW_Marvelous, TW_Perfect, TW_Great, TW_Good, TW_Boo, TW_Mine, TW_Attack };
|
||||||
PREFSMAN->m_fJudgeWindowAdd )
|
|
||||||
|
float ADJUSTED_WINDOW_HOLD( HoldWindow hw )
|
||||||
|
{
|
||||||
|
float fSecs = 0;
|
||||||
|
switch( hw )
|
||||||
|
{
|
||||||
|
case HW_OK: fSecs = PREFSMAN->m_fJudgeWindowSecondsOK; break;
|
||||||
|
case HW_Roll: fSecs = PREFSMAN->m_fJudgeWindowSecondsRoll; break;
|
||||||
|
default: ASSERT(0);
|
||||||
|
}
|
||||||
|
fSecs *= PREFSMAN->m_fJudgeWindowScale;
|
||||||
|
fSecs += PREFSMAN->m_fJudgeWindowAdd;
|
||||||
|
return fSecs;
|
||||||
|
}
|
||||||
|
|
||||||
|
float ADJUSTED_WINDOW_TAP( TapWindow tw )
|
||||||
|
{
|
||||||
|
float fSecs = 0;
|
||||||
|
switch( tw )
|
||||||
|
{
|
||||||
|
case TW_Marvelous: fSecs = PREFSMAN->m_fJudgeWindowSecondsMarvelous; break;
|
||||||
|
case TW_Perfect: fSecs = PREFSMAN->m_fJudgeWindowSecondsPerfect; break;
|
||||||
|
case TW_Great: fSecs = PREFSMAN->m_fJudgeWindowSecondsGreat; break;
|
||||||
|
case TW_Good: fSecs = PREFSMAN->m_fJudgeWindowSecondsGood; break;
|
||||||
|
case TW_Boo: fSecs = PREFSMAN->m_fJudgeWindowSecondsBoo; break;
|
||||||
|
case TW_Mine: fSecs = PREFSMAN->m_fJudgeWindowSecondsMine; break;
|
||||||
|
case TW_Attack: fSecs = PREFSMAN->m_fJudgeWindowSecondsAttack; break;
|
||||||
|
default: ASSERT(0);
|
||||||
|
}
|
||||||
|
fSecs *= PREFSMAN->m_fJudgeWindowScale;
|
||||||
|
fSecs += PREFSMAN->m_fJudgeWindowAdd;
|
||||||
|
if( PREFSMAN->m_bMercifulBeginner && tw==TW_Boo )
|
||||||
|
fSecs += 0.5f;
|
||||||
|
return fSecs;
|
||||||
|
}
|
||||||
|
|
||||||
#define ADJUSTED_WINDOW_TAP( judge, tns ) (ADJUSTED_WINDOW_HOLD(judge))
|
|
||||||
|
|
||||||
Player::Player()
|
Player::Player()
|
||||||
{
|
{
|
||||||
@@ -468,7 +501,7 @@ void Player::Update( float fDeltaTime )
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Decrease life
|
// Decrease life
|
||||||
fLife -= fDeltaTime/ADJUSTED_WINDOW_HOLD(OK);
|
fLife -= fDeltaTime/ADJUSTED_WINDOW_HOLD(HW_OK);
|
||||||
fLife = max( fLife, 0 ); // clamp
|
fLife = max( fLife, 0 ); // clamp
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -479,7 +512,7 @@ void Player::Update( float fDeltaTime )
|
|||||||
// give positive life in Step(), not here.
|
// give positive life in Step(), not here.
|
||||||
|
|
||||||
// Decrease life
|
// Decrease life
|
||||||
fLife -= fDeltaTime/ADJUSTED_WINDOW_HOLD(Roll);
|
fLife -= fDeltaTime/ADJUSTED_WINDOW_HOLD(HW_Roll);
|
||||||
fLife = max( fLife, 0 ); // clamp
|
fLife = max( fLife, 0 ); // clamp
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -856,20 +889,20 @@ void Player::HandleStep( int col, const RageTimer &tm, bool bHeld )
|
|||||||
{
|
{
|
||||||
case TapNote::mine:
|
case TapNote::mine:
|
||||||
// stepped too close to mine?
|
// stepped too close to mine?
|
||||||
if( fSecondsFromPerfect <= ADJUSTED_WINDOW_TAP(Mine,TNS_HIT_MINE) )
|
if( fSecondsFromPerfect <= ADJUSTED_WINDOW_TAP(TW_Mine) )
|
||||||
score = TNS_HIT_MINE;
|
score = TNS_HIT_MINE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TapNote::attack:
|
case TapNote::attack:
|
||||||
if( fSecondsFromPerfect <= ADJUSTED_WINDOW_TAP(Attack,TNS_NONE) && !tn.result.bHidden )
|
if( fSecondsFromPerfect <= ADJUSTED_WINDOW_TAP(TW_Attack) && !tn.result.bHidden )
|
||||||
score = TNS_PERFECT; /* sentinel */
|
score = TNS_PERFECT; /* sentinel */
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if( fSecondsFromPerfect <= ADJUSTED_WINDOW_TAP(Marvelous, TNS_MARVELOUS) ) score = TNS_MARVELOUS;
|
if( fSecondsFromPerfect <= ADJUSTED_WINDOW_TAP(TW_Marvelous) ) score = TNS_MARVELOUS;
|
||||||
else if( fSecondsFromPerfect <= ADJUSTED_WINDOW_TAP(Perfect, TNS_PERFECT) ) score = TNS_PERFECT;
|
else if( fSecondsFromPerfect <= ADJUSTED_WINDOW_TAP(TW_Perfect) ) score = TNS_PERFECT;
|
||||||
else if( fSecondsFromPerfect <= ADJUSTED_WINDOW_TAP(Great, TNS_GREAT) ) score = TNS_GREAT;
|
else if( fSecondsFromPerfect <= ADJUSTED_WINDOW_TAP(TW_Great) ) score = TNS_GREAT;
|
||||||
else if( fSecondsFromPerfect <= ADJUSTED_WINDOW_TAP(Good, TNS_GOOD) ) score = TNS_GOOD;
|
else if( fSecondsFromPerfect <= ADJUSTED_WINDOW_TAP(TW_Good) ) score = TNS_GOOD;
|
||||||
else if( fSecondsFromPerfect <= ADJUSTED_WINDOW_TAP(Boo, TNS_BOO) ) score = TNS_BOO;
|
else if( fSecondsFromPerfect <= ADJUSTED_WINDOW_TAP(TW_Boo) ) score = TNS_BOO;
|
||||||
else score = TNS_NONE;
|
else score = TNS_NONE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -990,48 +1023,57 @@ void Player::HandleStep( int col, const RageTimer &tm, bool bHeld )
|
|||||||
if( score == TNS_MARVELOUS && !GAMESTATE->ShowMarvelous() )
|
if( score == TNS_MARVELOUS && !GAMESTATE->ShowMarvelous() )
|
||||||
score = TNS_PERFECT;
|
score = TNS_PERFECT;
|
||||||
|
|
||||||
if( score != TNS_NONE && score != TNS_MISS )
|
bool bSteppedEarly = -fNoteOffset < 0;
|
||||||
|
bool bScoreThis = true;
|
||||||
|
if( PREFSMAN->m_bMercifulBeginner && score==TNS_BOO && bSteppedEarly )
|
||||||
{
|
{
|
||||||
int ms_error = (int) roundf( fSecondsFromPerfect * 1000 );
|
m_Judgment.SetJudgment( score, bSteppedEarly );
|
||||||
ms_error = min( ms_error, MAX_PRO_TIMING_ERROR.GetValue() );
|
|
||||||
|
|
||||||
if( m_pPlayerStageStats )
|
|
||||||
m_pPlayerStageStats->iTotalError += ms_error;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
//LOG->Trace("XXX: %i col %i, at %f, music at %f, step was at %f, off by %f",
|
|
||||||
// score, col, fStepSeconds, fCurrentMusicSeconds, fMusicSeconds, fNoteOffset );
|
|
||||||
// LOG->Trace("Note offset: %f (fSecondsFromPerfect = %f), Score: %i", fNoteOffset, fSecondsFromPerfect, score);
|
|
||||||
|
|
||||||
tn.result.tns = score;
|
|
||||||
|
|
||||||
if( score != TNS_NONE )
|
|
||||||
tn.result.fTapNoteOffset = -fNoteOffset;
|
|
||||||
|
|
||||||
m_NoteData.SetTapNote( col, iIndexOverlappingNote, tn );
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: Remove use of PlayerNumber.
|
|
||||||
PlayerNumber pn = m_pPlayerState->m_PlayerNumber;
|
|
||||||
|
|
||||||
// Keep this here so we get the same data as Autosync
|
|
||||||
NSMAN->ReportTiming( fNoteOffset,pn );
|
|
||||||
|
|
||||||
if( m_pPrimaryScoreKeeper )
|
|
||||||
m_pPrimaryScoreKeeper->HandleTapScore( score );
|
|
||||||
if( m_pSecondaryScoreKeeper )
|
|
||||||
m_pSecondaryScoreKeeper->HandleTapScore( score );
|
|
||||||
|
|
||||||
switch( tn.type )
|
|
||||||
{
|
{
|
||||||
case TapNote::tap:
|
tn.result.tns = score;
|
||||||
case TapNote::hold_head:
|
|
||||||
// don't judge the row if this note is a mine or tap attack
|
|
||||||
if( NoteDataWithScoring::IsRowCompletelyJudged( m_NoteData, iIndexOverlappingNote ) )
|
|
||||||
OnRowCompletelyJudged( iIndexOverlappingNote );
|
|
||||||
}
|
|
||||||
|
|
||||||
m_LastTapNoteScore = score;
|
if( score != TNS_NONE )
|
||||||
|
tn.result.fTapNoteOffset = -fNoteOffset;
|
||||||
|
|
||||||
|
if( score != TNS_NONE && score != TNS_MISS )
|
||||||
|
{
|
||||||
|
int ms_error = (int) roundf( fSecondsFromPerfect * 1000 );
|
||||||
|
ms_error = min( ms_error, MAX_PRO_TIMING_ERROR.GetValue() );
|
||||||
|
|
||||||
|
if( m_pPlayerStageStats )
|
||||||
|
m_pPlayerStageStats->iTotalError += ms_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
//LOG->Trace("XXX: %i col %i, at %f, music at %f, step was at %f, off by %f",
|
||||||
|
// score, col, fStepSeconds, fCurrentMusicSeconds, fMusicSeconds, fNoteOffset );
|
||||||
|
// LOG->Trace("Note offset: %f (fSecondsFromPerfect = %f), Score: %i", fNoteOffset, fSecondsFromPerfect, score);
|
||||||
|
|
||||||
|
m_NoteData.SetTapNote( col, iIndexOverlappingNote, tn );
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: Remove use of PlayerNumber.
|
||||||
|
PlayerNumber pn = m_pPlayerState->m_PlayerNumber;
|
||||||
|
|
||||||
|
// Keep this here so we get the same data as Autosync
|
||||||
|
NSMAN->ReportTiming( fNoteOffset,pn );
|
||||||
|
|
||||||
|
if( m_pPrimaryScoreKeeper )
|
||||||
|
m_pPrimaryScoreKeeper->HandleTapScore( score );
|
||||||
|
if( m_pSecondaryScoreKeeper )
|
||||||
|
m_pSecondaryScoreKeeper->HandleTapScore( score );
|
||||||
|
|
||||||
|
switch( tn.type )
|
||||||
|
{
|
||||||
|
case TapNote::tap:
|
||||||
|
case TapNote::hold_head:
|
||||||
|
// don't judge the row if this note is a mine or tap attack
|
||||||
|
if( NoteDataWithScoring::IsRowCompletelyJudged( m_NoteData, iIndexOverlappingNote ) )
|
||||||
|
OnRowCompletelyJudged( iIndexOverlappingNote );
|
||||||
|
}
|
||||||
|
|
||||||
|
m_LastTapNoteScore = score;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( m_pNoteField )
|
if( m_pNoteField )
|
||||||
@@ -1622,7 +1664,7 @@ void Player::HandleHoldScore( HoldNoteScore holdScore, TapNoteScore tapScore )
|
|||||||
|
|
||||||
float Player::GetMaxStepDistanceSeconds()
|
float Player::GetMaxStepDistanceSeconds()
|
||||||
{
|
{
|
||||||
return GAMESTATE->m_SongOptions.m_fMusicRate * ADJUSTED_WINDOW_TAP(Boo,TNS_BOO);
|
return GAMESTATE->m_SongOptions.m_fMusicRate * ADJUSTED_WINDOW_TAP(TW_Boo);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::FadeToFail()
|
void Player::FadeToFail()
|
||||||
|
|||||||
Reference in New Issue
Block a user