Files
itgmania212121/stepmania/src/Player.cpp
T

528 lines
16 KiB
C++
Raw Normal View History

2001-11-03 10:52:42 +00:00
#include "stdafx.h"
/*
-----------------------------------------------------------------------------
2002-06-24 22:04:31 +00:00
Class: Player
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.
2002-06-24 22:04:31 +00:00
Chris Danford
-----------------------------------------------------------------------------
*/
2002-05-01 19:14:55 +00:00
#include "GameConstantsAndTypes.h"
2001-11-03 10:52:42 +00:00
#include "Math.h" // for fabs()
#include "Player.h"
#include "RageUtil.h"
2002-07-23 01:41:40 +00:00
#include "PrefsManager.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"
2002-06-14 22:25:22 +00:00
#include "SongManager.h"
2002-07-23 01:41:40 +00:00
#include "GameState.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;
2002-06-24 22:04:31 +00:00
const float HOLD_ARROW_NG_TIME = 0.18f;
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;
2002-06-24 22:04:31 +00:00
m_PlayerNumber = PLAYER_INVALID;
2001-11-03 10:52:42 +00:00
2002-04-28 20:42:32 +00:00
m_pLifeMeter = NULL;
m_pScore = NULL;
2002-07-23 01:41:40 +00:00
this->AddSubActor( &m_GrayArrowRow );
this->AddSubActor( &m_NoteField );
this->AddSubActor( &m_GhostArrowRow );
2002-05-19 01:59:48 +00:00
2002-07-23 01:41:40 +00:00
m_frameJudgement.AddSubActor( &m_Judgement );
this->AddSubActor( &m_frameJudgement );
m_frameCombo.AddSubActor( &m_Combo );
this->AddSubActor( &m_frameCombo );
2002-05-19 01:59:48 +00:00
2002-04-16 17:31:00 +00:00
for( int c=0; c<MAX_NOTE_TRACKS; c++ )
2002-07-23 01:41:40 +00:00
this->AddSubActor( &m_HoldJudgement[c] );
2001-11-03 10:52:42 +00:00
}
2002-07-23 01:41:40 +00:00
void Player::Load( PlayerNumber player_no, StyleDef* pStyleDef, NoteData* pNoteData, const PlayerOptions& po, LifeMeter* pLM, ScoreDisplay* pScore, int iOriginalNumNotes, int iNotesMeter )
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-07-02 00:27:58 +00:00
NoteDataWithScoring::Init();
2002-07-03 21:27:26 +00:00
for( int i=0; i<MAX_TAP_NOTE_ROWS; i++ )
m_fHoldNoteLife[i] = 1.0f;
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-06-14 22:25:22 +00:00
if( m_pScore )
2002-07-04 21:05:18 +00:00
m_pScore->Init( player_no, m_PlayerOptions, iOriginalNumNotes, iNotesMeter );
2002-04-28 20:42:32 +00:00
2002-05-27 08:23:27 +00:00
if( !po.m_bHoldNotes )
2002-04-16 17:31:00 +00:00
this->RemoveHoldNotes();
2001-12-20 12:37:38 +00:00
2002-04-16 17:31:00 +00:00
this->Turn( po.m_TurnType );
2002-02-24 01:43:11 +00:00
if( po.m_bLittle )
2002-04-16 17:31:00 +00:00
this->MakeLittle();
2002-07-27 19:29:51 +00:00
int iPixelsToDrawBefore = 64;
int iPixelsToDrawAfter = 320;
switch( po.m_EffectType )
{
case PlayerOptions::EFFECT_MINI: iPixelsToDrawBefore *= 2; iPixelsToDrawAfter *= 2; break;
case PlayerOptions::EFFECT_SPACE: iPixelsToDrawBefore *= 2; iPixelsToDrawAfter *= 2; break;
}
m_NoteField.Load( (NoteData*)this, player_no, pStyleDef, po, iPixelsToDrawBefore, iPixelsToDrawAfter, NoteField::MODE_DANCING );
2002-05-19 01:59:48 +00:00
2002-05-27 08:23:27 +00:00
m_GrayArrowRow.Load( player_no, pStyleDef, po );
m_GhostArrowRow.Load( player_no, pStyleDef, po );
2002-02-24 01:43:11 +00:00
2002-07-23 01:41:40 +00:00
m_frameJudgement.SetY( FRAME_JUDGE_AND_COMBO_Y );
m_frameCombo.SetY( FRAME_JUDGE_AND_COMBO_Y );
2002-05-19 01:59:48 +00:00
m_Combo.SetY( po.m_bReverseScroll ? -COMBO_Y_OFFSET : COMBO_Y_OFFSET );
m_Judgement.SetY( po.m_bReverseScroll ? -JUDGEMENT_Y_OFFSET : JUDGEMENT_Y_OFFSET );
2002-02-24 01:43:11 +00:00
2002-06-24 22:04:31 +00:00
for( int c=0; c<pStyleDef->m_iColsPerPlayer; c++ )
2002-02-24 01:43:11 +00:00
m_HoldJudgement[c].SetY( po.m_bReverseScroll ? SCREEN_HEIGHT - HOLD_JUDGEMENT_Y : HOLD_JUDGEMENT_Y );
2002-06-24 22:04:31 +00:00
for( c=0; c<pStyleDef->m_iColsPerPlayer; c++ )
m_HoldJudgement[c].SetX( (float)pStyleDef->m_ColumnInfo[player_no][c].fXOffset );
2002-02-24 01:43:11 +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 );
2002-07-27 19:29:51 +00:00
if( po.m_EffectType == PlayerOptions::EFFECT_MINI )
{
m_NoteField.SetZoom( 0.5f );
m_GrayArrowRow.SetZoom( 0.5f );
m_GhostArrowRow.SetZoom( 0.5f );
}
}
void Player::Update( float fDeltaTime, float fSongBeat, float fMaxBeatDifference )
2001-11-03 10:52:42 +00:00
{
2002-05-01 19:14:55 +00:00
//LOG->WriteLine( "Player::Update(%f, %f, %f)", fDeltaTime, fSongBeat, fMaxBeatDifference );
2001-11-03 10:52:42 +00:00
2002-07-23 01:41:40 +00:00
m_fSongBeat = fSongBeat; // save song beat
2002-06-23 11:43:53 +00:00
2002-02-24 01:43:11 +00:00
//
// Check for TapNote misses
2002-02-24 01:43:11 +00:00
//
2002-05-29 09:47:24 +00:00
UpdateTapNotesMissedOlderThan( m_fSongBeat-fMaxBeatDifference );
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];
2002-06-14 22:25:22 +00:00
float &fLife = m_fHoldNoteLife[i];
2002-06-14 22:25:22 +00:00
if( hns != HNS_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
2001-12-19 01:50:57 +00:00
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 StyleInput StyleI( m_PlayerNumber, hn.m_iTrack );
2002-07-23 01:41:40 +00:00
const GameInput GameI = GAMESTATE->GetCurrentStyleDef()->StyleInputToGameInput( StyleI );
2002-02-24 01:43:11 +00:00
2002-06-14 22:25:22 +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-06-24 22:04:31 +00:00
const bool bIsHoldingButton = INPUTMAPPER->IsButtonDown( GameI ) || PREFSMAN->m_bAutoPlay;
2002-06-14 22:25:22 +00:00
// if they got a bad score or haven't stepped on the corresponding tap yet
2002-06-24 22:04:31 +00:00
const bool bSteppedOnTapNote = m_TapNoteScores[hn.m_iTrack][hn.m_iStartIndex] >= TNS_GREAT;
2002-04-16 17:31:00 +00:00
2002-06-14 22:25:22 +00:00
if( bIsHoldingButton && bSteppedOnTapNote )
2001-12-19 01:50:57 +00:00
{
2002-06-14 22:25:22 +00:00
// Increase life
fLife += fDeltaTime/HOLD_ARROW_NG_TIME;
fLife = min( fLife, 1 ); // clamp
2002-06-23 11:43:53 +00:00
m_NoteField.m_HoldNotes[i].m_iStartIndex = BeatToNoteRow( m_fSongBeat ); // move the start of this Hold
2002-06-14 22:25:22 +00:00
2002-06-24 22:04:31 +00:00
m_GhostArrowRow.HoldNote( hn.m_iTrack ); // update the "electric ghost" effect
2001-12-19 01:50:57 +00:00
}
2002-02-24 01:43:11 +00:00
else // !bIsHoldingButton
{
2002-06-14 22:25:22 +00:00
if( m_fSongBeat-fStartBeat > fMaxBeatDifference )
{
// Decrease life
fLife -= fDeltaTime/HOLD_ARROW_NG_TIME;
fLife = max( fLife, 0 ); // clamp
}
2002-02-24 01:43:11 +00:00
}
2002-06-14 22:25:22 +00:00
m_NoteField.SetHoldNoteLife( i, fLife ); // update the NoteField display
2001-12-20 21:08:45 +00:00
}
2002-02-24 01:43:11 +00:00
// check for NG
2002-06-14 22:25:22 +00:00
if( fLife == 0 ) // the player has not pressed the button for a long time!
2001-12-20 21:08:45 +00:00
{
2002-06-14 22:25:22 +00:00
hns = HNS_NG;
2002-07-23 01:41:40 +00:00
GAMESTATE->GetLatestGameplayStatistics().iActualDancePoints[m_PlayerNumber] += HoldNoteScoreToDancePoints( hns );
2002-06-24 22:04:31 +00:00
m_Combo.EndCombo();
m_HoldJudgement[hn.m_iTrack].SetHoldJudgement( HNS_NG );
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
{
2002-06-14 22:25:22 +00:00
// At this point fLife > 0, or else we would have marked it NG above
fLife = 1;
hns = HNS_OK;
2002-07-23 01:41:40 +00:00
GAMESTATE->GetLatestGameplayStatistics().iActualDancePoints[m_PlayerNumber] += HoldNoteScoreToDancePoints( hns );
2002-06-24 22:04:31 +00:00
m_HoldJudgement[hn.m_iTrack].SetHoldJudgement( HNS_OK );
2002-06-14 22:25:22 +00:00
m_NoteField.SetHoldNoteLife( i, 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-07-23 01:41:40 +00:00
m_frameJudgement.Update( fDeltaTime );
m_frameCombo.Update( fDeltaTime );
2002-05-19 01:59:48 +00:00
2002-07-02 00:27:58 +00:00
if( m_pLifeMeter )
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 );
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
{
// 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;
2002-07-27 19:29:51 +00:00
if( m_PlayerOptions.m_bReverseScroll )
D3DXMatrixLookAtLH(
&matNewView,
&D3DXVECTOR3( CENTER_X, GetY()-300.0f, 400.0f ),
&D3DXVECTOR3( CENTER_X, GetY()+100.0f, 0.0f ),
&D3DXVECTOR3( 0.0f, -1.0f, 0.0f )
);
else
D3DXMatrixLookAtLH(
&matNewView,
&D3DXVECTOR3( CENTER_X, GetY()+800.0f, 400.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-07-23 01:41:40 +00:00
m_frameCombo.Draw();
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
}
2002-07-23 01:41:40 +00:00
m_frameJudgement.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-05-27 08:23:27 +00:00
void Player::HandlePlayerStep( 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::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
// 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
2002-05-29 09:47:24 +00:00
int iIndexOverlappingNote = -1; // leave as -1 if we don't find any
2002-06-24 22:04:31 +00:00
// Start at iIndexStartLookingAt and search outward. The first one note overlaps the player's hit (this is the closest match).
for( int delta=0; delta <= iNumElementsToExamine; delta++ )
{
int iCurrentIndexEarlier = iIndexStartLookingAt - delta;
int iCurrentIndexLater = iIndexStartLookingAt + delta;
2001-11-03 10:52:42 +00:00
// 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 );
2001-11-03 10:52:42 +00:00
////////////////////////////
// check the step to the left of iIndexStartLookingAt
////////////////////////////
2002-05-19 01:59:48 +00:00
//LOG->WriteLine( "Checking Notes[%d]", iCurrentIndexEarlier );
2002-06-24 22:04:31 +00:00
if( m_TapNotes[col][iCurrentIndexEarlier] != '0' && // there is a note here
m_TapNoteScores[col][iCurrentIndexEarlier] == TNS_NONE ) // this note doesn't have a score
{
2002-05-29 09:47:24 +00:00
iIndexOverlappingNote = iCurrentIndexEarlier;
break;
}
2001-11-03 10:52:42 +00:00
2002-05-29 09:47:24 +00:00
////////////////////////////
// check the step to the right of iIndexStartLookingAt
////////////////////////////
2002-05-19 01:59:48 +00:00
//LOG->WriteLine( "Checking Notes[%d]", iCurrentIndexLater );
2002-06-24 22:04:31 +00:00
if( m_TapNotes[col][iCurrentIndexLater] != '0' && // there is a note here
m_TapNoteScores[col][iCurrentIndexLater] == TNS_NONE ) // this note doesn't have a score
{
2002-05-29 09:47:24 +00:00
iIndexOverlappingNote = iCurrentIndexLater;
break;
}
}
2002-05-29 09:47:24 +00:00
2002-07-11 19:02:26 +00:00
bool bDestroyedNote = false;
2002-05-29 09:47:24 +00:00
if( iIndexOverlappingNote != -1 )
{
2002-06-24 22:04:31 +00:00
// compute the score for this hit
const float fStepBeat = NoteRowToBeat( (float)iIndexOverlappingNote );
const float fBeatsUntilStep = fStepBeat - fSongBeat;
const float fPercentFromPerfect = fabsf( fBeatsUntilStep / fMaxBeatDiff );
TapNoteScore &score = m_TapNoteScores[col][iIndexOverlappingNote];
2002-07-11 19:02:26 +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;
2002-06-24 22:04:31 +00:00
else score = TNS_BOO;
2002-07-11 19:02:26 +00:00
bDestroyedNote = score >= TNS_GOOD;
2002-06-24 22:04:31 +00:00
2002-05-29 09:47:24 +00:00
bool bRowDestroyed = true;
for( int t=0; t<m_iNumTracks; t++ ) // did this complete the elminiation of the row?
{
2002-06-24 22:04:31 +00:00
if( m_TapNotes[t][iIndexOverlappingNote] != '0' && // there is a note here
m_TapNoteScores[t][iIndexOverlappingNote] == TNS_NONE ) // and it doesn't have a score
{
2002-05-29 09:47:24 +00:00
bRowDestroyed = false;
2002-06-24 22:04:31 +00:00
break; // stop searching
}
2002-05-29 09:47:24 +00:00
}
if( bRowDestroyed )
OnRowDestroyed( fSongBeat, col, fMaxBeatDiff, iIndexOverlappingNote );
}
2002-07-11 19:02:26 +00:00
if( !bDestroyedNote )
m_GrayArrowRow.Step( col );
}
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-01 19:14:55 +00:00
//LOG->WriteLine( "fBeatsUntilStep: %f, fPercentFromPerfect: %f",
// fBeatsUntilStep, fPercentFromPerfect );
2002-06-24 22:04:31 +00:00
// find the minimum score of the row
TapNoteScore score = TNS_PERFECT;
for( int t=0; t<m_iNumTracks; t++ )
if( m_TapNoteScores[t][iIndexThatWasSteppedOn] >= TNS_BOO )
score = min( score, m_TapNoteScores[t][iIndexThatWasSteppedOn] );
2001-11-03 10:52:42 +00:00
// update the judgement, score, and life
2002-02-24 01:43:11 +00:00
m_Judgement.SetJudgement( score );
2002-07-02 00:27:58 +00:00
if( m_pLifeMeter )
m_pLifeMeter->ChangeLife( score );
2001-11-03 10:52:42 +00:00
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
for( int c=0; c<m_iNumTracks; c++ ) // for each column
2002-02-24 01:43:11 +00:00
{
2002-06-24 22:04:31 +00:00
if( m_TapNotes[c][iIndexThatWasSteppedOn] != '0' ) // if there is a note in this col
{
2002-04-16 17:31:00 +00:00
m_GhostArrowRow.TapNote( c, score, m_Combo.GetCurrentCombo()>100 ); // show the ghost arrow for this column
2002-06-24 22:04:31 +00:00
2002-07-02 00:27:58 +00:00
if( m_pScore )
m_pScore->AddToScore( score, m_Combo.GetCurrentCombo() ); // update score - called once per note in this row
2001-12-01 23:46:09 +00:00
2002-07-23 01:41:40 +00:00
// update dance points for Oni lifemeter
2002-07-27 19:29:51 +00:00
if( GAMESTATE->m_aGameplayStatistics.GetSize() > 0 )
2002-07-23 01:41:40 +00:00
GAMESTATE->GetLatestGameplayStatistics().iActualDancePoints[m_PlayerNumber] += TapNoteScoreToDancePoints( score );
2002-06-24 22:04:31 +00:00
// update combo - called once per note in this row
switch( score )
{
case TNS_PERFECT:
case TNS_GREAT:
m_Combo.ContinueCombo();
break;
case TNS_GOOD:
case TNS_BOO:
m_Combo.EndCombo();
break;
}
}
2001-11-03 10:52:42 +00:00
}
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;
}
2002-07-23 01:41:40 +00:00
m_frameJudgement.SetZoom( fStartZoom );
m_frameJudgement.BeginTweening( 0.2f );
m_frameJudgement.SetTweenZoom( 1 );
m_frameCombo.SetZoom( fStartZoom );
m_frameCombo.BeginTweening( 0.2f );
m_frameCombo.SetTweenZoom( 1 );
2001-11-03 10:52:42 +00:00
}
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 );
2002-05-19 01:59:48 +00:00
int iMissIfOlderThanThisIndex = BeatToNoteRow( fMissIfOlderThanThisBeat );
2001-11-03 10:52:42 +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.
// Instead, only check 10 elements back. Even 10 is overkill.
int iStartCheckingAt = max( 0, iMissIfOlderThanThisIndex-10 );
2001-11-03 10:52:42 +00:00
2002-05-01 19:14:55 +00:00
//LOG->WriteLine( "iStartCheckingAt: %d iMissIfOlderThanThisIndex: %d", iStartCheckingAt, iMissIfOlderThanThisIndex );
2002-06-24 22:04:31 +00:00
for( int t=0; t<m_iNumTracks; t++ )
2001-11-03 10:52:42 +00:00
{
2002-06-24 22:04:31 +00:00
for( int r=iStartCheckingAt; r<iMissIfOlderThanThisIndex; r++ )
2001-11-03 10:52:42 +00:00
{
2002-06-24 22:04:31 +00:00
bool bFoundAMissInThisRow = false;
if( m_TapNotes[t][r] != '0' && m_TapNoteScores[t][r] == TNS_NONE )
{
m_TapNoteScores[t][r] = TNS_MISS;
iNumMissesFound++;
bFoundAMissInThisRow = true;
}
if( bFoundAMissInThisRow )
2002-07-02 00:27:58 +00:00
if( m_pLifeMeter )
m_pLifeMeter->ChangeLife( TNS_MISS );
2001-11-03 10:52:42 +00:00
}
}
2002-05-29 09:47:24 +00:00
if( iNumMissesFound > 0 )
{
m_Judgement.SetJudgement( TNS_MISS );
m_Combo.EndCombo();
}
2001-11-03 10:52:42 +00:00
return iNumMissesFound;
}
2002-06-24 22:04:31 +00:00
void Player::CrossedRow( int iNoteRow, float fSongBeat, float fMaxBeatDiff )
{
if( PREFSMAN->m_bAutoPlay )
{
// check to see if there's at the crossed row
for( int t=0; t<m_iNumTracks; t++ )
{
if( m_TapNotes[t][iNoteRow] != '0' )
this->HandlePlayerStep( fSongBeat, t, fMaxBeatDiff );
}
}
}
2001-11-03 10:52:42 +00:00
2002-07-23 01:41:40 +00:00
void Player::SaveGameplayStatistics()
2002-06-24 22:04:31 +00:00
{
2002-07-23 01:41:40 +00:00
GameplayStatistics& GS = GAMESTATE->m_aGameplayStatistics[GAMESTATE->m_aGameplayStatistics.GetSize()-1];
int p = m_PlayerNumber;
2002-06-24 22:04:31 +00:00
2002-07-23 01:41:40 +00:00
GS.iActualDancePoints[p] = 0;
2002-06-24 22:04:31 +00:00
for( int t=0; t<MAX_NOTE_TRACKS; t++ )
{
for( int r=0; r<MAX_TAP_NOTE_ROWS; r++ )
{
if( m_TapNotes[t][r] == '0' )
continue; // no note here
switch( m_TapNoteScores[t][r] )
{
2002-07-23 01:41:40 +00:00
case TNS_PERFECT: GS.perfect[p]++; break;
case TNS_GREAT: GS.great[p]++; break;
case TNS_GOOD: GS.good[p]++; break;
case TNS_BOO: GS.boo[p]++; break;
case TNS_MISS: GS.miss[p]++; break;
2002-06-24 22:04:31 +00:00
case TNS_NONE: break;
default: ASSERT( false );
}
2002-07-23 01:41:40 +00:00
GS.iActualDancePoints[p] += TapNoteScoreToDancePoints( m_TapNoteScores[t][r] );
2002-06-24 22:04:31 +00:00
}
}
for( int i=0; i<m_iNumHoldNotes; i++ )
{
switch( m_HoldNoteScores[i] )
{
2002-07-23 01:41:40 +00:00
case HNS_NG: GS.ng[p]++; break;
case HNS_OK: GS.ok[p]++; break;
case HNS_NONE: break;
2002-06-24 22:04:31 +00:00
default: ASSERT( false );
}
2002-07-23 01:41:40 +00:00
GS.iActualDancePoints[p] += HoldNoteScoreToDancePoints( m_HoldNoteScores[i] );
2002-06-24 22:04:31 +00:00
}
2002-07-23 01:41:40 +00:00
GS.max_combo[p] = m_Combo.GetMaxCombo();
GS.score[p] = m_pScore ? m_pScore->GetScore() : 0;
2002-06-24 22:04:31 +00:00
2002-07-23 01:41:40 +00:00
GS.failed[p] = m_pLifeMeter ? m_pLifeMeter->FailedEarlier() : false;
2002-06-24 22:04:31 +00:00
for( int r=0; r<NUM_RADAR_VALUES; r++ )
{
2002-07-23 01:41:40 +00:00
GS.fRadarActual[p][r] = this->GetActualRadarValue( (RadarCategory)r, GAMESTATE->m_pCurSong->m_fMusicLengthSeconds );
CLAMP( GS.fRadarActual[p][r], 0, 1 );
2002-06-24 22:04:31 +00:00
}
}