Files
itgmania212121/stepmania/src/Player.cpp
T

554 lines
16 KiB
C++
Raw Normal View History

2001-11-03 10:52:42 +00:00
#include "stdafx.h"
/*
-----------------------------------------------------------------------------
2002-05-19 01:59:48 +00:00
Class: Notes
2001-11-03 10:52:42 +00:00
Desc: See header.
2001-11-03 10:52:42 +00:00
2002-05-19 01:59:48 +00:00
Copyright (c) 2001-2002 by the person(s) listed below. All rights reserved.
-----------------------------------------------------------------------------
*/
2001-11-03 10:52:42 +00:00
2002-05-01 19:14:55 +00:00
#include "GameConstantsAndTypes.h"
#include "Math.h" // for fabs()
2001-11-03 10:52:42 +00:00
#include "Player.h"
#include "RageUtil.h"
2002-01-16 10:01:32 +00:00
#include "ThemeManager.h"
2002-05-01 19:14:55 +00:00
#include "GameConstantsAndTypes.h"
2002-02-24 10:31:20 +00:00
#include "ArrowEffects.h"
2002-04-16 17:31:00 +00:00
#include "GameManager.h"
#include "InputMapper.h"
2001-11-03 10:52:42 +00:00
2002-05-19 01:59:48 +00:00
// these two items are in the
const float FRAME_JUDGE_AND_COMBO_Y = CENTER_Y;
const float JUDGEMENT_Y_OFFSET = -26;
const float COMBO_Y_OFFSET = +26;
2002-02-24 01:43:11 +00:00
const float ARROWS_Y = SCREEN_TOP + ARROW_SIZE * 1.5f;
const float HOLD_JUDGEMENT_Y = ARROWS_Y + 80;
2001-11-03 10:52:42 +00:00
const float HOLD_ARROW_NG_TIME = 0.27f;
2002-02-24 01:43:11 +00:00
Player::Player()
2001-11-03 10:52:42 +00:00
{
2002-02-24 01:43:11 +00:00
m_fSongBeat = 0;
m_PlayerNumber = PLAYER_NONE;
2001-11-20 11:49:10 +00:00
2002-02-24 01:43:11 +00:00
// init step elements
2002-05-19 01:59:48 +00:00
for( int i=0; i<MAX_TAP_NOTE_ROWS; i++ )
2001-12-19 01:50:57 +00:00
{
2002-04-16 17:31:00 +00:00
for( int c=0; c<MAX_NOTE_TRACKS; c++ )
{
m_TapNotesOriginal[c][i] = '0';
m_TapNotes[c][i] = '0';
}
m_TapNoteScores[i] = TNS_NONE;
2001-12-19 01:50:57 +00:00
}
m_iNumHoldNotes = 0;
2001-11-26 05:41:43 +00:00
2002-04-28 20:42:32 +00:00
m_pLifeMeter = NULL;
m_pScore = NULL;
2002-04-16 17:31:00 +00:00
this->AddActor( &m_GrayArrowRow );
this->AddActor( &m_NoteField );
this->AddActor( &m_GhostArrowRow );
2002-05-19 01:59:48 +00:00
m_frameJudgeAndCombo.AddActor( &m_Judgement );
m_frameJudgeAndCombo.AddActor( &m_Combo );
this->AddActor( &m_frameJudgeAndCombo );
2002-04-16 17:31:00 +00:00
for( int c=0; c<MAX_NOTE_TRACKS; c++ )
2002-02-24 01:43:11 +00:00
this->AddActor( &m_HoldJudgement[c] );
2001-11-03 10:52:42 +00:00
}
2002-05-27 08:23:27 +00:00
void Player::Load( PlayerNumber player_no, StyleDef* pStyleDef, NoteData* pNoteData, const PlayerOptions& po, LifeMeterBar* pLM, ScoreDisplayRolling* pScore )
2002-02-02 05:11:12 +00:00
{
2002-05-01 19:14:55 +00:00
//LOG->WriteLine( "Player::Load()", );
2002-04-16 17:31:00 +00:00
this->CopyAll( pNoteData );
2002-02-02 05:11:12 +00:00
2002-02-24 01:43:11 +00:00
m_PlayerNumber = player_no;
2002-02-24 10:31:20 +00:00
m_PlayerOptions = po;
2002-02-02 05:11:12 +00:00
2002-04-28 20:42:32 +00:00
m_pLifeMeter = pLM;
m_pScore = pScore;
2002-05-27 08:23:27 +00:00
if( !po.m_bHoldNotes )
2002-04-16 17:31:00 +00:00
this->RemoveHoldNotes();
2002-04-16 17:31:00 +00:00
this->Turn( po.m_TurnType );
2001-12-20 12:37:38 +00:00
2002-02-24 01:43:11 +00:00
if( po.m_bLittle )
2002-04-16 17:31:00 +00:00
this->MakeLittle();
2001-11-30 19:08:44 +00:00
2002-05-27 08:23:27 +00:00
m_NoteField.Load( (NoteData*)this, player_no, pStyleDef, po, 1.5f, 5.5f, NoteField::MODE_DANCING );
2002-05-19 01:59:48 +00:00
for( int t=0; t<pNoteData->m_iNumTracks; t++ )
{
for( int r=0; r<MAX_TAP_NOTE_ROWS; r++ )
m_TapNotesOriginal[t][r] = pNoteData->m_TapNotes[t][r];
}
2001-11-30 19:08:44 +00:00
2002-05-27 08:23:27 +00:00
m_GrayArrowRow.Load( player_no, pStyleDef, po );
m_GhostArrowRow.Load( player_no, pStyleDef, po );
2001-12-20 12:37:38 +00:00
2002-05-19 01:59:48 +00:00
m_frameJudgeAndCombo.SetY( FRAME_JUDGE_AND_COMBO_Y );
m_Combo.SetY( po.m_bReverseScroll ? -COMBO_Y_OFFSET : COMBO_Y_OFFSET );
m_Judgement.SetY( po.m_bReverseScroll ? -JUDGEMENT_Y_OFFSET : JUDGEMENT_Y_OFFSET );
2001-12-20 12:37:38 +00:00
2002-04-16 17:31:00 +00:00
for( int c=0; c<MAX_NOTE_TRACKS; c++ )
2002-02-24 01:43:11 +00:00
m_HoldJudgement[c].SetY( po.m_bReverseScroll ? SCREEN_HEIGHT - HOLD_JUDGEMENT_Y : HOLD_JUDGEMENT_Y );
2001-12-28 10:15:59 +00:00
2002-04-16 17:31:00 +00:00
m_NoteField.SetY( po.m_bReverseScroll ? SCREEN_HEIGHT - ARROWS_Y : ARROWS_Y );
m_GrayArrowRow.SetY( po.m_bReverseScroll ? SCREEN_HEIGHT - ARROWS_Y : ARROWS_Y );
m_GhostArrowRow.SetY( po.m_bReverseScroll ? SCREEN_HEIGHT - ARROWS_Y : ARROWS_Y );
}
2001-11-03 10:52:42 +00:00
void Player::Update( float fDeltaTime, float fSongBeat, float fMaxBeatDifference )
{
2002-05-01 19:14:55 +00:00
//LOG->WriteLine( "Player::Update(%f, %f, %f)", fDeltaTime, fSongBeat, fMaxBeatDifference );
2001-11-28 20:26:45 +00:00
2002-02-24 01:43:11 +00:00
//
// Check for TapNote misses
2002-02-24 01:43:11 +00:00
//
2002-04-16 17:31:00 +00:00
int iNumMisses = UpdateTapNotesMissedOlderThan( m_fSongBeat-fMaxBeatDifference );
2001-11-03 10:52:42 +00:00
if( iNumMisses > 0 )
{
m_Judgement.SetJudgement( TNS_MISS );
2002-02-24 01:43:11 +00:00
m_Combo.EndCombo();
for( int i=0; i<iNumMisses; i++ )
2002-04-28 20:42:32 +00:00
m_pLifeMeter->ChangeLife( TNS_MISS );
2001-11-03 10:52:42 +00:00
}
2002-02-24 01:43:11 +00:00
//
// update HoldNotes logic
2002-02-24 01:43:11 +00:00
//
for( int i=0; i<m_iNumHoldNotes; i++ ) // for each HoldNote
2001-12-19 01:50:57 +00:00
{
HoldNote &hn = m_HoldNotes[i];
HoldNoteScore &hns = m_HoldNoteScores[i];
if( hns.m_Result != HNR_NONE ) // if this HoldNote already has a result
2002-02-24 01:43:11 +00:00
continue; // we don't need to update the logic for this one
2002-05-19 01:59:48 +00:00
float fStartBeat = NoteRowToBeat( (float)hn.m_iStartIndex );
float fEndBeat = NoteRowToBeat( (float)hn.m_iEndIndex );
2002-02-24 01:43:11 +00:00
2002-04-16 17:31:00 +00:00
const int iCol = hn.m_iTrack;
const StyleInput StyleI( m_PlayerNumber, hn.m_iTrack );
2002-05-27 08:23:27 +00:00
const GameInput GameI = GAMEMAN->GetCurrentStyleDef()->StyleInputToGameInput( StyleI );
2001-12-19 01:50:57 +00:00
2002-02-24 01:43:11 +00:00
// update the life
if( fStartBeat < m_fSongBeat && m_fSongBeat < fEndBeat ) // if the song beat is in the range of this hold
2001-12-19 01:50:57 +00:00
{
2002-05-19 01:59:48 +00:00
const bool bIsHoldingButton = INPUTMAPPER->IsButtonDown( GameI );
2002-04-16 17:31:00 +00:00
2002-02-24 01:43:11 +00:00
if( bIsHoldingButton )
2001-12-19 01:50:57 +00:00
{
hns.m_fLife += fDeltaTime/HOLD_ARROW_NG_TIME;
hns.m_fLife = min( hns.m_fLife, 1 ); // clamp
2002-04-16 17:31:00 +00:00
m_GhostArrowRow.HoldNote( iCol ); // update the "electric ghost" effect
2001-12-19 01:50:57 +00:00
}
2002-02-24 01:43:11 +00:00
else // !bIsHoldingButton
2001-12-19 01:50:57 +00:00
{
hns.m_fLife -= fDeltaTime/HOLD_ARROW_NG_TIME;
hns.m_fLife = max( hns.m_fLife, 0 ); // clamp
2001-12-19 01:50:57 +00:00
}
2002-04-16 17:31:00 +00:00
m_NoteField.SetHoldNoteLife( i, hns.m_fLife ); // update the NoteField display
2001-12-19 01:50:57 +00:00
}
2002-02-24 01:43:11 +00:00
// check for NG
if( hns.m_fLife == 0 ) // the player has not pressed the button for a long time!
2002-02-24 01:43:11 +00:00
{
hns.m_Result = HNR_NG;
m_HoldJudgement[iCol].SetHoldJudgement( HNR_NG );
2002-02-24 01:43:11 +00:00
}
2001-12-19 01:50:57 +00:00
2002-02-24 01:43:11 +00:00
// check for OK
if( m_fSongBeat > fEndBeat ) // if this HoldNote is in the past
2001-12-19 01:50:57 +00:00
{
// this implies that hns.m_fLife > 0, or else we would have marked it NG above
hns.m_fLife = 1;
hns.m_Result = HNR_OK;
m_HoldJudgement[iCol].SetHoldJudgement( HNR_OK );
2002-04-16 17:31:00 +00:00
m_NoteField.SetHoldNoteLife( i, hns.m_fLife ); // update the NoteField display
2001-12-19 01:50:57 +00:00
}
}
2002-02-24 01:43:11 +00:00
ActorFrame::Update( fDeltaTime );
2002-05-19 01:59:48 +00:00
m_frameJudgeAndCombo.Update( fDeltaTime );
2002-04-28 20:42:32 +00:00
m_pLifeMeter->SetBeat( fSongBeat );
2002-02-24 01:43:11 +00:00
2002-04-16 17:31:00 +00:00
m_GrayArrowRow.Update( fDeltaTime, fSongBeat );
m_NoteField.Update( fDeltaTime, fSongBeat );
m_GhostArrowRow.Update( fDeltaTime, fSongBeat );
2002-02-24 01:43:11 +00:00
m_fSongBeat = fSongBeat; // save song beat
2001-12-20 12:37:38 +00:00
2001-11-03 10:52:42 +00:00
}
2002-05-19 01:59:48 +00:00
void Player::DrawPrimitives()
2002-02-24 10:31:20 +00:00
{
D3DXMATRIX matOldView, matOldProj;
2002-02-28 19:40:40 +00:00
if( m_PlayerOptions.m_EffectType == PlayerOptions::EFFECT_SPACE )
2002-02-24 10:31:20 +00:00
{
// turn off Z Buffering
2002-05-19 01:59:48 +00:00
DISPLAY->GetDevice()->SetRenderState( D3DRS_ZENABLE, FALSE );
DISPLAY->GetDevice()->SetRenderState( D3DRS_ZWRITEENABLE, FALSE );
2002-02-24 10:31:20 +00:00
// save old view and projection
2002-05-19 01:59:48 +00:00
DISPLAY->GetDevice()->GetTransform( D3DTS_VIEW, &matOldView );
DISPLAY->GetDevice()->GetTransform( D3DTS_PROJECTION, &matOldProj );
2002-02-24 10:31:20 +00:00
// construct view and project matrix
D3DXMATRIX matNewView;
D3DXMatrixLookAtLH( &matNewView, &D3DXVECTOR3( CENTER_X, GetY()+800.0f, 300.0f ),
&D3DXVECTOR3( CENTER_X
, GetY()+400.0f, 0.0f ),
&D3DXVECTOR3( 0.0f, -1.0f, 0.0f ) );
2002-05-19 01:59:48 +00:00
DISPLAY->GetDevice()->SetTransform( D3DTS_VIEW, &matNewView );
2002-02-24 10:31:20 +00:00
D3DXMATRIX matNewProj;
D3DXMatrixPerspectiveFovLH( &matNewProj, D3DX_PI/4.0f, SCREEN_WIDTH/(float)SCREEN_HEIGHT, 0.0f, 1000.0f );
2002-05-19 01:59:48 +00:00
DISPLAY->GetDevice()->SetTransform( D3DTS_PROJECTION, &matNewProj );
2002-02-24 10:31:20 +00:00
}
2002-04-16 17:31:00 +00:00
m_GrayArrowRow.Draw();
m_NoteField.Draw();
m_GhostArrowRow.Draw();
2002-02-24 10:31:20 +00:00
2002-02-28 19:40:40 +00:00
if( m_PlayerOptions.m_EffectType == PlayerOptions::EFFECT_SPACE )
2002-02-24 10:31:20 +00:00
{
// restire old view and projection
2002-05-19 01:59:48 +00:00
DISPLAY->GetDevice()->SetTransform( D3DTS_VIEW, &matOldView );
DISPLAY->GetDevice()->SetTransform( D3DTS_PROJECTION, &matOldProj );
2002-02-24 10:31:20 +00:00
// turn Z Buffering back on
2002-05-19 01:59:48 +00:00
DISPLAY->GetDevice()->SetRenderState( D3DRS_ZENABLE, TRUE );
DISPLAY->GetDevice()->SetRenderState( D3DRS_ZWRITEENABLE, TRUE );
2002-02-24 10:31:20 +00:00
}
2002-05-19 01:59:48 +00:00
m_frameJudgeAndCombo.Draw();
2002-02-24 10:31:20 +00:00
2002-04-16 17:31:00 +00:00
for( int c=0; c<m_iNumTracks; c++ )
2002-02-24 10:31:20 +00:00
m_HoldJudgement[c].Draw();
2001-12-28 10:15:59 +00:00
}
2002-02-24 01:43:11 +00:00
bool Player::IsThereANoteAtIndex( int iIndex )
2001-11-03 10:52:42 +00:00
{
2002-04-16 17:31:00 +00:00
for( int t=0; t<m_iNumTracks; t++ )
{
if( m_TapNotesOriginal[t][iIndex] != '0' )
return true;
}
2002-03-10 10:30:45 +00:00
for( int i=0; i<m_iNumHoldNotes; i++ ) // for each HoldNote
2002-03-10 10:30:45 +00:00
{
if( m_HoldNotes[i].m_iStartIndex == iIndex )
2002-03-10 10:30:45 +00:00
return true;
}
return false;
}
2001-11-03 10:52:42 +00:00
2002-02-24 01:43:11 +00:00
2002-05-27 08:23:27 +00:00
void Player::HandlePlayerStep( float fSongBeat, int col, float fMaxBeatDiff )
{
2002-05-01 19:14:55 +00:00
//LOG->WriteLine( "Player::HandlePlayerStep()" );
2001-11-03 10:52:42 +00:00
2002-04-16 17:31:00 +00:00
ASSERT( col >= 0 && col <= m_iNumTracks );
2002-03-09 06:19:40 +00:00
2002-04-16 17:31:00 +00:00
m_GrayArrowRow.Step( col );
2001-11-03 10:52:42 +00:00
2002-04-16 17:31:00 +00:00
CheckForCompleteRow( fSongBeat, col, fMaxBeatDiff );
2001-12-19 01:50:57 +00:00
2002-02-24 01:43:11 +00:00
//
// check if we stepped on the TapNote part of a HoldNote
2002-02-24 01:43:11 +00:00
//
for( int i=0; i<m_iNumHoldNotes; i++ ) // for each HoldNote
2001-12-19 01:50:57 +00:00
{
HoldNote& hn = m_HoldNotes[i];
HoldNoteScore& hns = m_HoldNoteScores[i];
2002-02-24 01:43:11 +00:00
if( hns.m_Result != HNR_NONE ) // if this note already has a score
2002-02-24 01:43:11 +00:00
continue; // we don't need to update its logic
if( hns.m_TapNoteScore != TNS_NONE ) // the TapNote already has a score
2002-02-24 01:43:11 +00:00
continue; // no need to continue;
2002-04-16 17:31:00 +00:00
if( col == m_HoldNotes[i].m_iTrack ) // the player's step is the same as this HoldNote
2001-12-19 01:50:57 +00:00
{
2002-05-19 01:59:48 +00:00
float fBeatDifference = fabsf( NoteRowToBeat(hn.m_iStartIndex) - fSongBeat );
2001-12-19 01:50:57 +00:00
2002-02-24 01:43:11 +00:00
if( fBeatDifference <= fMaxBeatDiff )
2001-12-28 10:15:59 +00:00
{
2002-05-19 01:59:48 +00:00
float fBeatsUntilStep = NoteRowToBeat( (float)hn.m_iStartIndex ) - fSongBeat;
2002-02-24 01:43:11 +00:00
float fPercentFromPerfect = fabsf( fBeatsUntilStep / fMaxBeatDiff );
2001-12-28 10:15:59 +00:00
2002-05-01 19:14:55 +00:00
//LOG->WriteLine( "fBeatsUntilStep: %f, fPercentFromPerfect: %f",
2001-12-28 10:15:59 +00:00
// fBeatsUntilStep, fPercentFromPerfect );
// compute what the score should be for the note we stepped on
TapNoteScore &score = hns.m_TapNoteScore;
if( fPercentFromPerfect < 0.25f ) score = TNS_PERFECT;
else if( fPercentFromPerfect < 0.50f ) score = TNS_GREAT;
else if( fPercentFromPerfect < 0.75f ) score = TNS_GOOD;
else score = TNS_BOO;
2001-12-28 10:15:59 +00:00
// update the judgement, score, and life
2002-02-24 01:43:11 +00:00
m_Judgement.SetJudgement( score );
2002-04-28 20:42:32 +00:00
m_pScore->AddToScore( score, m_Combo.GetCurrentCombo() );
m_pLifeMeter->ChangeLife( score );
2001-12-28 10:15:59 +00:00
// show the gray arrow ghost
2002-04-16 17:31:00 +00:00
m_GhostArrowRow.TapNote( col, score, m_Combo.GetCurrentCombo() > 100 );
2001-12-28 10:15:59 +00:00
// update the combo display
2002-02-24 01:43:11 +00:00
switch( score )
2001-12-28 10:15:59 +00:00
{
case TNS_PERFECT:
case TNS_GREAT:
2002-02-24 01:43:11 +00:00
m_Combo.ContinueCombo();
2001-12-28 10:15:59 +00:00
break;
case TNS_GOOD:
case TNS_BOO:
2002-02-24 01:43:11 +00:00
m_Combo.EndCombo();
2001-12-28 10:15:59 +00:00
break;
}
2002-05-19 01:59:48 +00:00
// zoom the judgement and combo like a heart beat
float fStartZoom;
switch( score )
{
case TNS_PERFECT: fStartZoom = 1.5f; break;
case TNS_GREAT: fStartZoom = 1.3f; break;
case TNS_GOOD: fStartZoom = 1.2f; break;
case TNS_BOO: fStartZoom = 1.0f; break;
}
m_frameJudgeAndCombo.SetZoom( fStartZoom );
m_frameJudgeAndCombo.BeginTweening( 0.2f );
m_frameJudgeAndCombo.SetTweenZoom( 1 );
2001-12-28 10:15:59 +00:00
}
2001-12-19 01:50:57 +00:00
}
}
}
2001-11-03 10:52:42 +00:00
2002-05-27 08:23:27 +00:00
void Player::CheckForCompleteRow( float fSongBeat, int col, float fMaxBeatDiff )
2001-11-03 10:52:42 +00:00
{
2002-05-01 19:14:55 +00:00
//LOG->WriteLine( "Player::CheckForCompleteRow()" );
2001-11-03 10:52:42 +00:00
// look for the closest matching step
2002-05-19 01:59:48 +00:00
int iIndexStartLookingAt = BeatToNoteRow( fSongBeat );
int iNumElementsToExamine = BeatToNoteRow( fMaxBeatDiff ); // number of elements to examine on either end of iIndexStartLookingAt
2001-11-03 10:52:42 +00:00
2002-05-01 19:14:55 +00:00
//LOG->WriteLine( "iIndexStartLookingAt = %d, iNumElementsToExamine = %d", iIndexStartLookingAt, iNumElementsToExamine );
2001-11-03 10:52:42 +00:00
// Start at iIndexStartLookingAt and search outward. The first one that overlaps the player's step is the closest match.
for( int delta=0; delta <= iNumElementsToExamine; delta++ )
{
int iCurrentIndexEarlier = iIndexStartLookingAt - delta;
int iCurrentIndexLater = iIndexStartLookingAt + delta;
// silly check to make sure we don't go out of bounds
2002-05-19 01:59:48 +00:00
iCurrentIndexEarlier = clamp( iCurrentIndexEarlier, 0, MAX_TAP_NOTE_ROWS-1 );
iCurrentIndexLater = clamp( iCurrentIndexLater, 0, MAX_TAP_NOTE_ROWS-1 );
////////////////////////////
// check the step to the left of iIndexStartLookingAt
////////////////////////////
2002-05-19 01:59:48 +00:00
//LOG->WriteLine( "Checking Notes[%d]", iCurrentIndexEarlier );
if( m_TapNotes[col][iCurrentIndexEarlier] != '0' ) // these Notes overlap
{
2002-04-16 17:31:00 +00:00
m_TapNotes[col][iCurrentIndexEarlier] = '0'; // mark hit
bool bRowDestroyed = true;
for( int t=0; t<m_iNumTracks; t++ ) // did this complete the elminiation of the row?
{
if( m_TapNotes[col][iCurrentIndexEarlier] != '0' )
bRowDestroyed = false;
}
2002-04-16 17:31:00 +00:00
if( bRowDestroyed )
OnRowDestroyed( fSongBeat, col, fMaxBeatDiff, iCurrentIndexEarlier );
return;
}
2001-11-03 10:52:42 +00:00
////////////////////////////
// check the step to the right of iIndexStartLookingAt
////////////////////////////
2002-05-19 01:59:48 +00:00
//LOG->WriteLine( "Checking Notes[%d]", iCurrentIndexLater );
if( m_TapNotes[col][iCurrentIndexLater] != '0' ) // these Notes overlap
{
2002-04-16 17:31:00 +00:00
m_TapNotes[col][iCurrentIndexLater] = '0'; // mark hit
bool bRowDestroyed = true;
for( int t=0; t<m_iNumTracks; t++ ) // did this complete the elminiation of the row?
{
if( m_TapNotes[col][iCurrentIndexLater] != '0' )
bRowDestroyed = false;
}
2002-04-16 17:31:00 +00:00
if( bRowDestroyed )
OnRowDestroyed( fSongBeat, col, fMaxBeatDiff, iCurrentIndexLater );
return;
}
}
}
2001-11-03 10:52:42 +00:00
2002-05-27 08:23:27 +00:00
void Player::OnRowDestroyed( float fSongBeat, int col, float fMaxBeatDiff, int iIndexThatWasSteppedOn )
{
2002-05-19 01:59:48 +00:00
float fStepBeat = NoteRowToBeat( (float)iIndexThatWasSteppedOn );
2001-11-30 09:38:35 +00:00
float fBeatsUntilStep = fStepBeat - fSongBeat;
2002-02-24 01:43:11 +00:00
float fPercentFromPerfect = fabsf( fBeatsUntilStep / fMaxBeatDiff );
2001-11-03 10:52:42 +00:00
2002-05-01 19:14:55 +00:00
//LOG->WriteLine( "fBeatsUntilStep: %f, fPercentFromPerfect: %f",
// fBeatsUntilStep, fPercentFromPerfect );
2001-11-03 10:52:42 +00:00
// compute what the score should be for the note we stepped on
TapNoteScore &score = m_TapNoteScores[iIndexThatWasSteppedOn];
2001-11-03 10:52:42 +00:00
if( fPercentFromPerfect < 0.25f ) score = TNS_PERFECT;
else if( fPercentFromPerfect < 0.50f ) score = TNS_GREAT;
else if( fPercentFromPerfect < 0.75f ) score = TNS_GOOD;
else score = TNS_BOO;
// update the judgement, score, and life
2002-02-24 01:43:11 +00:00
m_Judgement.SetJudgement( score );
2002-04-28 20:42:32 +00:00
m_pScore->AddToScore( score, m_Combo.GetCurrentCombo() );
m_pLifeMeter->ChangeLife( score );
2002-02-24 01:43:11 +00:00
2002-04-16 17:31:00 +00:00
// remove this row from the NoteField
2002-04-28 20:42:32 +00:00
if ( ( score == TNS_PERFECT ) || ( score == TNS_GREAT ) )
m_NoteField.RemoveTapNoteRow( iIndexThatWasSteppedOn );
2002-02-24 01:43:11 +00:00
2002-04-16 17:31:00 +00:00
// show ghost arrows
for( int c=0; c<m_iNumTracks; c++ ) // for each column
2002-02-24 01:43:11 +00:00
{
2002-04-16 17:31:00 +00:00
if( m_TapNotesOriginal[c][iIndexThatWasSteppedOn] != '0' ) // if there is an original note note in this column
m_GhostArrowRow.TapNote( c, score, m_Combo.GetCurrentCombo()>100 ); // show the ghost arrow for this column
2001-12-01 23:46:09 +00:00
}
2001-11-03 10:52:42 +00:00
// update the combo display
2002-02-24 01:43:11 +00:00
switch( score )
2001-11-03 10:52:42 +00:00
{
case TNS_PERFECT:
case TNS_GREAT:
2002-02-24 01:43:11 +00:00
m_Combo.ContinueCombo();
2001-11-03 10:52:42 +00:00
break;
case TNS_GOOD:
case TNS_BOO:
2002-02-24 01:43:11 +00:00
m_Combo.EndCombo();
2001-11-03 10:52:42 +00:00
break;
}
2002-05-19 01:59:48 +00:00
// zoom the judgement and combo like a heart beat
float fStartZoom;
switch( score )
{
case TNS_PERFECT: fStartZoom = 1.5f; break;
case TNS_GREAT: fStartZoom = 1.3f; break;
case TNS_GOOD: fStartZoom = 1.2f; break;
case TNS_BOO: fStartZoom = 1.0f; break;
}
m_frameJudgeAndCombo.SetZoom( fStartZoom );
m_frameJudgeAndCombo.BeginTweening( 0.2f );
m_frameJudgeAndCombo.SetTweenZoom( 1 );
2001-11-03 10:52:42 +00:00
}
2001-11-03 10:52:42 +00:00
ScoreSummary Player::GetScoreSummary()
{
ScoreSummary scoreSummary;
2002-05-19 01:59:48 +00:00
for( int i=0; i<MAX_TAP_NOTE_ROWS; i++ )
2001-11-03 10:52:42 +00:00
{
switch( m_TapNoteScores[i] )
2001-11-03 10:52:42 +00:00
{
case TNS_PERFECT: scoreSummary.perfect++; break;
case TNS_GREAT: scoreSummary.great++; break;
case TNS_GOOD: scoreSummary.good++; break;
case TNS_BOO: scoreSummary.boo++; break;
case TNS_MISS: scoreSummary.miss++; break;
case TNS_NONE: break;
2002-02-24 01:43:11 +00:00
default: ASSERT( false );
2001-11-03 10:52:42 +00:00
}
}
for( i=0; i<m_iNumHoldNotes; i++ )
2001-12-28 10:15:59 +00:00
{
switch( m_HoldNoteScores[i].m_TapNoteScore )
2001-12-28 10:15:59 +00:00
{
case TNS_PERFECT: scoreSummary.perfect++; break;
case TNS_GREAT: scoreSummary.great++; break;
case TNS_GOOD: scoreSummary.good++; break;
case TNS_BOO: scoreSummary.boo++; break;
case TNS_MISS: scoreSummary.miss++; break;
case TNS_NONE: break;
2002-02-24 01:43:11 +00:00
default: ASSERT( false );
2001-12-28 10:15:59 +00:00
}
switch( m_HoldNoteScores[i].m_Result )
2001-12-28 10:15:59 +00:00
{
case HNR_NG: scoreSummary.ng++; break;
case HNR_OK: scoreSummary.ok++; break;
case HNR_NONE: break;
2002-02-24 01:43:11 +00:00
default: ASSERT( false );
2001-12-28 10:15:59 +00:00
}
}
2002-02-24 01:43:11 +00:00
scoreSummary.max_combo = m_Combo.GetMaxCombo();
2002-04-28 20:42:32 +00:00
scoreSummary.score = m_pScore ? m_pScore->GetScore() : 0;
2001-11-03 10:52:42 +00:00
return scoreSummary;
}
2002-04-16 17:31:00 +00:00
int Player::UpdateTapNotesMissedOlderThan( float fMissIfOlderThanThisBeat )
{
2002-05-19 01:59:48 +00:00
//LOG->WriteLine( "Notes::UpdateTapNotesMissedOlderThan(%f)", fMissIfOlderThanThisBeat );
2001-11-20 11:49:10 +00:00
2002-05-19 01:59:48 +00:00
int iMissIfOlderThanThisIndex = BeatToNoteRow( fMissIfOlderThanThisBeat );
2001-11-20 11:49:10 +00:00
2002-02-24 01:43:11 +00:00
int iNumMissesFound = 0;
2002-04-16 17:31:00 +00:00
// Since this is being called every frame, let's not check the whole array every time.
2002-02-24 01:43:11 +00:00
// Instead, only check 10 elements back. Even 10 is overkill.
int iStartCheckingAt = max( 0, iMissIfOlderThanThisIndex-10 );
2001-12-19 01:50:57 +00:00
2002-05-01 19:14:55 +00:00
//LOG->WriteLine( "iStartCheckingAt: %d iMissIfOlderThanThisIndex: %d", iStartCheckingAt, iMissIfOlderThanThisIndex );
2002-02-24 01:43:11 +00:00
for( int i=iStartCheckingAt; i<iMissIfOlderThanThisIndex; i++ )
2001-12-19 01:50:57 +00:00
{
2002-04-16 17:31:00 +00:00
if( m_TapNoteScores[i] != TNS_NONE ) // this index already has a score
continue;
// look for any track at this index that still has data
if( !this->IsRowEmpty( i ) )
{
m_TapNoteScores[i] = TNS_MISS;
2002-02-24 01:43:11 +00:00
iNumMissesFound++;
2002-04-28 20:42:32 +00:00
m_pLifeMeter->ChangeLife( TNS_MISS );
}
2001-12-19 01:50:57 +00:00
}
2002-02-24 01:43:11 +00:00
return iNumMissesFound;
}