Files
itgmania212121/stepmania/src/Player.cpp
T

1416 lines
42 KiB
C++
Raw Normal View History

2001-11-03 10:52:42 +00:00
#include "stdafx.h"
/*
-----------------------------------------------------------------------------
File: Player.cpp
2001-11-03 10:52:42 +00:00
Desc: Object that accepts pad input, knocks down ColorArrows that were stepped on,
and keeps score for the player.
2001-11-03 10:52:42 +00:00
Copyright (c) 2001 Chris Danford. All rights reserved.
-----------------------------------------------------------------------------
*/
2001-11-03 10:52:42 +00:00
#include "ScreenDimensions.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"
2001-11-03 10:52:42 +00:00
2002-01-20 23:29:03 +00:00
const float LIFE_PERFECT = 0.010f;
const float LIFE_GREAT = 0.005f;
2001-11-20 11:49:10 +00:00
const float LIFE_GOOD = 0.000f;
2002-01-20 23:29:03 +00:00
const float LIFE_BOO = -0.010f;
const float LIFE_MISS = -0.020f;
2001-11-20 11:49:10 +00:00
const int ARROW_SIZE = 64;
const float ARROW_X_OFFSET[6] = {
ARROW_SIZE*-2.5,
ARROW_SIZE*-1.5,
ARROW_SIZE*-0.5,
ARROW_SIZE* 0.5,
ARROW_SIZE* 1.5,
ARROW_SIZE* 2.5
};
2001-11-20 11:49:10 +00:00
const float GRAY_ARROW_Y = ARROW_SIZE * 1.5;
const float ARROW_GAP = 70;
const int NUM_FRAMES_IN_COLOR_ARROW_SPRITE = 12;
const float JUDGEMENT_DISPLAY_TIME = 0.6f;
2001-12-20 12:37:38 +00:00
const float JUDGEMENT_Y_OFFSET = 20;
2001-12-20 12:37:38 +00:00
const float HOLD_JUDGEMENT_Y = GRAY_ARROW_Y + 80;
2001-12-19 01:50:57 +00:00
2001-11-26 05:41:43 +00:00
2001-11-20 11:49:10 +00:00
const float COMBO_TWEEN_TIME = 0.5f;
const float COMBO_Y = (CENTER_Y+60);
2001-11-20 11:49:10 +00:00
const int LIEFMETER_NUM_PILLS = 17;
const float LIFEMETER_Y = 30;
2001-12-19 01:50:57 +00:00
const float LIFEMETER_PILLS_Y = LIFEMETER_Y;
const float PILL_OFFSET_Y[LIEFMETER_NUM_PILLS] = {
2001-11-20 11:49:10 +00:00
0.3f, 0.7f, 1.0f, 0.7f, 0.3f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f // kind of a sin wave
};
2001-11-20 11:49:10 +00:00
const float SCORE_Y = SCREEN_HEIGHT - 40;
2001-11-03 10:52:42 +00:00
2001-12-20 12:37:38 +00:00
Player::Player( PlayerOptions po, PlayerNumber pn )
2001-11-03 10:52:42 +00:00
{
2001-12-19 01:50:57 +00:00
m_PlayerOptions = po;
2001-12-20 12:37:38 +00:00
m_PlayerNumber = pn;
2001-12-19 01:50:57 +00:00
m_iCurCombo = 0;
m_iMaxCombo = 0;
m_fLifePercentage = 0.50f;
m_fScore = 0;
2001-11-20 11:49:10 +00:00
// init step elements
for( int i=0; i<MAX_STEP_ELEMENTS; i++ )
{
m_OriginalStep[i] = 0;
m_LeftToStepOn[i] = 0;
m_StepScore[i] = none;
m_iColorArrowFrameOffset[i] = 0;
}
2001-11-03 10:52:42 +00:00
2001-11-20 11:49:10 +00:00
CMap<Step, Step, float, float> mapStepToRotation; // arrow facing left is rotation 0
mapStepToRotation[STEP_PAD1_LEFT] = 0;
mapStepToRotation[STEP_PAD1_UPLEFT] = D3DX_PI/4.0f;
mapStepToRotation[STEP_PAD1_DOWN] = -D3DX_PI/2.0f;
mapStepToRotation[STEP_PAD1_UP] = D3DX_PI/2.0f;
mapStepToRotation[STEP_PAD1_UPRIGHT]= D3DX_PI*3.0f/4.0f;
mapStepToRotation[STEP_PAD1_RIGHT] = D3DX_PI;
mapStepToRotation[STEP_PAD2_LEFT] = mapStepToRotation[STEP_PAD1_LEFT];
mapStepToRotation[STEP_PAD2_UPLEFT] = mapStepToRotation[STEP_PAD1_UPLEFT];
mapStepToRotation[STEP_PAD2_DOWN] = mapStepToRotation[STEP_PAD1_DOWN];
mapStepToRotation[STEP_PAD2_UP] = mapStepToRotation[STEP_PAD1_UP];
mapStepToRotation[STEP_PAD2_UPRIGHT]= mapStepToRotation[STEP_PAD1_UPRIGHT];
mapStepToRotation[STEP_PAD2_RIGHT] = mapStepToRotation[STEP_PAD1_RIGHT];
switch( GAMEINFO->m_GameMode )
{
case MODE_SINGLE:
case MODE_VERSUS:
case MODE_COUPLE:
2001-11-20 11:49:10 +00:00
m_iNumColumns = 4; // LEFT, DOWN, UP, RIGHT
m_StepToColumnNumber[STEP_PAD1_LEFT] = 0;
m_StepToColumnNumber[STEP_PAD1_DOWN] = 1;
m_StepToColumnNumber[STEP_PAD1_UP] = 2;
m_StepToColumnNumber[STEP_PAD1_RIGHT] = 3;
m_ColumnNumberToStep[0] = STEP_PAD1_LEFT;
m_ColumnNumberToStep[1] = STEP_PAD1_DOWN;
m_ColumnNumberToStep[2] = STEP_PAD1_UP;
m_ColumnNumberToStep[3] = STEP_PAD1_RIGHT;
m_ColumnToRotation[0] = mapStepToRotation[STEP_PAD1_LEFT];
m_ColumnToRotation[1] = mapStepToRotation[STEP_PAD1_DOWN];
m_ColumnToRotation[2] = mapStepToRotation[STEP_PAD1_UP];
m_ColumnToRotation[3] = mapStepToRotation[STEP_PAD1_RIGHT];
break;
case MODE_SOLO:
2001-11-20 11:49:10 +00:00
m_iNumColumns = 6; // LEFT, UP+LEFT, DOWN, UP, UP+RIGHT, RIGHT
m_StepToColumnNumber[STEP_PAD1_LEFT] = 0;
m_StepToColumnNumber[STEP_PAD1_UPLEFT] = 1;
m_StepToColumnNumber[STEP_PAD1_DOWN] = 2;
m_StepToColumnNumber[STEP_PAD1_UP] = 3;
m_StepToColumnNumber[STEP_PAD1_UPRIGHT] = 4;
m_StepToColumnNumber[STEP_PAD1_RIGHT] = 5;
m_ColumnNumberToStep[0] = STEP_PAD1_LEFT;
m_ColumnNumberToStep[1] = STEP_PAD1_UPLEFT;
m_ColumnNumberToStep[2] = STEP_PAD1_DOWN;
m_ColumnNumberToStep[3] = STEP_PAD1_UP;
m_ColumnNumberToStep[4] = STEP_PAD1_UPRIGHT;
m_ColumnNumberToStep[5] = STEP_PAD1_RIGHT;
m_ColumnToRotation[0] = mapStepToRotation[STEP_PAD1_LEFT];
m_ColumnToRotation[1] = mapStepToRotation[STEP_PAD1_UPLEFT];
m_ColumnToRotation[2] = mapStepToRotation[STEP_PAD1_DOWN];
m_ColumnToRotation[3] = mapStepToRotation[STEP_PAD1_UP];
m_ColumnToRotation[4] = mapStepToRotation[STEP_PAD1_UPRIGHT];
m_ColumnToRotation[5] = mapStepToRotation[STEP_PAD1_RIGHT];
break;
case MODE_DOUBLE:
2001-11-20 11:49:10 +00:00
m_iNumColumns = 8; // 1_LEFT, 1_DOWN, 1_UP, 1_RIGHT, 2_LEFT, 2_DOWN, 2_UP, 2_RIGHT
m_StepToColumnNumber[STEP_PAD1_LEFT] = 0;
m_StepToColumnNumber[STEP_PAD1_DOWN] = 1;
m_StepToColumnNumber[STEP_PAD1_UP] = 2;
m_StepToColumnNumber[STEP_PAD1_RIGHT] = 3;
m_StepToColumnNumber[STEP_PAD2_LEFT] = 4;
m_StepToColumnNumber[STEP_PAD2_DOWN] = 5;
m_StepToColumnNumber[STEP_PAD2_UP] = 6;
m_StepToColumnNumber[STEP_PAD2_RIGHT] = 7;
m_ColumnNumberToStep[0] = STEP_PAD1_LEFT;
m_ColumnNumberToStep[1] = STEP_PAD1_DOWN;
m_ColumnNumberToStep[2] = STEP_PAD1_UP;
m_ColumnNumberToStep[3] = STEP_PAD1_RIGHT;
m_ColumnNumberToStep[4] = STEP_PAD2_LEFT;
m_ColumnNumberToStep[5] = STEP_PAD2_DOWN;
m_ColumnNumberToStep[6] = STEP_PAD2_UP;
m_ColumnNumberToStep[7] = STEP_PAD2_RIGHT;
m_ColumnToRotation[0] = mapStepToRotation[STEP_PAD1_LEFT];
m_ColumnToRotation[1] = mapStepToRotation[STEP_PAD1_DOWN];
m_ColumnToRotation[2] = mapStepToRotation[STEP_PAD1_UP];
m_ColumnToRotation[3] = mapStepToRotation[STEP_PAD1_RIGHT];
m_ColumnToRotation[4] = mapStepToRotation[STEP_PAD2_LEFT];
m_ColumnToRotation[5] = mapStepToRotation[STEP_PAD2_DOWN];
m_ColumnToRotation[6] = mapStepToRotation[STEP_PAD2_UP];
m_ColumnToRotation[7] = mapStepToRotation[STEP_PAD2_RIGHT];
break;
default:
ASSERT( true ); // invalid GameMode
2001-11-20 11:49:10 +00:00
}
2001-12-01 23:46:09 +00:00
// init arrow rotations
2001-11-20 11:49:10 +00:00
for( int c=0; c < MAX_NUM_COLUMNS; c++ ) {
2001-11-29 11:05:04 +00:00
m_GrayArrow[c].SetRotation( m_ColumnToRotation[c] );
m_GhostArrow[c].SetRotation( m_ColumnToRotation[c] );
2001-12-28 10:15:59 +00:00
m_GhostArrowBright[c].SetRotation( m_ColumnToRotation[c] );
2001-12-19 01:50:57 +00:00
m_HoldGhostArrow[c].SetRotation( m_ColumnToRotation[c] );
2001-11-29 11:05:04 +00:00
m_ColorArrow[c].SetRotation( m_ColumnToRotation[c] );
}
2001-11-03 10:52:42 +00:00
2001-12-20 12:37:38 +00:00
// holder for judgement and combo displays
m_frameJudgementAndCombo.AddActor( &m_sprJudgement );
m_frameJudgementAndCombo.AddActor( &m_sprCombo );
2002-01-16 10:01:32 +00:00
m_frameJudgementAndCombo.AddActor( &m_textComboNumber );
2001-12-20 12:37:38 +00:00
m_frameJudgementAndCombo.SetXY( CENTER_X, CENTER_Y );
// judgement
m_fJudgementDisplayCountdown = 0;
2002-01-16 10:01:32 +00:00
m_sprJudgement.Load( THEME->GetPathTo(GRAPHIC_JUDGEMENT) );
2001-12-19 01:50:57 +00:00
m_sprJudgement.StopAnimating();
2001-12-20 12:37:38 +00:00
m_sprJudgement.SetXY( 0, m_PlayerOptions.m_bReverseScroll ? JUDGEMENT_Y_OFFSET : -JUDGEMENT_Y_OFFSET );
// combo
2002-01-16 10:01:32 +00:00
m_sprCombo.Load( THEME->GetPathTo(GRAPHIC_COMBO) );
2001-12-20 12:37:38 +00:00
m_sprCombo.StopAnimating();
m_sprCombo.SetXY( 40, m_PlayerOptions.m_bReverseScroll ? -JUDGEMENT_Y_OFFSET : JUDGEMENT_Y_OFFSET+2 );
m_sprCombo.SetZoom( 1.0f );
2002-01-16 10:01:32 +00:00
m_textComboNumber.Load( THEME->GetPathTo(FONT_COMBO_NUMBERS) );
m_textComboNumber.SetXY( -40, m_PlayerOptions.m_bReverseScroll ? -JUDGEMENT_Y_OFFSET : JUDGEMENT_Y_OFFSET );
2001-12-20 12:37:38 +00:00
2002-01-16 10:01:32 +00:00
m_textComboNumber.SetDiffuseColor( D3DXCOLOR(1,1,1,0) ); // invisible
2001-12-20 12:37:38 +00:00
m_sprCombo.SetDiffuseColor( D3DXCOLOR(1,1,1,0) ); // invisible
2001-12-19 01:50:57 +00:00
2001-12-20 12:37:38 +00:00
// hold judgement
2001-12-19 01:50:57 +00:00
for( c=0; c<MAX_NUM_COLUMNS; c++ )
{
m_fHoldJudgementDisplayCountdown[c] = 0;
2002-01-16 10:01:32 +00:00
m_sprHoldJudgement[c].Load( THEME->GetPathTo(GRAPHIC_JUDGEMENT) );
2001-12-19 01:50:57 +00:00
m_sprHoldJudgement[c].StopAnimating();
}
// life meter
2002-01-16 10:01:32 +00:00
m_sprLifeMeterFrame.Load( THEME->GetPathTo(GRAPHIC_LIFEMETER_FRAME) );
2001-12-19 01:50:57 +00:00
m_sprLifeMeterFrame.StopAnimating();
2002-01-16 10:01:32 +00:00
m_sprLifeMeterPills.Load( THEME->GetPathTo(GRAPHIC_LIFEMETER_PILLS) );
2001-12-19 01:50:57 +00:00
m_sprLifeMeterPills.StopAnimating();
// score
2002-01-16 10:01:32 +00:00
m_sprScoreFrame.Load( THEME->GetPathTo(GRAPHIC_SCORE_FRAME) );
2002-01-17 07:41:01 +00:00
m_ScoreDisplay.SetScore( 0 );
2001-11-26 05:41:43 +00:00
SetX( CENTER_X );
2001-12-28 10:15:59 +00:00
// assist
2002-01-16 10:01:32 +00:00
m_soundAssistTick.Load( THEME->GetPathTo(SOUND_ASSIST) );
2001-12-28 10:15:59 +00:00
2001-11-03 10:52:42 +00:00
}
2001-11-28 20:26:45 +00:00
void Player::SetX( float fX )
2001-11-03 10:52:42 +00:00
{
2001-11-28 20:26:45 +00:00
m_fArrowsCenterX = fX;
2002-01-16 19:28:31 +00:00
int fXInt = (int)m_fArrowsCenterX;
2002-01-16 19:28:31 +00:00
SetGrayArrowsX(fXInt);
SetGhostArrowsX(fXInt);
SetColorArrowsX(fXInt);
SetJudgementX(fXInt);
SetComboX(fXInt);
SetScoreX(fXInt);
SetLifeMeterX(fXInt);
2001-12-20 12:37:38 +00:00
m_frameJudgementAndCombo.SetX(fX);
}
2001-11-03 10:52:42 +00:00
2001-11-30 19:08:44 +00:00
void Player::SetSteps( const Steps& newSteps, bool bLoadOnlyLeftSide, bool bLoadOnlyRightSide )
{
2001-12-20 12:37:38 +00:00
Step tempSteps[MAX_STEP_ELEMENTS];
CArray<HoldStep, HoldStep> tempHoldSteps;
// copy the steps into our tempSteps where we will transform them
2001-11-30 19:08:44 +00:00
for( int i=0; i<MAX_STEP_ELEMENTS; i++ )
{
2001-12-20 12:37:38 +00:00
tempSteps[i] = newSteps.m_Steps[i];
2001-11-30 19:08:44 +00:00
2001-12-20 12:37:38 +00:00
if( bLoadOnlyLeftSide )
{
2001-11-30 19:08:44 +00:00
// mask off the pad2 steps
2001-12-20 12:37:38 +00:00
tempSteps[i] &= ~(STEP_PAD2_LEFT | STEP_PAD2_UPLEFT | STEP_PAD2_DOWN | STEP_PAD2_UP | STEP_PAD2_UPRIGHT | STEP_PAD2_RIGHT );
}
else if( bLoadOnlyRightSide )
{
2001-11-30 19:08:44 +00:00
// replace the step making pad2's step the new pad1 step
2001-12-20 12:37:38 +00:00
tempSteps[i] = (tempSteps[i]&STEP_PAD2_LEFT ? STEP_PAD1_LEFT : 0) |
(tempSteps[i]&STEP_PAD2_UPLEFT ? STEP_PAD1_UPLEFT : 0) |
(tempSteps[i]&STEP_PAD2_DOWN ? STEP_PAD1_DOWN : 0) |
(tempSteps[i]&STEP_PAD2_UP ? STEP_PAD1_UP : 0) |
(tempSteps[i]&STEP_PAD2_UPRIGHT ? STEP_PAD1_UPRIGHT : 0) |
(tempSteps[i]&STEP_PAD2_RIGHT ? STEP_PAD1_RIGHT : 0);
2001-11-30 19:08:44 +00:00
}
2001-11-03 10:52:42 +00:00
}
2001-11-30 19:08:44 +00:00
2001-12-20 12:37:38 +00:00
if( m_PlayerOptions.m_bAllowFreezeArrows )
{
// copy the HoldSteps and transform them later
for( int i=0; i<newSteps.m_HoldSteps.GetSize(); i++ )
{
HoldStep &hs = newSteps.m_HoldSteps[i];
2001-12-19 01:50:57 +00:00
2001-12-20 12:37:38 +00:00
if( bLoadOnlyLeftSide )
{
if( hs.m_Step & (STEP_PAD1_LEFT | STEP_PAD1_UPLEFT | STEP_PAD1_DOWN | STEP_PAD1_UP | STEP_PAD1_UPRIGHT | STEP_PAD1_RIGHT) )
tempHoldSteps.Add( hs );
}
else if( bLoadOnlyRightSide )
{
if( hs.m_Step & (STEP_PAD2_LEFT | STEP_PAD2_UPLEFT | STEP_PAD2_DOWN | STEP_PAD2_UP | STEP_PAD2_UPRIGHT | STEP_PAD2_RIGHT) )
tempHoldSteps.Add( hs );
}
else // load both sides
{
tempHoldSteps.Add( hs );
}
}
}
// transform the steps
Step oldStepToNewStep [12][2]; // 0 is old Step, 1 is new Step mapping
oldStepToNewStep[0][0] = STEP_PAD1_LEFT; oldStepToNewStep[0][1] = STEP_PAD1_LEFT;
oldStepToNewStep[1][0] = STEP_PAD1_UPLEFT; oldStepToNewStep[1][1] = STEP_PAD1_UPLEFT;
oldStepToNewStep[2][0] = STEP_PAD1_DOWN; oldStepToNewStep[2][1] = STEP_PAD1_DOWN;
oldStepToNewStep[3][0] = STEP_PAD1_UP; oldStepToNewStep[3][1] = STEP_PAD1_UP;
oldStepToNewStep[4][0] = STEP_PAD1_UPRIGHT; oldStepToNewStep[4][1] = STEP_PAD1_UPRIGHT;
oldStepToNewStep[5][0] = STEP_PAD1_RIGHT; oldStepToNewStep[5][1] = STEP_PAD1_RIGHT;
oldStepToNewStep[6][0] = STEP_PAD2_LEFT; oldStepToNewStep[6][1] = STEP_PAD2_LEFT;
oldStepToNewStep[7][0] = STEP_PAD2_UPLEFT; oldStepToNewStep[7][1] = STEP_PAD2_UPLEFT;
oldStepToNewStep[8][0] = STEP_PAD2_DOWN; oldStepToNewStep[8][1] = STEP_PAD2_DOWN;
oldStepToNewStep[9][0] = STEP_PAD2_UP; oldStepToNewStep[9][1] = STEP_PAD2_UP;
oldStepToNewStep[10][0]= STEP_PAD2_UPRIGHT; oldStepToNewStep[10][1]= STEP_PAD2_UPRIGHT;
oldStepToNewStep[11][0]= STEP_PAD2_RIGHT; oldStepToNewStep[11][1]= STEP_PAD2_RIGHT;
switch( m_PlayerOptions.m_TurnType )
{
case PlayerOptions::TURN_NONE:
break;
case PlayerOptions::TURN_MIRROR:
oldStepToNewStep[0][1] = STEP_PAD1_RIGHT;
oldStepToNewStep[2][1] = STEP_PAD1_UP;
oldStepToNewStep[3][1] = STEP_PAD1_DOWN;
oldStepToNewStep[5][1] = STEP_PAD1_LEFT;
oldStepToNewStep[6][1] = STEP_PAD2_RIGHT;
oldStepToNewStep[8][1] = STEP_PAD2_UP;
oldStepToNewStep[9][1] = STEP_PAD2_DOWN;
oldStepToNewStep[11][1]= STEP_PAD2_LEFT;
break;
case PlayerOptions::TURN_LEFT:
oldStepToNewStep[0][1] = STEP_PAD1_DOWN;
oldStepToNewStep[2][1] = STEP_PAD1_RIGHT;
oldStepToNewStep[3][1] = STEP_PAD1_LEFT;
oldStepToNewStep[5][1] = STEP_PAD1_UP;
oldStepToNewStep[6][1] = STEP_PAD2_DOWN;
oldStepToNewStep[8][1] = STEP_PAD2_RIGHT;
oldStepToNewStep[9][1] = STEP_PAD2_LEFT;
oldStepToNewStep[11][1]= STEP_PAD2_UP;
break;
case PlayerOptions::TURN_RIGHT:
oldStepToNewStep[0][1] = STEP_PAD1_UP;
oldStepToNewStep[2][1] = STEP_PAD1_LEFT;
oldStepToNewStep[3][1] = STEP_PAD1_RIGHT;
oldStepToNewStep[5][1] = STEP_PAD1_DOWN;
oldStepToNewStep[6][1] = STEP_PAD2_UP;
oldStepToNewStep[8][1] = STEP_PAD2_LEFT;
oldStepToNewStep[9][1] = STEP_PAD2_RIGHT;
oldStepToNewStep[11][1]= STEP_PAD2_DOWN;
break;
case PlayerOptions::TURN_SHUFFLE:
bool bAlreadyMapped[12];
for( int i=0; i<12; i++ )
bAlreadyMapped[i] = false;
// hack: don't shuffle the Up+... Steps
bAlreadyMapped[1] = true;
bAlreadyMapped[4] = true;
bAlreadyMapped[7] = true;
bAlreadyMapped[10] = true;
// shuffle left side
for( i=0; i<6; i++ )
{
if( i == 1 || i == 4 )
continue;
int iMapsTo;
do {
iMapsTo = rand()%6;
} while( bAlreadyMapped[iMapsTo] );
bAlreadyMapped[iMapsTo] = true;
oldStepToNewStep[i][1] = oldStepToNewStep[iMapsTo][0];
}
// shuffle right side
for( i=6; i<12; i++ )
{
if( i == 7 || i == 10 )
continue;
int iMapsTo;
do {
iMapsTo = rand()%6+6;
} while( bAlreadyMapped[iMapsTo] );
bAlreadyMapped[iMapsTo] = true;
oldStepToNewStep[i][1] = oldStepToNewStep[iMapsTo][0];
}
break;
}
// transform tempSteps and store them in the Player's structures
for( i=0; i<MAX_STEP_ELEMENTS; i++ )
2001-12-19 01:50:57 +00:00
{
2001-12-20 12:37:38 +00:00
Step &oldStep = tempSteps[i];
Step &newStep = m_OriginalStep[i];
newStep = STEP_NONE;
for( int j=0; j<12; j++ )
{
if( oldStep & oldStepToNewStep[j][0] )
newStep |= oldStepToNewStep[j][1];
}
m_LeftToStepOn[i] = m_OriginalStep[i];
m_iColorArrowFrameOffset[i] = (int)( i/(float)ELEMENTS_PER_BEAT*NUM_FRAMES_IN_COLOR_ARROW_SPRITE );
}
// transform tempHoldSteps and store them in the Player's structures
for( i=0; i<tempHoldSteps.GetSize(); i++ )
{
HoldStep &oldHoldStep = tempHoldSteps[i];
HoldStep newHoldStep = oldHoldStep;
2001-12-28 10:15:59 +00:00
newHoldStep.m_Step = STEP_NONE;
2001-12-20 12:37:38 +00:00
for( int j=0; j<12; j++ )
{
if( oldHoldStep.m_Step & oldStepToNewStep[j][0] )
newHoldStep.m_Step |= oldStepToNewStep[j][1];
}
m_HoldSteps.Add( newHoldStep );
2001-12-28 10:15:59 +00:00
m_HoldStepScores.Add( HoldStepScore() );
2001-12-19 01:50:57 +00:00
}
2001-12-20 12:37:38 +00:00
2001-12-28 10:15:59 +00:00
// filter out all non-quarter notes if little is enabled
if( m_PlayerOptions.m_bLittle )
{
for( i=0; i<MAX_STEP_ELEMENTS; i++ )
{
if( i%ELEMENTS_PER_BEAT != 0 )
{
m_OriginalStep[i] = STEP_NONE;
m_LeftToStepOn[i] = STEP_NONE;
}
}
// leave HoldSteps unchanged
}
}
2001-11-03 10:52:42 +00:00
void Player::Update( float fDeltaTime, float fSongBeat, float fMaxBeatDifference )
{
//RageLog( "Player::Update(%f, %f, %f)", fDeltaTime, fSongBeat, fMaxBeatDifference );
2001-11-28 20:26:45 +00:00
m_fSongBeat = fSongBeat; // save song beat
2001-12-19 01:50:57 +00:00
// check for misses
int iNumMisses = UpdateStepsMissedOlderThan( m_fSongBeat-fMaxBeatDifference );
2001-11-03 10:52:42 +00:00
if( iNumMisses > 0 )
{
SetJudgement( miss );
2001-12-28 10:15:59 +00:00
EndCombo();
for( int i=0; i<iNumMisses; i++ )
ChangeLife( miss );
2001-11-03 10:52:42 +00:00
}
2001-12-19 01:50:57 +00:00
// check for HoldStep misses
for( int i=0; i<m_HoldSteps.GetSize(); i++ )
{
HoldStep &hs = m_HoldSteps[i];
float fStartBeat = StepIndexToBeat( hs.m_iStartIndex );
float fEndBeat = StepIndexToBeat( hs.m_iEndIndex );
2001-12-28 10:15:59 +00:00
// update the "electric ghost arrow"
if( m_HoldStepScores[i].m_HoldScore == HoldStepScore::HOLD_STEPPED_ON && // this hold doesn't already have a score
2001-12-20 21:08:45 +00:00
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
{
2001-12-20 12:37:38 +00:00
PlayerInput PlayerI = { m_PlayerNumber, hs.m_Step };
2001-12-19 01:50:57 +00:00
if( GAMEINFO->IsButtonDown( PlayerI ) ) // they're holding the button down
{
int iCol = m_StepToColumnNumber[ hs.m_Step ];
m_HoldGhostArrow[iCol].Step();
}
2001-12-20 21:08:45 +00:00
}
// update the logic
2001-12-28 10:15:59 +00:00
if( (m_HoldStepScores[i].m_HoldScore == HoldStepScore::HOLD_SCORE_NONE || m_HoldStepScores[i].m_HoldScore == HoldStepScore::HOLD_STEPPED_ON) && // this hold doesn't already have a score
2001-12-20 21:08:45 +00:00
fStartBeat+fMaxBeatDifference/2 < m_fSongBeat && m_fSongBeat < fEndBeat-fMaxBeatDifference/2 ) // if the song beat is in the range of this hold
{
PlayerInput PlayerI = { m_PlayerNumber, hs.m_Step };
if( !GAMEINFO->IsButtonDown( PlayerI ) ) // they're not holding the button down
2001-12-19 01:50:57 +00:00
{
2001-12-28 10:15:59 +00:00
m_HoldStepScores[i].m_HoldScore = HoldStepScore::HOLD_SCORE_NG;
2001-12-19 01:50:57 +00:00
int iCol = m_StepToColumnNumber[ hs.m_Step ];
2001-12-28 10:15:59 +00:00
SetHoldJudgement( iCol, HoldStepScore::HOLD_SCORE_NG );
2001-12-19 01:50:57 +00:00
}
}
}
// check for HoldStep completes
for( i=0; i<m_HoldSteps.GetSize(); i++ )
{
HoldStep &hs = m_HoldSteps[i];
float fEndBeat = StepIndexToBeat( hs.m_iEndIndex );
2001-12-20 21:08:45 +00:00
if( m_fSongBeat > fEndBeat && // if this hold step is in the past
2001-12-28 10:15:59 +00:00
m_HoldStepScores[i].m_HoldScore == HoldStepScore::HOLD_STEPPED_ON ) // and it doesn't yet have a score
2001-12-19 01:50:57 +00:00
{
2001-12-28 10:15:59 +00:00
m_HoldStepScores[i].m_HoldScore = HoldStepScore::HOLD_SCORE_OK;
2001-12-19 01:50:57 +00:00
int iCol = m_StepToColumnNumber[ hs.m_Step ];
2001-12-28 10:15:59 +00:00
SetHoldJudgement( iCol, HoldStepScore::HOLD_SCORE_OK );
2001-12-19 01:50:57 +00:00
}
}
UpdateGrayArrows( fDeltaTime );
UpdateColorArrows( fDeltaTime );
2001-12-01 23:46:09 +00:00
UpdateGhostArrows( fDeltaTime );
UpdateJudgement( fDeltaTime );
UpdateCombo( fDeltaTime );
UpdateScore( fDeltaTime );
UpdateLifeMeter( fDeltaTime );
2001-12-20 12:37:38 +00:00
m_frameJudgementAndCombo.Update( fDeltaTime );
2001-11-03 10:52:42 +00:00
}
2001-12-28 10:15:59 +00:00
void Player::CrossedIndex( int iIndex )
{
if( GAMEINFO->m_SongOptions.m_AssistType == SongOptions::ASSIST_TICK )
{
bool bThereIsANoteThisIndex = false;
bThereIsANoteThisIndex |= (m_OriginalStep[iIndex] != STEP_NONE);
for( int i=0; i<m_HoldSteps.GetSize(); i++ )
{
if( m_HoldSteps[i].m_iStartIndex == iIndex )
{
bThereIsANoteThisIndex |= true;
break;
}
}
if( bThereIsANoteThisIndex )
m_soundAssistTick.PlayRandom();
}
}
2002-01-16 10:01:32 +00:00
void Player::RenderPrimitives()
2001-11-03 10:52:42 +00:00
{
DrawGrayArrows();
2001-11-28 20:26:45 +00:00
DrawColorArrows();
2001-12-01 23:46:09 +00:00
DrawGhostArrows();
DrawJudgement();
DrawCombo();
DrawScore();
2001-12-20 12:37:38 +00:00
DrawLifeMeter();
m_frameJudgementAndCombo.Draw();
}
2001-11-03 10:52:42 +00:00
void Player::HandlePlayerStep( float fSongBeat, Step player_step, float fMaxBeatDiff )
{
//RageLog( "Player::HandlePlayerStep()" );
2001-11-03 10:52:42 +00:00
// update gray arrows
2001-11-20 11:49:10 +00:00
int iColumnNum = m_StepToColumnNumber[player_step];
2001-12-01 23:46:09 +00:00
GrayArrowStep( iColumnNum, perfect );
2001-11-03 10:52:42 +00:00
CheckForCompleteStep( fSongBeat, player_step, fMaxBeatDiff );
2001-12-19 01:50:57 +00:00
// check if we stepped on the beginning of a HoldStep
int iCurrentIndex = BeatToStepIndex( fSongBeat );
for( int i=0; i<m_HoldSteps.GetSize(); i++ ) // for each HoldStep
{
2001-12-28 10:15:59 +00:00
if( m_HoldStepScores[i].m_HoldScore == HoldStepScore::HOLD_SCORE_NONE && // this has not already been stepped on
player_step == m_HoldSteps[i].m_Step ) // player steps is the same note as the hold
2001-12-19 01:50:57 +00:00
{
HoldStep &hs = m_HoldSteps[i];
int iIndexDifference = abs( hs.m_iStartIndex - iCurrentIndex );
int iMaxIndexDiff = BeatToStepIndex( fMaxBeatDiff );
if( iIndexDifference <= iMaxIndexDiff )
2001-12-28 10:15:59 +00:00
{
m_HoldStepScores[i].m_HoldScore = HoldStepScore::HOLD_STEPPED_ON;
float fBeatsUntilStep = StepIndexToBeat(hs.m_iStartIndex) - fSongBeat;
float fPercentFromPerfect = (float)fabs( fBeatsUntilStep / fMaxBeatDiff );
//RageLog( "fBeatsUntilStep: %f, fPercentFromPerfect: %f",
// fBeatsUntilStep, fPercentFromPerfect );
// compute what the score should be for the note we stepped on
StepScore &stepscore = m_HoldStepScores[i].m_StepScore;
if( fPercentFromPerfect < 0.25f ) stepscore = perfect;
else if( fPercentFromPerfect < 0.50f ) stepscore = great;
else if( fPercentFromPerfect < 0.75f ) stepscore = good;
else stepscore = boo;
// update the judgement, score, and life
SetJudgement( stepscore );
ChangeScore( stepscore, m_iCurCombo );
ChangeLife( stepscore );
// show the gray arrow ghost
for( int c=0; c < m_iNumColumns; c++ ) // for each arrow column
{
if( m_HoldSteps[i].m_Step & m_ColumnNumberToStep[c] ) // this column matches the step
GhostArrowStep( c, stepscore );
}
// update the combo display
switch( stepscore )
{
case perfect:
case great:
ContinueCombo();
break;
case good:
case boo:
EndCombo();
break;
}
}
2001-12-19 01:50:57 +00:00
}
}
}
2001-11-03 10:52:42 +00:00
void Player::CheckForCompleteStep( float fSongBeat, Step player_step, float fMaxBeatDiff )
2001-11-03 10:52:42 +00:00
{
//RageLog( "Player::CheckForCompleteStep()" );
2001-11-03 10:52:42 +00:00
// look for the closest matching step
int iIndexStartLookingAt = BeatToStepIndex( fSongBeat );
int iNumElementsToExamine = BeatToStepIndex( fMaxBeatDiff ); // number of elements to examine on either end of iIndexStartLookingAt
2001-11-03 10:52:42 +00:00
//RageLog( "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
iCurrentIndexEarlier = clamp( iCurrentIndexEarlier, 0, MAX_STEP_ELEMENTS-1 );
iCurrentIndexLater = clamp( iCurrentIndexLater, 0, MAX_STEP_ELEMENTS-1 );
////////////////////////////
// check the step to the left of iIndexStartLookingAt
////////////////////////////
//RageLog( "Checking steps[%d]", iCurrentIndexEarlier );
if( m_LeftToStepOn[iCurrentIndexEarlier] & player_step ) // these steps overlap
{
m_LeftToStepOn[iCurrentIndexEarlier] &= ~player_step; // subtract player_step
if( m_LeftToStepOn[iCurrentIndexEarlier] == 0 ) { // did this complete the step?
OnCompleteStep( fSongBeat, player_step, fMaxBeatDiff, iCurrentIndexEarlier );
return;
}
}
2001-11-03 10:52:42 +00:00
////////////////////////////
// check the step to the right of iIndexStartLookingAt
////////////////////////////
//RageLog( "Checking steps[%d]", iCurrentIndexLater );
if( m_LeftToStepOn[iCurrentIndexLater] & player_step ) // these steps overlap
{
m_LeftToStepOn[iCurrentIndexLater] &= ~player_step; // subtract player_step
if( m_LeftToStepOn[iCurrentIndexLater] == 0 ) { // did this complete the step?
OnCompleteStep( fSongBeat, player_step, fMaxBeatDiff, iCurrentIndexLater );
return;
}
}
}
}
2001-11-03 10:52:42 +00:00
void Player::OnCompleteStep( float fSongBeat, Step player_step, float fMaxBeatDiff, int iIndexThatWasSteppedOn )
{
float fStepBeat = StepIndexToBeat( iIndexThatWasSteppedOn );
2001-11-30 09:38:35 +00:00
float fBeatsUntilStep = fStepBeat - fSongBeat;
float fPercentFromPerfect = (float)fabs( fBeatsUntilStep / fMaxBeatDiff );
2001-11-03 10:52:42 +00:00
//RageLog( "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
StepScore &stepscore = m_StepScore[iIndexThatWasSteppedOn];
2001-11-03 10:52:42 +00:00
2001-12-19 14:56:22 +00:00
if( fPercentFromPerfect < 0.25f ) stepscore = perfect;
else if( fPercentFromPerfect < 0.50f ) stepscore = great;
else if( fPercentFromPerfect < 0.75f ) stepscore = good;
else stepscore = boo;
// update the judgement, score, and life
SetJudgement( stepscore );
ChangeScore( stepscore, m_iCurCombo );
ChangeLife( stepscore );
2001-11-03 10:52:42 +00:00
2001-12-01 23:46:09 +00:00
// show the gray arrow ghost
for( int c=0; c < m_iNumColumns; c++ ) { // for each arrow column
if( m_OriginalStep[iIndexThatWasSteppedOn] & m_ColumnNumberToStep[c] ) { // this column is still unstepped on?
GhostArrowStep( c, stepscore );
}
}
2001-11-03 10:52:42 +00:00
// update the combo display
switch( stepscore )
2001-11-03 10:52:42 +00:00
{
case perfect:
case great:
2001-12-28 10:15:59 +00:00
ContinueCombo();
2001-11-03 10:52:42 +00:00
break;
case good:
case boo:
2001-12-28 10:15:59 +00:00
EndCombo();
2001-11-03 10:52:42 +00:00
break;
}
}
int Player::UpdateStepsMissedOlderThan( float fMissIfOlderThanThisBeat )
2001-11-03 10:52:42 +00:00
{
//RageLog( "Steps::UpdateStepsMissedOlderThan(%f)", fMissIfOlderThanThisBeat );
2001-11-03 10:52:42 +00:00
int iMissIfOlderThanThisIndex = BeatToStepIndex( fMissIfOlderThanThisBeat );
2001-11-03 10:52:42 +00:00
int iNumMissesFound = 0;
// Since this is being called 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
//RageLog( "iStartCheckingAt: %d iMissIfOlderThanThisIndex: %d", iStartCheckingAt, iMissIfOlderThanThisIndex );
for( int i=iStartCheckingAt; i<iMissIfOlderThanThisIndex; i++ )
2001-11-03 10:52:42 +00:00
{
//RageLog( "Checking for miss: %d: lefttostepon == %d, score == %d", i, m_LeftToStepOn[i], m_StepScore[i] );
if( m_LeftToStepOn[i] != 0 && m_StepScore[i] != miss)
2001-11-03 10:52:42 +00:00
{
m_StepScore[i] = miss;
iNumMissesFound++;
ChangeLife( miss );
2001-11-03 10:52:42 +00:00
}
}
return iNumMissesFound;
}
ScoreSummary Player::GetScoreSummary()
{
ScoreSummary scoreSummary;
for( int i=0; i<MAX_STEP_ELEMENTS; i++ )
2001-11-03 10:52:42 +00:00
{
switch( m_StepScore[i] )
{
case perfect: scoreSummary.perfect++; break;
case great: scoreSummary.great++; break;
case good: scoreSummary.good++; break;
case boo: scoreSummary.boo++; break;
case miss: scoreSummary.miss++; break;
case none: break;
2001-11-03 10:52:42 +00:00
}
}
2001-12-28 10:15:59 +00:00
for( i=0; i<m_HoldStepScores.GetSize(); i++ )
{
switch( m_HoldStepScores[i].m_StepScore )
{
case perfect: scoreSummary.perfect++; break;
case great: scoreSummary.great++; break;
case good: scoreSummary.good++; break;
case boo: scoreSummary.boo++; break;
case miss: scoreSummary.miss++; break;
case none: break;
}
switch( m_HoldStepScores[i].m_HoldScore )
{
case HoldStepScore::HOLD_SCORE_NG: scoreSummary.ng++; break;
case HoldStepScore::HOLD_SCORE_OK: scoreSummary.ok++; break;
}
}
2001-11-03 10:52:42 +00:00
scoreSummary.max_combo = m_iMaxCombo;
scoreSummary.score = m_fScore;
return scoreSummary;
}
2001-11-28 20:26:45 +00:00
float Player::GetArrowColumnX( int iColNum )
{
float fColOffsetFromCenter = iColNum - (m_iNumColumns-1)/2.0f;
return m_fArrowsCenterX + fColOffsetFromCenter * ARROW_SIZE;
2001-11-20 11:49:10 +00:00
}
void Player::UpdateGrayArrows( float fDeltaTime )
{
2001-11-20 11:49:10 +00:00
for( int i=0; i < m_iNumColumns; i++ ) {
2001-11-29 11:05:04 +00:00
m_GrayArrow[i].Update( fDeltaTime );
2001-12-01 23:46:09 +00:00
}
}
void Player::UpdateGhostArrows( float fDeltaTime )
2001-12-01 23:46:09 +00:00
{
for( int i=0; i < m_iNumColumns; i++ ) {
2001-11-29 11:05:04 +00:00
m_GhostArrow[i].Update( fDeltaTime );
2001-12-28 10:15:59 +00:00
m_GhostArrowBright[i].Update( fDeltaTime );
2001-12-19 01:50:57 +00:00
m_HoldGhostArrow[i].Update( fDeltaTime );
}
}
void Player::DrawGrayArrows()
{
2001-11-20 11:49:10 +00:00
for( int i=0; i<m_iNumColumns; i++ )
2001-11-30 03:03:10 +00:00
{
2001-12-01 23:46:09 +00:00
m_GrayArrow[i].SetBeat( m_fSongBeat );
2001-11-29 11:05:04 +00:00
m_GrayArrow[i].Draw();
2001-11-30 03:03:10 +00:00
}
}
2001-12-01 23:46:09 +00:00
void Player::DrawGhostArrows()
{
for( int i=0; i<m_iNumColumns; i++ )
{
m_GhostArrow[i].SetBeat( m_fSongBeat );
m_GhostArrow[i].Draw();
2001-12-28 10:15:59 +00:00
m_GhostArrowBright[i].SetBeat( m_fSongBeat );
m_GhostArrowBright[i].Draw();
2001-12-19 01:50:57 +00:00
m_HoldGhostArrow[i].SetBeat( m_fSongBeat );
m_HoldGhostArrow[i].Draw();
2001-12-01 23:46:09 +00:00
}
}
void Player::SetGrayArrowsX( int iNewX )
{
2001-11-20 11:49:10 +00:00
for( int i=0; i<m_iNumColumns; i++ )
2001-12-19 01:50:57 +00:00
{
float fY = GetGrayArrowYPos();
if( m_PlayerOptions.m_bReverseScroll ) fY = SCREEN_HEIGHT - fY;
m_GrayArrow[i].SetXY( GetArrowColumnX(i), fY );
}
}
2001-11-29 11:05:04 +00:00
void Player::SetGhostArrowsX( int iNewX )
{
2001-11-20 11:49:10 +00:00
for( int i=0; i<m_iNumColumns; i++ )
2001-12-19 01:50:57 +00:00
{
float fY = GetGrayArrowYPos();
if( m_PlayerOptions.m_bReverseScroll ) fY = SCREEN_HEIGHT - fY;
m_GhostArrow[i].SetXY( GetArrowColumnX(i), fY );
2001-12-28 10:15:59 +00:00
m_GhostArrowBright[i].SetXY( GetArrowColumnX(i), fY );
2001-12-19 01:50:57 +00:00
m_HoldGhostArrow[i].SetXY( GetArrowColumnX(i), fY );
}
2001-11-29 11:05:04 +00:00
}
2001-11-29 11:05:04 +00:00
void Player::SetColorArrowsX( int iNewX )
{
for( int i=0; i<m_iNumColumns; i++ )
m_ColorArrow[i].SetX( GetArrowColumnX(i) );
}
2001-12-01 23:46:09 +00:00
void Player::GrayArrowStep( int index, StepScore score )
{
2001-12-01 23:46:09 +00:00
m_GrayArrow[index].Step( perfect );
}
2001-12-01 23:46:09 +00:00
void Player::GhostArrowStep( int index, StepScore score )
{
2001-12-28 10:15:59 +00:00
if( m_iCurCombo >= 100 )
m_GhostArrowBright[index].Step( score );
else
m_GhostArrow[index].Step( score );
}
void Player::UpdateColorArrows( float fDeltaTime )
{
2001-11-29 11:05:04 +00:00
int iIndexFirstArrowToDraw = BeatToStepIndex( m_fSongBeat - 2.0f ); // 2 beats earlier
if( iIndexFirstArrowToDraw < 0 ) iIndexFirstArrowToDraw = 0;
int iIndexLastArrowToDraw = BeatToStepIndex( m_fSongBeat + 7.0f ); // 7 beats later
2001-11-29 11:05:04 +00:00
for( int c=0; c < m_iNumColumns; c++ )
m_ColorArrow[c].Update( fDeltaTime );
}
2001-11-29 11:05:04 +00:00
//
// modified to add color shifting to the arrow texture
//
2001-11-28 20:26:45 +00:00
void Player::DrawColorArrows()
{
//RageLog( "ColorArrows::Draw(%f)", fSongBeat );
2001-11-28 20:26:45 +00:00
int iBaseFrameNo = (int)(m_fSongBeat*2.5) % 12; // 2.5 is a "fudge number" :-) This should be based on BPM
2001-12-19 01:50:57 +00:00
if( iBaseFrameNo < 0 )
iBaseFrameNo = 0;
if( m_fSongBeat < 0 )
m_fSongBeat = 0;
2001-11-28 20:26:45 +00:00
int iIndexFirstArrowToDraw = BeatToStepIndex( m_fSongBeat - 2.0f ); // 2 beats earlier
if( iIndexFirstArrowToDraw < 0 ) iIndexFirstArrowToDraw = 0;
2001-11-28 20:26:45 +00:00
int iIndexLastArrowToDraw = BeatToStepIndex( m_fSongBeat + 7.0f ); // 7 beats later
//RageLog( "Drawing elements %d through %d", iIndexFirstArrowToDraw, iIndexLastArrowToDraw );
2001-11-20 11:49:10 +00:00
for( int i=iIndexFirstArrowToDraw; i<=iIndexLastArrowToDraw; i++ ) // for each row
{
2001-12-20 21:08:45 +00:00
if( m_LeftToStepOn[i] != 0 || // this step is not yet complete
m_StepScore[i] == good || m_StepScore[i] == boo || m_StepScore[i] == miss )
{
2001-12-20 12:37:38 +00:00
float fYOffset = GetColorArrowYOffset( i, m_fSongBeat );
2001-11-28 20:26:45 +00:00
float fYPos = GetColorArrowYPos( i, m_fSongBeat );
2001-12-19 01:50:57 +00:00
if( m_PlayerOptions.m_bReverseScroll ) fYPos = SCREEN_HEIGHT - fYPos;
2001-12-20 12:37:38 +00:00
float fAlpha = GetColorArrowAlphaFromYOffset( fYOffset );
2001-11-30 02:24:56 +00:00
// beats until the note is stepped on.
float fBeatsTilStep = StepIndexToBeat( i ) - m_fSongBeat;
//RageLog( "iYPos: %d, iFrameNo: %d, m_OriginalStep[i]: %d", iYPos, iFrameNo, m_OriginalStep[i] );
2001-11-20 11:49:10 +00:00
for( int c=0; c < m_iNumColumns; c++ ) { // for each arrow column
if( m_OriginalStep[i] & m_ColumnNumberToStep[c] ) { // this column is still unstepped on?
2001-11-29 11:05:04 +00:00
m_ColorArrow[c].SetY( fYPos );
2001-12-01 23:46:09 +00:00
m_ColorArrow[c].SetIndexAndBeat( i, m_fSongBeat );
2001-12-20 12:37:38 +00:00
m_ColorArrow[c].SetAlpha( fAlpha );
2001-11-29 11:05:04 +00:00
m_ColorArrow[c].Draw();
2001-11-20 11:49:10 +00:00
}
}
2001-11-20 11:49:10 +00:00
} // end if there is a step
} // end foreach arrow to draw
2001-12-19 01:50:57 +00:00
// draw all freeze arrows
for( i=0; i<m_HoldSteps.GetSize(); i++ )
{
HoldStep &hs = m_HoldSteps[i];
2001-12-28 10:15:59 +00:00
// check if this entire hold step is on the screen
2001-12-19 01:50:57 +00:00
if( !( iIndexFirstArrowToDraw <= hs.m_iEndIndex && hs.m_iEndIndex <= iIndexLastArrowToDraw ||
iIndexFirstArrowToDraw <= hs.m_iStartIndex && hs.m_iStartIndex <= iIndexLastArrowToDraw ||
hs.m_iStartIndex < iIndexFirstArrowToDraw && hs.m_iEndIndex > iIndexLastArrowToDraw ) )
{
continue;
}
2001-12-28 10:15:59 +00:00
HoldStepScore::HoldScore &score = m_HoldStepScores[i].m_HoldScore;
2001-12-19 01:50:57 +00:00
int iColNum = m_StepToColumnNumber[ hs.m_Step ];
switch( score )
{
2001-12-28 10:15:59 +00:00
case HoldStepScore::HOLD_SCORE_OK:
2001-12-19 01:50:57 +00:00
continue; // don't draw
2001-12-28 10:15:59 +00:00
case HoldStepScore::HOLD_SCORE_NONE:
case HoldStepScore::HOLD_SCORE_NG:
2001-12-19 01:50:57 +00:00
m_ColorArrow[iColNum].SetGrayPartClear();
break;
2001-12-28 10:15:59 +00:00
case HoldStepScore::HOLD_STEPPED_ON:
2001-12-19 01:50:57 +00:00
m_ColorArrow[iColNum].SetGrayPartFull();
break;
}
// draw the gray parts
for( int j=hs.m_iEndIndex; j>=hs.m_iStartIndex; j-- ) // for each arrow in this freeze
{
2001-12-28 10:15:59 +00:00
// check if this hold step is off the the screen
if( j < iIndexFirstArrowToDraw || iIndexLastArrowToDraw < j)
continue; // skip this arrow
2001-12-20 12:37:38 +00:00
float fYOffset = GetColorArrowYOffset( j, m_fSongBeat );
2001-12-19 01:50:57 +00:00
float fYPos = GetColorArrowYPos( j, m_fSongBeat );
2001-12-28 10:15:59 +00:00
if( score == HoldStepScore::HOLD_STEPPED_ON || score == HoldStepScore::HOLD_SCORE_OK )
{
if( fYPos < GetGrayArrowYPos() )
continue; // don't draw
}
2001-12-19 01:50:57 +00:00
if( m_PlayerOptions.m_bReverseScroll ) fYPos = SCREEN_HEIGHT - fYPos;
m_ColorArrow[iColNum].SetY( fYPos );
2001-12-28 10:15:59 +00:00
float fAlpha = GetColorArrowAlphaFromYOffset( fYOffset );
2001-12-20 12:37:38 +00:00
m_ColorArrow[iColNum].SetAlpha( fAlpha );
2001-12-19 01:50:57 +00:00
m_ColorArrow[iColNum].DrawGrayPart();
}
// draw the color parts
for( j=hs.m_iEndIndex; j>=hs.m_iStartIndex; j-- ) // for each arrow in this freeze
{
2001-12-28 10:15:59 +00:00
// check if this hold step is off the the screen
if( j < iIndexFirstArrowToDraw || iIndexLastArrowToDraw < j)
continue; // skip this arrow
2001-12-20 12:37:38 +00:00
float fYOffset = GetColorArrowYOffset( j, m_fSongBeat );
2001-12-19 01:50:57 +00:00
float fYPos = GetColorArrowYPos( j, m_fSongBeat );
m_ColorArrow[iColNum].SetY( fYPos );
2001-12-28 10:15:59 +00:00
if( score == HoldStepScore::HOLD_STEPPED_ON || score == HoldStepScore::HOLD_SCORE_OK )
{
if( fYPos < GetGrayArrowYPos() )
continue; // don't draw
}
2001-12-19 01:50:57 +00:00
if( m_PlayerOptions.m_bReverseScroll ) fYPos = SCREEN_HEIGHT - fYPos;
m_ColorArrow[iColNum].SetY( fYPos );
D3DXCOLOR color( (float)(j-hs.m_iStartIndex)/(float)(hs.m_iEndIndex-hs.m_iStartIndex), 1, 0, 1 ); // color shifts from green to yellow
2001-12-20 12:37:38 +00:00
m_ColorArrow[iColNum].SetDiffuseColor( color );
2001-12-28 10:15:59 +00:00
float fAlpha = GetColorArrowAlphaFromYOffset( fYOffset );
2001-12-20 12:37:38 +00:00
m_ColorArrow[iColNum].SetAlpha( fAlpha );
2001-12-19 01:50:57 +00:00
m_ColorArrow[iColNum].DrawColorPart();
}
// draw the first arrow on top of the others
j = hs.m_iStartIndex;
2001-12-20 12:37:38 +00:00
float fYOffset = GetColorArrowYOffset( j, m_fSongBeat );
2001-12-19 01:50:57 +00:00
float fYPos = GetColorArrowYPos( j, m_fSongBeat );
2001-12-28 10:15:59 +00:00
if( score == HoldStepScore::HOLD_STEPPED_ON || score == HoldStepScore::HOLD_SCORE_OK )
2001-12-19 01:50:57 +00:00
fYPos = max( fYPos, GetGrayArrowYPos() );
if( m_PlayerOptions.m_bReverseScroll ) fYPos = SCREEN_HEIGHT - fYPos;
m_ColorArrow[iColNum].SetY( fYPos );
m_ColorArrow[iColNum].SetIndexAndBeat( i, m_fSongBeat );
D3DXCOLOR color( 0, 1, 0, 1 ); // color shifts from green to yellow
m_ColorArrow[iColNum].SetDiffuseColor( color );
2001-12-28 10:15:59 +00:00
float fAlpha = GetColorArrowAlphaFromYOffset( fYOffset );
2001-12-20 12:37:38 +00:00
m_ColorArrow[iColNum].SetAlpha( fAlpha );
2001-12-19 01:50:57 +00:00
m_ColorArrow[iColNum].Draw();
}
}
2001-11-28 20:26:45 +00:00
float Player::GetColorArrowYPos( int iStepIndex, float fSongBeat )
{
float fBeatsUntilStep = StepIndexToBeat( iStepIndex ) - fSongBeat;
2001-12-19 01:50:57 +00:00
float fYOffset = fBeatsUntilStep * ARROW_GAP * m_PlayerOptions.m_fArrowScrollSpeed;
switch( m_PlayerOptions.m_EffectType )
{
case PlayerOptions::EFFECT_BOOST:
fYOffset *= 1.4f / ((fYOffset+SCREEN_HEIGHT/1.6f)/SCREEN_HEIGHT);
break;
case PlayerOptions::EFFECT_WAVE:
2002-01-16 19:28:31 +00:00
fYOffset += 15.0f*(float)sin( fYOffset/38.0f );
2001-12-19 01:50:57 +00:00
break;
}
float fYPos = fYOffset + GRAY_ARROW_Y;
return fYPos;
}
2001-12-20 12:37:38 +00:00
float Player::GetColorArrowYOffset( int iStepIndex, float fSongBeat )
{
float fBeatsUntilStep = StepIndexToBeat( iStepIndex ) - fSongBeat;
float fYOffset = fBeatsUntilStep * ARROW_GAP * m_PlayerOptions.m_fArrowScrollSpeed;
switch( m_PlayerOptions.m_EffectType )
{
case PlayerOptions::EFFECT_BOOST:
fYOffset *= 1.4f / ((fYOffset+SCREEN_HEIGHT/1.6f)/SCREEN_HEIGHT);
break;
case PlayerOptions::EFFECT_WAVE:
2002-01-16 19:28:31 +00:00
fYOffset += 15.0f*(float)sin( fYOffset/38.0f );
2001-12-20 12:37:38 +00:00
break;
}
return fYOffset;
}
float Player::GetColorArrowAlphaFromYOffset( float fYOffset )
{
float fAlpha;
switch( m_PlayerOptions.m_AppearanceType )
{
case PlayerOptions::APPEARANCE_VISIBLE:
fAlpha = 1;
break;
case PlayerOptions::APPEARANCE_HIDDEN:
// fAlpha = m_PlayerOptions.m_bReverseScroll ? ((SCREEN_HEIGHT-(fYPos-200))/200) : ((fYPos-200)/200);
fAlpha = (fYOffset-100)/200;
break;
case PlayerOptions::APPEARANCE_SUDDEN:
// fAlpha = m_PlayerOptions.m_bReverseScroll ? ((SCREEN_HEIGHT-(fYPos+200))/200) : ((fYPos+200)/200);
fAlpha = ((SCREEN_HEIGHT-fYOffset)-280)/200;
break;
case PlayerOptions::APPEARANCE_STEALTH:
fAlpha = 0;
break;
};
if( fYOffset < 0 )
fAlpha = 1;
return fAlpha;
};
2001-12-19 01:50:57 +00:00
float Player::GetGrayArrowYPos()
{
return GRAY_ARROW_Y;
}
void Player::SetJudgementX( int iNewX )
{
2001-12-20 12:37:38 +00:00
// the frame will do this for us
//float fY = JUDGEMENT_Y;
//if( m_PlayerOptions.m_bReverseScroll ) fY = SCREEN_HEIGHT - fY;
//m_sprJudgement.SetXY( iNewX, fY );
2001-12-19 01:50:57 +00:00
2001-12-20 12:37:38 +00:00
float fY = HOLD_JUDGEMENT_Y;
2001-12-19 01:50:57 +00:00
if( m_PlayerOptions.m_bReverseScroll ) fY = SCREEN_HEIGHT - fY;
for( int c=0; c<MAX_NUM_COLUMNS; c++ )
{
m_sprHoldJudgement[c].SetXY( GetArrowColumnX(c), fY );
}
}
void Player::UpdateJudgement( float fDeltaTime )
{
2001-12-20 12:37:38 +00:00
m_fJudgementDisplayCountdown -= fDeltaTime;
if( m_fJudgementDisplayCountdown < 0 )
{
m_sprJudgement.SetDiffuseColor( D3DXCOLOR(1,1,1,0) ); // invisible
m_fJudgementDisplayCountdown = 0;
}
// m_sprJudgement.Update( fDeltaTime ); // the frame will take care of this for us.
2001-12-19 01:50:57 +00:00
for( int c=0; c<MAX_NUM_COLUMNS; c++ )
{
if( m_fHoldJudgementDisplayCountdown[c] > 0 )
m_fHoldJudgementDisplayCountdown[c] -= fDeltaTime;
m_sprHoldJudgement[c].Update( fDeltaTime );
}
}
void Player::DrawJudgement()
{
2001-12-20 12:37:38 +00:00
//if( m_fJudgementDisplayCountdown > 0.0 )
// m_sprJudgement.Draw(); // the frame will take care of this for us
2001-12-19 01:50:57 +00:00
for( int c=0; c<MAX_NUM_COLUMNS; c++ )
{
if( m_fHoldJudgementDisplayCountdown[c] > 0.0 )
m_sprHoldJudgement[c].Draw();
}
}
void Player::SetJudgement( StepScore score )
{
//RageLog( "Judgement::SetJudgement()" );
switch( score )
{
case perfect: m_sprJudgement.SetState( 0 ); break;
case great: m_sprJudgement.SetState( 1 ); break;
case good: m_sprJudgement.SetState( 2 ); break;
case boo: m_sprJudgement.SetState( 3 ); break;
case miss: m_sprJudgement.SetState( 4 ); break;
}
m_fJudgementDisplayCountdown = JUDGEMENT_DISPLAY_TIME;
2001-12-01 23:46:09 +00:00
if( score == miss ) { // falling down
2001-12-20 12:37:38 +00:00
m_sprJudgement.SetY( (m_PlayerOptions.m_bReverseScroll ? JUDGEMENT_Y_OFFSET : -JUDGEMENT_Y_OFFSET) - 30 );
2001-12-01 23:46:09 +00:00
m_sprJudgement.SetZoom( 1.0f );
2001-12-20 12:37:38 +00:00
m_sprJudgement.SetDiffuseColor( D3DXCOLOR(1,1,1,1) ); // visible
2001-12-01 23:46:09 +00:00
m_sprJudgement.BeginTweening( JUDGEMENT_DISPLAY_TIME );
2001-12-20 12:37:38 +00:00
m_sprJudgement.SetTweenY( (m_PlayerOptions.m_bReverseScroll ? JUDGEMENT_Y_OFFSET : -JUDGEMENT_Y_OFFSET) + 30 );
2001-12-01 23:46:09 +00:00
} else { // zooming out
2001-12-20 12:37:38 +00:00
m_sprJudgement.StopTweening();
m_sprJudgement.SetY( (m_PlayerOptions.m_bReverseScroll ? JUDGEMENT_Y_OFFSET : -JUDGEMENT_Y_OFFSET) );
m_sprJudgement.SetDiffuseColor( D3DXCOLOR(1,1,1,1) ); // visible
m_frameJudgementAndCombo.SetZoom( 1.35f );
2002-01-16 19:28:31 +00:00
m_frameJudgementAndCombo.BeginTweening( JUDGEMENT_DISPLAY_TIME/5.0f );
2001-12-20 12:37:38 +00:00
m_frameJudgementAndCombo.SetTweenZoom( 1.0f );
/* m_sprJudgement.SetZoom( 1.5f );
m_sprJudgement.SetDiffuseColor( D3DXCOLOR(1,1,1,1) ); // visible
2001-12-01 23:46:09 +00:00
m_sprJudgement.BeginTweening( JUDGEMENT_DISPLAY_TIME/3.0 );
m_sprJudgement.SetTweenZoom( 1.0f );
2001-12-20 12:37:38 +00:00
*/
2001-12-01 23:46:09 +00:00
}
}
2001-12-28 10:15:59 +00:00
void Player::SetHoldJudgement( int iCol, HoldStepScore::HoldScore score )
2001-12-19 01:50:57 +00:00
{
//RageLog( "Judgement::SetJudgement()" );
switch( score )
{
2001-12-28 10:15:59 +00:00
case HoldStepScore::HOLD_SCORE_NONE: m_sprHoldJudgement[iCol].SetState( 0 ); break; // freeze!
case HoldStepScore::HOLD_SCORE_OK: m_sprHoldJudgement[iCol].SetState( 7 ); break;
case HoldStepScore::HOLD_SCORE_NG: m_sprHoldJudgement[iCol].SetState( 8 ); break;
2001-12-19 01:50:57 +00:00
}
m_fHoldJudgementDisplayCountdown[iCol] = JUDGEMENT_DISPLAY_TIME;
2001-12-28 10:15:59 +00:00
if( score == HoldStepScore::HOLD_SCORE_NG ) { // falling down
2001-12-19 01:50:57 +00:00
float fY = HOLD_JUDGEMENT_Y;
if( m_PlayerOptions.m_bReverseScroll ) fY = SCREEN_HEIGHT - fY;
m_sprHoldJudgement[iCol].SetY( fY - 10 );
m_sprHoldJudgement[iCol].SetZoom( 1.0f );
m_sprHoldJudgement[iCol].BeginTweening( JUDGEMENT_DISPLAY_TIME );
2001-12-20 12:37:38 +00:00
m_sprHoldJudgement[iCol].SetTweenY( fY + 10 );
2001-12-19 01:50:57 +00:00
} else { // zooming out
float fY = HOLD_JUDGEMENT_Y;
if( m_PlayerOptions.m_bReverseScroll ) fY = SCREEN_HEIGHT - fY;
m_sprHoldJudgement[iCol].SetY( fY );
m_sprHoldJudgement[iCol].SetZoom( 1.5f );
2002-01-16 19:28:31 +00:00
m_sprHoldJudgement[iCol].BeginTweening( JUDGEMENT_DISPLAY_TIME/3.0f );
2001-12-19 01:50:57 +00:00
m_sprHoldJudgement[iCol].SetTweenZoom( 1.0f );
}
}
void Player::SetComboX( int iNewX )
{
2001-12-19 01:50:57 +00:00
float fY;
fY = COMBO_Y;
if( m_PlayerOptions.m_bReverseScroll ) fY = SCREEN_HEIGHT - fY;
2001-12-20 12:37:38 +00:00
//m_sprCombo.SetXY( iNewX+40, fY ); // the frame will do this for us
2002-01-16 10:01:32 +00:00
//m_textComboNumber.SetXY( iNewX-50, fY );
}
void Player::UpdateCombo( float fDeltaTime )
{
2001-12-20 12:37:38 +00:00
//m_sprCombo.Update( fDeltaTime ); // the frame will do this for us
2002-01-16 10:01:32 +00:00
//m_textComboNumber.Update( fDeltaTime ); // the frame will do this for us
}
void Player::DrawCombo()
{
2001-12-20 12:37:38 +00:00
// the frame will do this for us
// if( m_bComboVisible )
// {
2002-01-16 10:01:32 +00:00
// m_textComboNumber.Draw();
2001-12-20 12:37:38 +00:00
// m_sprCombo.Draw();
// }
}
2001-12-28 10:15:59 +00:00
void Player::ContinueCombo()
{
2001-12-28 10:15:59 +00:00
m_iCurCombo++;
2001-12-28 10:15:59 +00:00
// new max combo
if( m_iCurCombo > m_iMaxCombo )
m_iMaxCombo = m_iCurCombo;
2001-12-28 10:15:59 +00:00
if( m_iCurCombo <= 4 )
{
2002-01-16 10:01:32 +00:00
m_textComboNumber.SetDiffuseColor( D3DXCOLOR(1,1,1,0) ); // invisible
2001-12-20 12:37:38 +00:00
m_sprCombo.SetDiffuseColor( D3DXCOLOR(1,1,1,0) ); // invisible
}
else
{
2002-01-16 10:01:32 +00:00
m_textComboNumber.SetDiffuseColor( D3DXCOLOR(1,1,1,1) ); // visible
2001-12-20 12:37:38 +00:00
m_sprCombo.SetDiffuseColor( D3DXCOLOR(1,1,1,1) ); // visible
2002-01-16 10:01:32 +00:00
m_textComboNumber.SetText( ssprintf("%d", m_iCurCombo) );
2001-12-28 10:15:59 +00:00
float fNewZoom = 0.5f + m_iCurCombo/800.0f;
2002-01-16 10:01:32 +00:00
m_textComboNumber.SetZoom( fNewZoom );
m_textComboNumber.SetX( -40 - (fNewZoom-1)*30 );
m_textComboNumber.SetY( m_PlayerOptions.m_bReverseScroll ? -JUDGEMENT_Y_OFFSET : JUDGEMENT_Y_OFFSET );
2001-12-20 12:37:38 +00:00
2002-01-16 10:01:32 +00:00
//m_textComboNumber.BeginTweening( COMBO_TWEEN_TIME );
//m_textComboNumber.SetTweenZoom( 1 );
}
2001-12-28 10:15:59 +00:00
}
void Player::EndCombo()
{
m_iCurCombo = 0;
2002-01-16 10:01:32 +00:00
m_textComboNumber.SetDiffuseColor( D3DXCOLOR(1,1,1,0) ); // invisible
2001-12-28 10:15:59 +00:00
m_sprCombo.SetDiffuseColor( D3DXCOLOR(1,1,1,0) ); // invisible
}
void Player::SetLifeMeterX( int iNewX )
{
2002-01-16 19:28:31 +00:00
m_sprLifeMeterFrame.SetXY( (float)iNewX, LIFEMETER_Y );
m_sprLifeMeterPills.SetXY( (float)iNewX, LIFEMETER_PILLS_Y );
}
void Player::UpdateLifeMeter( float fDeltaTime )
{
m_sprLifeMeterFrame.Update( fDeltaTime );
m_sprLifeMeterPills.Update( fDeltaTime );
}
2001-11-28 20:26:45 +00:00
void Player::DrawLifeMeter()
{
2001-11-28 20:26:45 +00:00
float fBeatPercentage = m_fSongBeat - (int)m_fSongBeat;
int iOffsetStart = roundf( LIEFMETER_NUM_PILLS*fBeatPercentage );
m_sprLifeMeterFrame.Draw();
2001-11-28 20:26:45 +00:00
float iX = m_sprLifeMeterFrame.GetX() - m_sprLifeMeterFrame.GetZoomedWidth()/2 + 27;
int iNumPills = (int)(m_sprLifeMeterPills.GetNumStates() * m_fLifePercentage);
2002-01-16 19:28:31 +00:00
int iPillWidth = (int)m_sprLifeMeterPills.GetZoomedWidth();
for( int i=0; i<iNumPills; i++ )
{
m_sprLifeMeterPills.SetState( i );
m_sprLifeMeterPills.SetX( iX );
int iOffsetNum = (iOffsetStart - i + LIEFMETER_NUM_PILLS) % LIEFMETER_NUM_PILLS;
int iOffset = roundf( PILL_OFFSET_Y[iOffsetNum] * m_fLifePercentage * 8.0f );
m_sprLifeMeterPills.SetY( LIFEMETER_PILLS_Y - iOffset );
m_sprLifeMeterPills.Draw();
iX += iPillWidth;
}
}
void Player::ChangeLife( StepScore score )
{
switch( score )
{
case perfect: m_fLifePercentage += LIFE_PERFECT; break;
case great: m_fLifePercentage += LIFE_GREAT; break;
case good: m_fLifePercentage += LIFE_GOOD; break;
case boo: m_fLifePercentage += LIFE_BOO; break;
case miss: m_fLifePercentage += LIFE_MISS; break;
}
m_fLifePercentage = clamp( m_fLifePercentage, 0, 1 );
if( m_fLifePercentage == 1 )
m_sprLifeMeterFrame.SetEffectCamelion( 5, D3DXCOLOR(0.2f,0.2f,0.2f,1), D3DXCOLOR(1,1,1,1) );
else if( m_fLifePercentage < 0.25f )
m_sprLifeMeterFrame.SetEffectCamelion( 5, D3DXCOLOR(1,0.8f,0.8f,1), D3DXCOLOR(1,0.2f,0.2f,1) );
else
m_sprLifeMeterFrame.SetEffectNone();
}
void Player::SetScoreX( int iNewX )
{
2002-01-17 07:41:01 +00:00
m_sprScoreFrame.SetXY( iNewX, SCORE_Y );
m_ScoreDisplay.SetXY( iNewX, SCORE_Y );
}
void Player::UpdateScore( float fDeltaTime )
{
m_sprScoreFrame.Update( fDeltaTime );
2002-01-17 07:41:01 +00:00
m_ScoreDisplay.Update( fDeltaTime );
}
void Player::DrawScore()
{
2002-01-17 07:41:01 +00:00
m_ScoreDisplay.Draw();
m_sprScoreFrame.Draw();
}
void Player::ChangeScore( StepScore score, int iCurCombo )
{
// The scoring system for DDR versions 1 and 2 (including the Plus remixes) is as follows:
// For every step:
//
// Multiplier (M) = (# of steps in your current combo / 4) rounded down
// "Good" step = M * 100 (and this ends your combo)
// "Great" step = M * M * 100
// "Perfect" step = M * M * 300
//
// e.g. When you get a 259 combo, the 260th step will earn you:
//
// M = (260 / 4) rounded down
// = 65
// step = M x M X 100
// = 65 x 65 x 100
// = 422,500
// Perfect step = Great step score x 3
// = 422,500 x 3
// = 1,267,500
float M = iCurCombo/4.0f;
2001-11-28 20:26:45 +00:00
float fScoreToAdd = 0;
switch( score )
{
case miss: break;
case boo: break;
2001-11-28 20:26:45 +00:00
case good: fScoreToAdd = M * 100 + 100; break;
case great: fScoreToAdd = M * M * 100 + 300; break;
case perfect: fScoreToAdd = M * M * 300 + 500; break;
}
2001-11-28 20:26:45 +00:00
m_fScore += fScoreToAdd;
2001-12-01 23:46:09 +00:00
ASSERT( m_fScore >= 0 );
2002-01-17 07:41:01 +00:00
m_ScoreDisplay.SetScore( m_fScore );
2001-11-03 10:52:42 +00:00
}