Major rewrite of all classes related to gameplay (Song, Steps, Player,

WindowDancing and all its UI elements).  All of the dancing UI elements
have been consolidated into the Player class, which simplifies things a
great deal.  Steps and the classes that use them have been generalized
to use a variable number of panels (6 panel, 8 panel).  Only a little more
work is needed on the ColorArrows portion of Player to fully support these
panel modes.
This commit is contained in:
Chris Danford
2001-11-04 19:34:28 +00:00
parent 7caffe0c93
commit a40558031b
50 changed files with 1093 additions and 1092 deletions
+559 -162
View File
@@ -1,18 +1,19 @@
#include "stdafx.h"
//-----------------------------------------------------------------------------
// File: Player.cpp
//
// Desc: Object that accepts pad input, knocks down ColorArrows that were stepped on,
// and keeps score for the player.
//
// Copyright (c) 2001 Chris Danford. All rights reserved.
//-----------------------------------------------------------------------------
/*
-----------------------------------------------------------------------------
File: Player.cpp
Desc: Object that accepts pad input, knocks down ColorArrows that were stepped on,
and keeps score for the player.
#include "Util.h"
Copyright (c) 2001 Chris Danford. All rights reserved.
-----------------------------------------------------------------------------
*/
#include "ScreenDimensions.h"
#include "Math.h" // for fabs()
#include "Player.h"
#include "RageUtil.h"
@@ -23,220 +24,302 @@
#define SCORE_ADD_GOOD 200
#define SCORE_ADD_BOO 100
#define SCORE_MULT_PERFECT 1.007f
#define SCORE_MULT_GREAT 1.004f
#define SCORE_MULT_GOOD 1.002f
#define SCORE_MULT_BOO 1.001f
#define LIFE_PERFECT 0.015f
#define LIFE_GREAT 0.008f
#define LIFE_GOOD 0.000f
#define LIFE_BOO -0.015f
#define LIFE_MISS -0.060f
#define SPRITE_COLOR_ARROW_LEFT "Sprites\\Color Arrow Left.sprite"
#define SPRITE_COLOR_ARROW_DOWN "Sprites\\Color Arrow Down.sprite"
#define SPRITE_COLOR_ARROW_UP "Sprites\\Color Arrow Up.sprite"
#define SPRITE_COLOR_ARROW_RIGHT "Sprites\\Color Arrow Right.sprite"
void Player::Set( GrayArrows *pGA, ColorArrows *pCA,
Judgement *pJ, Combo *pC,
Score *pS, LifeMeter *pL,
Steps steps, FLOAT fMaxBeatDifference )
const int ARROW_X_OFFSET[4] = {
(int)(64*-1.5),
(int)(64*-0.5),
(int)(64* 0.5),
(int)(64* 1.5)
};
#define GRAY_ARROW_Y ((int)(64* 1.5))
#define GRAY_ARROW_POP_UP_TIME 0.30f
#define ARROW_HEIGHT 70
#define NUM_FRAMES_IN_COLOR_ARROW_SPRITE 12
const CString SPRITE_COLOR_ARROW[4] = {
"Sprites\\Color Arrow Left.sprite",
"Sprites\\Color Arrow Down.sprite",
"Sprites\\Color Arrow Up.sprite",
"Sprites\\Color Arrow Right.sprite"
};
const CString SPRITE_GRAY_ARROW[4] = {
"Sprites\\Gray Arrow Left.sprite",
"Sprites\\Gray Arrow Down.sprite",
"Sprites\\Gray Arrow Up.sprite",
"Sprites\\Gray Arrow Right.sprite"
};
#define JUDGEMENT_DISPLAY_TIME 1.0f
#define JUDGEMENT_SPRITE "Sprites\\Judgement.sprite"
#define JUDGEMENT_Y CENTER_Y
#define FONT_COMBO "Fonts\\Font - Arial Bold numbers 30px.font"
#define COMBO_TWEEN_TIME 0.5f
#define COMBO_SPRITE "Sprites\\Combo.sprite"
#define COMBO_Y (CENTER_Y+60)
#define LIEFMETER_NUM_PILLS 17
#define LIFEMETER_FRAME_SPRITE "Sprites\\Life Meter Frame.sprite"
#define LIFEMETER_PILLS_SPRITE "Sprites\\Life Meter Pills.sprite"
#define LIFEMETER_Y 30
#define LIFEMETER_PILLS_Y (LIFEMETER_Y+2)
const float PILL_OFFSET_Y[LIEFMETER_NUM_PILLS] = {
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
};
#define FONT_SCORE "Fonts\\Font - Arial Bold numbers 30px.font"
#define SCORE_FRAME_TEXTURE "Textures\\Score Frame 1x1.png"
#define SCORE_Y (480-40)
Player::Player()
{
RageLog( "Player::Set()" );
m_iCurCombo = 0;
m_iMaxCombo = 0;
m_fLifePercentage = 0.50f;
m_fScore = 0.0f;
m_pGA = pGA;
m_pCA = pCA;
m_pJudgement = pJ;
m_pCombo = pC;
m_pScore = pS;
m_pLifeMeter = pL;
if( m_pLifeMeter ) m_pLifeMeter->SetLife( m_fLife );
for( int i=0; i<MAX_STEP_ELEMENTS; i++ ) {
m_OriginalStep[i] = 0;
m_LeftToStepOn[i] = 0;
m_StepScore[i] = none;
}
m_Steps = steps;
// gray arrows
for( i=0; i<4; i++ )
{
m_sprGrayArrow[i].LoadFromSpriteFile( SPRITE_GRAY_ARROW[i] );
m_sprGrayArrowGhost[i].LoadFromSpriteFile( SPRITE_GRAY_ARROW[i] );
m_sprGrayArrowGhost[i].StopAnimating();
m_sprGrayArrowGhost[i].SetState( 1 );
m_sprGrayArrowGhost[i].SetColor( D3DXCOLOR(1,1,1,0) );
}
m_StepScore.SetSize( MAX_STEP_ELEMENTS );
for( int i=0; i<m_StepScore.GetSize(); i++ )
m_StepScore[i] = no_score;
// color arrows
for( i=0; i<4; i++ )
{
m_sprColorArrow[i].LoadFromSpriteFile( SPRITE_COLOR_ARROW[i] );
m_sprColorArrow[i].StopAnimating();
}
for( i=0; i<MAX_STEP_ELEMENTS; i++ )
m_iColorArrowFrameOffset[i] = 0;
m_fMaxBeatDifference = fMaxBeatDifference;
// judgement
m_fJudgementDisplayCountdown = 0;
m_sprJudgement.LoadFromSpriteFile( JUDGEMENT_SPRITE );
// combo
m_bComboVisible = FALSE;
m_sprCombo.LoadFromSpriteFile( COMBO_SPRITE );
m_textComboNum.LoadFromFontFile( FONT_COMBO );
m_textComboNum.SetText( "" );
// life meter
m_sprLifeMeterFrame.LoadFromSpriteFile( LIFEMETER_FRAME_SPRITE );
m_sprLifeMeterPills.LoadFromSpriteFile( LIFEMETER_PILLS_SPRITE );
// score
m_sprScoreFrame.LoadFromTexture( SCORE_FRAME_TEXTURE );
m_textScoreNum.LoadFromFontFile( FONT_SCORE );
m_textScoreNum.SetText( " " );
SetX( CENTER_X );
}
void Player::Update( const FLOAT &fDeltaTime )
void Player::SetX( int iX )
{
m_iArrowsCenterX = iX;
SetGrayArrowsX(iX);
SetColorArrowsX(iX);
SetJudgementX(iX);
SetComboX(iX);
SetScoreX(iX);
SetLifeMeterX(iX);
}
void Player::SetSteps( const Steps& newSteps )
{
for( int i=0; i<MAX_STEP_ELEMENTS; i++ ) {
m_OriginalStep[i] = newSteps.m_steps[i];
m_LeftToStepOn[i] = newSteps.m_steps[i];
m_iColorArrowFrameOffset[i] = (int)( i/(FLOAT)ELEMENTS_PER_BEAT*NUM_FRAMES_IN_COLOR_ARROW_SPRITE );
}
}
void Player::Update( const float &fDeltaTime, float fSongBeat, float fMaxBeatDifference )
{
//RageLog( "Player::Update(%f)", fDeltaTime );
for( int i=0; i<2; i++ ) {
for( int j=0; j<4; j++ ) {
if( m_fStepCountDown[i][j] > 0.0 )
m_fStepCountDown[i][j] -= fDeltaTime;
}
}
int iNumMisses = UpdateMissedStepsOlderThan( m_fSongBeat-m_fMaxBeatDifference );
int iNumMisses = UpdateStepsMissedOlderThan( fSongBeat-fMaxBeatDifference );
if( iNumMisses > 0 )
{
m_pJudgement->Miss();
SetJudgement( miss );
m_iCurCombo = 0;
m_pCombo->SetCombo( 0 );
m_fLife += LIFE_MISS * iNumMisses;
if( m_fLife < 0.0f )
m_fLife = 0.0f;
m_pLifeMeter->SetLife( m_fLife );
SetCombo( 0 );
for( int i=0; i<iNumMisses; i++ )
ChangeLife( miss );
}
UpdateGrayArrows( fDeltaTime );
UpdateColorArrows( fDeltaTime );
UpdateJudgement( fDeltaTime );
UpdateCombo( fDeltaTime );
UpdateScore( fDeltaTime );
UpdateLifeMeter( fDeltaTime );
}
void Player::StepOn( Step player_step )
void Player::Draw( float fSongBeat )
{
// DebugLog( CString("Player::Step() ") + padStepL.ToString() + CString(" ") + padStepR.ToString() );
// Fill the "step buffer" so that the player doesn't have to hit 2 buttons
// at the exact same time in order to hit a two direction step
if( player_step & STEP_P1_LEFT ) m_fStepCountDown[0][0] = STEP_DOWN_TIME;
if( player_step & STEP_P1_DOWN ) m_fStepCountDown[0][1] = STEP_DOWN_TIME;
if( player_step & STEP_P1_UP ) m_fStepCountDown[0][2] = STEP_DOWN_TIME;
if( player_step & STEP_P1_RIGHT ) m_fStepCountDown[0][3] = STEP_DOWN_TIME;
// make the gray foot steps on the screen follow the input
m_pGA->StepOn( player_step );
HandleStep();
DrawGrayArrows();
DrawColorArrows( fSongBeat );
DrawJudgement();
DrawCombo();
DrawScore();
DrawLifeMeter( fSongBeat );
}
void Player::HandleStep()
void Player::HandlePlayerStep( float fSongBeat, Step player_step, float fMaxBeatDiff )
{
//RageLog( "Player::HandleStep()" );
RageLog( "Player::HandlePlayerStep()" );
// This is being called just after a step, so we know at
// least one direction is being depressed.
// update gray arrows
if( player_step & STEP_P1_LEFT ) GrayArrowStep( 0 );
if( player_step & STEP_P1_DOWN ) GrayArrowStep( 1 );
if( player_step & STEP_P1_UP ) GrayArrowStep( 2 );
if( player_step & STEP_P1_RIGHT ) GrayArrowStep( 3 );
// Build pad steps to check against
Step player_step = 0x0000;
if( m_fStepCountDown[0][0] > 0.0f ) player_step |= STEP_P1_LEFT;
if( m_fStepCountDown[0][1] > 0.0f ) player_step |= STEP_P1_DOWN;
if( m_fStepCountDown[0][2] > 0.0f ) player_step |= STEP_P1_UP;
if( m_fStepCountDown[0][3] > 0.0f ) player_step |= STEP_P1_RIGHT;
CheckForCompleteStep( fSongBeat, player_step, fMaxBeatDiff );
}
void Player::CheckForCompleteStep( float fSongBeat, Step player_step, float fMaxBeatDiff )
{
RageLog( "Player::CheckForCompleteStep()" );
// look for the closest matching step
int iIndexStartLookingAt = BeatToStepIndex( fSongBeat );
int iNumElementsToExamine = BeatToStepIndex( fMaxBeatDiff ); // number of elements to examine on either end of iIndexStartLookingAt
// find the closest step that our PadSteps cover
//RageLog( "I ask: What step %s, %s, is near %f (within %f )",
// padStepL.ToString(),
// padStepR.ToString(),
// m_fSongBeat,
// MAX_BEAT_DIFFERENCE );
RageLog( "iIndexStartLookingAt = %d, iNumElementsToExamine = %d", iIndexStartLookingAt, iNumElementsToExamine );
int iIndexOfClosest =
m_Steps.GetIndexOfClosestStep( m_fSongBeat,
m_fMaxBeatDifference,
player_step );
// 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;
if( iIndexOfClosest == -1 ) // if no steps in our specified range are covered
return;
// 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 );
FLOAT fStepBeat = StepIndexToBeat( iIndexOfClosest ); // this is the beat of the note we stepped on
////////////////////////////
// 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;
}
}
//RageLog( "GetClosestMatch returned: iIndexOfClosest = %d (%s, %s, fStepBeat: %f)",
// iIndexOfClosest,
// m_Steps.StepsLeft [iIndexOfClosest].ToString(),
// m_Steps.StepsRight[iIndexOfClosest].ToString(),
// fStepBeat );
////////////////////////////
// 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;
}
}
}
}
void Player::OnCompleteStep( float fSongBeat, Step player_step, float fMaxBeatDiff, int iIndexThatWasSteppedOn )
{
float fStepBeat = StepIndexToBeat( iIndexThatWasSteppedOn );
FLOAT fBeatsUntilStep = fStepBeat - m_fSongBeat;
FLOAT fPercentFromPerfect = (FLOAT)fabs( fBeatsUntilStep / m_fMaxBeatDifference );
// show the gray arrow ghost
if( player_step & STEP_P1_LEFT ) GrayArrowGhostStep( 0 );
if( player_step & STEP_P1_DOWN ) GrayArrowGhostStep( 1 );
if( player_step & STEP_P1_UP ) GrayArrowGhostStep( 2 );
if( player_step & STEP_P1_RIGHT ) GrayArrowGhostStep( 3 );
float fBeatsUntilStep = fStepBeat - fSongBeat;
float fPercentFromPerfect = (float)fabs( fBeatsUntilStep / fMaxBeatDiff );
RageLog( "fBeatsUntilStep: %f, fPercentFromPerfect: %f",
fBeatsUntilStep, fPercentFromPerfect );
// step on the note so that it can't be stepped on any more
m_Steps.StatusArray[iIndexOfClosest] = stepped_on;
// compute what the score should be for the note we stepped on
StepScore &score = m_StepScore[iIndexOfClosest];
StepScore &score = m_StepScore[iIndexThatWasSteppedOn];
if( fPercentFromPerfect < 0.20f )
score = perfect;
else if( fPercentFromPerfect < 0.45f )
score = great;
else if( fPercentFromPerfect < 0.75f )
score = good;
else
score = boo;
if( fPercentFromPerfect < 0.20f ) score = perfect;
else if( fPercentFromPerfect < 0.45f ) score = great;
else if( fPercentFromPerfect < 0.75f ) score = good;
else score = boo;
// update the judgement display
switch( score )
{
case perfect: m_pJudgement->Perfect(); break;
case great: m_pJudgement->Great(); break;
case good: m_pJudgement->Good(); break;
case boo: m_pJudgement->Boo(); break;
}
// update the judgement, score, and life
SetJudgement( score );
ChangeScore( score );
ChangeLife( score );
// update the combo display
switch( score )
{
case perfect:
case great:
m_iCurCombo++;
m_pCombo->SetCombo( m_iCurCombo );
SetCombo( m_iCurCombo+1 ); // combo continuing
break;
case good:
case boo:
// combo stopped
if( m_iCurCombo > m_iMaxCombo )
m_iMaxCombo = m_iCurCombo;
m_iCurCombo = 0;
m_pCombo->SetCombo( m_iCurCombo );
SetCombo( 0 ); // combo stopped
break;
}
// remove the arrows from the ColorArrow columns if the score is high enough
if( score == perfect || score == great )
{
m_pCA->StepOn( BeatToStepIndex(fStepBeat) );
}
// update running score
switch( score )
{
case perfect: m_fScore += SCORE_ADD_PERFECT; m_fScore *= SCORE_MULT_PERFECT; break;
case great: m_fScore += SCORE_ADD_GREAT; m_fScore *= SCORE_MULT_GREAT; break;
case good: m_fScore += SCORE_ADD_GOOD; m_fScore *= SCORE_MULT_GOOD; break;
case boo: m_fScore += SCORE_ADD_BOO; m_fScore *= SCORE_MULT_BOO; break;
case miss: break;
}
// update life meter
switch( score )
{
case perfect: m_fLife += LIFE_PERFECT; break;
case great: m_fLife += LIFE_GREAT; break;
case good: m_fLife += LIFE_GOOD; break;
case boo: m_fLife += LIFE_BOO; break;
}
if( m_fLife < 0.0f ) m_fLife = 0.0f;
else if( m_fLife > 1.0f ) m_fLife = 1.0f;
m_pScore->SetScore( m_fScore );
m_pLifeMeter->SetLife( m_fLife );
}
int Player::UpdateMissedStepsOlderThan( FLOAT iMissIfOlderThanThisBeat )
{
//RageLog( "Steps::UpdateMissedStepsOlderThan(%f)", iMissIfOlderThanThisBeat );
int iMissIfOlderThanThisIndex = BeatToStepIndex( iMissIfOlderThanThisBeat );
int Player::UpdateStepsMissedOlderThan( float fMissIfOlderThanThisBeat )
{
//RageLog( "Steps::UpdateStepsMissedOlderThan(%f)", fMissIfOlderThanThisBeat );
int iMissIfOlderThanThisIndex = BeatToStepIndex( fMissIfOlderThanThisBeat );
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 );
for( int i=0; i<iMissIfOlderThanThisIndex; i++ )
for( int i=iStartCheckingAt; i<iMissIfOlderThanThisIndex; i++ )
{
// RageLog( "Step %d: status == %d, score == %d", i, StatusArray[i], Score[i] );
if( m_Steps.StatusArray[i] == not_stepped_on && m_StepScore[i] == no_score )
if( m_LeftToStepOn[i] != 0 )
{
m_StepScore[i] = miss;
iNumMissesFound++;
@@ -251,7 +334,7 @@ ScoreSummary Player::GetScoreSummary()
{
ScoreSummary scoreSummary;
for( int i=0; i<m_StepScore.GetSize(); i++ )
for( int i=0; i<MAX_STEP_ELEMENTS; i++ )
{
switch( m_StepScore[i] )
{
@@ -260,11 +343,325 @@ ScoreSummary Player::GetScoreSummary()
case good: scoreSummary.good++; break;
case boo: scoreSummary.boo++; break;
case miss: scoreSummary.miss++; break;
case no_score: break;
case none: break;
}
}
scoreSummary.max_combo = m_iMaxCombo;
scoreSummary.score = m_fScore;
return scoreSummary;
}
void Player::UpdateGrayArrows( const float &fDeltaTime )
{
for( int i=0; i<4; i++ )
m_sprGrayArrow[i].Update( fDeltaTime );
for( i=0; i<4; i++ )
m_sprGrayArrowGhost[i].Update( fDeltaTime );
}
void Player::DrawGrayArrows()
{
for( int i=0; i<4; i++ )
m_sprGrayArrow[i].Draw();
}
void Player::SetGrayArrowsX( int iNewX )
{
for( int i=0; i<4; i++ )
m_sprGrayArrow[i].SetXY( iNewX + ARROW_X_OFFSET[i], GRAY_ARROW_Y );
}
void Player::SetColorArrowsX( int iNewX )
{
}
void Player::GrayArrowStep( int index )
{
m_sprGrayArrow[index].SetZoom( 0.50 );
m_sprGrayArrow[index].TweenTo( GRAY_ARROW_POP_UP_TIME,
m_sprGrayArrow[index].GetX(),
m_sprGrayArrow[index].GetY(),
1.0f );
}
void Player::GrayArrowGhostStep( int index )
{
m_sprGrayArrowGhost[index].SetXY( m_iArrowsCenterX + ARROW_X_OFFSET[index], GRAY_ARROW_Y );
m_sprGrayArrowGhost[index].SetZoom( 1 );
m_sprGrayArrowGhost[index].SetColor( D3DXCOLOR(1,1,0.5f,1) );
m_sprGrayArrowGhost[index].SetTweening( 0.3f );
m_sprGrayArrowGhost[index].SetTweenZoom( 1.5 );
m_sprGrayArrowGhost[index].SetTweenColor( D3DXCOLOR(1,1,0.5f,0) );
}
void Player::UpdateColorArrows( const float &fDeltaTime )
{
}
void Player::DrawColorArrows( float fSongBeat )
{
//RageLog( "ColorArrows::Draw(%f)", fSongBeat );
int iBaseFrameNo = (int)(fSongBeat*2.5) % 12; // 2.5 is a "fudge number" :-) This should be based on BPM
int iIndexFirstArrowToDraw = BeatToStepIndex( fSongBeat - 2.0f ); // 2 beats earlier
if( iIndexFirstArrowToDraw < 0 ) iIndexFirstArrowToDraw = 0;
int iIndexLastArrowToDraw = BeatToStepIndex( fSongBeat + 7.0f ); // 7 beats later
//RageLog( "Drawing elements %d through %d", iIndexFirstArrowToDraw, iIndexLastArrowToDraw );
for( int i=iIndexFirstArrowToDraw; i<=iIndexLastArrowToDraw; i++ )
{
if( m_LeftToStepOn[i] != 0 ) // if there is a step here and it hasn't been stepped
{
int iYPos = GetColorArrowYPos( i, fSongBeat );
// calculate which frame to display
int iFrameNo = iBaseFrameNo + m_iColorArrowFrameOffset[i];
iFrameNo = iFrameNo % NUM_FRAMES_IN_COLOR_ARROW_SPRITE;
//RageLog( "iYPos: %d, iFrameNo: %d, m_OriginalStep[i]: %d", iYPos, iFrameNo, m_OriginalStep[i] );
if( m_OriginalStep[i] & STEP_P1_LEFT )
{
//RageLog( "Draw a left arrow at %d, %d", m_iArrowsCenterX + ARROW_X_OFFSET[0], iYPos );
m_sprColorArrow[0].SetXY( m_iArrowsCenterX + ARROW_X_OFFSET[0], iYPos );
m_sprColorArrow[0].SetState( iFrameNo );
m_sprColorArrow[0].Draw();
}
if( m_OriginalStep[i] & STEP_P1_DOWN )
{
m_sprColorArrow[1].SetXY( m_iArrowsCenterX + ARROW_X_OFFSET[1], iYPos );
m_sprColorArrow[1].SetState( iFrameNo );
m_sprColorArrow[1].Draw();
}
if( m_OriginalStep[i] & STEP_P1_UP )
{
m_sprColorArrow[2].SetXY( m_iArrowsCenterX + ARROW_X_OFFSET[2], iYPos );
m_sprColorArrow[2].SetState( iFrameNo );
m_sprColorArrow[2].Draw();
}
if( m_OriginalStep[i] & STEP_P1_RIGHT )
{
m_sprColorArrow[3].SetXY( m_iArrowsCenterX + ARROW_X_OFFSET[3], iYPos );
m_sprColorArrow[3].SetState( iFrameNo );
m_sprColorArrow[3].Draw();
}
} // end if there is a step
} // end foreach arrow to draw
for( i=0; i<4; i++ )
{
m_sprGrayArrowGhost[i].Draw();
}
}
int Player::GetColorArrowYPos( int iStepIndex, float fSongBeat )
{
float fBeatsUntilStep = StepIndexToBeat( iStepIndex ) - fSongBeat;
return (int)(fBeatsUntilStep * ARROW_HEIGHT) + GRAY_ARROW_Y;
}
void Player::SetJudgementX( int iNewX )
{
m_sprJudgement.SetXY( iNewX, CENTER_Y );
}
void Player::UpdateJudgement( const float &fDeltaTime )
{
if( m_fJudgementDisplayCountdown > 0.0 )
m_fJudgementDisplayCountdown -= fDeltaTime;
m_sprJudgement.Update( fDeltaTime );
}
void Player::DrawJudgement()
{
if( m_fJudgementDisplayCountdown > 0.0 )
m_sprJudgement.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;
m_sprJudgement.SetZoom( 1.5f );
m_sprJudgement.TweenTo( JUDGEMENT_DISPLAY_TIME/2.0,
m_sprJudgement.GetX(),
m_sprJudgement.GetY() );
}
void Player::SetComboX( int iNewX )
{
m_sprCombo.SetXY( iNewX+40, COMBO_Y );
m_textComboNum.SetXY( iNewX-50, COMBO_Y );
}
void Player::UpdateCombo( const float &fDeltaTime )
{
m_sprCombo.Update( fDeltaTime );
m_textComboNum.Update( fDeltaTime );
}
void Player::DrawCombo()
{
if( m_bComboVisible )
{
m_textComboNum.Draw();
m_sprCombo.Draw();
}
}
void Player::SetCombo( int iNewCombo )
{
// new max combo
if( iNewCombo > m_iMaxCombo )
m_iMaxCombo = iNewCombo;
m_iCurCombo = iNewCombo;
if( iNewCombo <= 4 )
{
m_bComboVisible = FALSE;
}
else
{
m_bComboVisible = TRUE;
m_textComboNum.SetText( ssprintf("%d", iNewCombo) );
m_textComboNum.SetZoom( 1.0f + iNewCombo/200.0f );
m_textComboNum.TweenTo( COMBO_TWEEN_TIME, m_textComboNum.GetX(), m_textComboNum.GetY() );
}
}
void Player::SetLifeMeterX( int iNewX )
{
m_sprLifeMeterFrame.SetXY( iNewX, LIFEMETER_Y );
m_sprLifeMeterPills.SetXY( iNewX, LIFEMETER_PILLS_Y );
}
void Player::UpdateLifeMeter( const float &fDeltaTime )
{
m_sprLifeMeterFrame.Update( fDeltaTime );
m_sprLifeMeterPills.Update( fDeltaTime );
}
void Player::DrawLifeMeter( float fSongBeat )
{
float fBeatPercentage = fSongBeat - (int)fSongBeat;
int iOffsetStart = roundf( LIEFMETER_NUM_PILLS*fBeatPercentage );
m_sprLifeMeterFrame.Draw();
float iX = m_sprLifeMeterFrame.GetLeftEdge() + 27;
int iNumPills = (int)(m_sprLifeMeterPills.GetNumStates() * m_fLifePercentage);
int iPillWidth = 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;
}
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 )
{
m_sprScoreFrame.SetXY( iNewX, SCORE_Y );
m_textScoreNum.SetXY( iNewX, SCORE_Y );
}
void Player::UpdateScore( const float &fDeltaTime )
{
m_sprScoreFrame.Update( fDeltaTime );
m_textScoreNum.Update( fDeltaTime );
}
void Player::DrawScore()
{
m_textScoreNum.Draw();
m_sprScoreFrame.Draw();
}
void Player::ChangeScore( StepScore score )
{
int iScoreToAdd;
switch( score )
{
case perfect: iScoreToAdd = SCORE_ADD_PERFECT; break;
case great: iScoreToAdd = SCORE_ADD_GREAT; break;
case good: iScoreToAdd = SCORE_ADD_GOOD; break;
case boo: iScoreToAdd = SCORE_ADD_BOO; break;
case miss: break;
}
m_fScore += iScoreToAdd * (1 + m_iCurCombo/200.0f);
// multiply the combo bonus
//m_fScore *= SCORE_MULT_BOO;
m_textScoreNum.SetText( ssprintf( "%9.0f", m_fScore ) );
}