add abstract scoring

(Got tired of having to search for the scoring stuff in Player ...)
This commit is contained in:
Glenn Maynard
2002-11-03 07:17:03 +00:00
parent 64499909d5
commit 576b9e393f
8 changed files with 226 additions and 76 deletions
+20 -67
View File
@@ -21,6 +21,7 @@
#include "InputMapper.h" #include "InputMapper.h"
#include "SongManager.h" #include "SongManager.h"
#include "GameState.h" #include "GameState.h"
#include "ScoreKeeperMAX2.h"
#include "RageLog.h" #include "RageLog.h"
#include "RageMath.h" #include "RageMath.h"
@@ -80,6 +81,7 @@ Player::Player()
m_pLifeMeter = NULL; m_pLifeMeter = NULL;
m_pScore = NULL; m_pScore = NULL;
m_ScoreKeeper = NULL;
m_iOffsetSample = 0; m_iOffsetSample = 0;
@@ -98,6 +100,12 @@ Player::Player()
} }
Player::~Player()
{
delete m_ScoreKeeper;
}
void Player::Load( PlayerNumber pn, NoteData* pNoteData, LifeMeter* pLM, ScoreDisplay* pScore ) void Player::Load( PlayerNumber pn, NoteData* pNoteData, LifeMeter* pLM, ScoreDisplay* pScore )
{ {
//LOG->Trace( "Player::Load()", ); //LOG->Trace( "Player::Load()", );
@@ -123,13 +131,8 @@ void Player::Load( PlayerNumber pn, NoteData* pNoteData, LifeMeter* pLM, ScoreDi
// m_Combo.Reset(); // don't reset combos between songs in a course! // m_Combo.Reset(); // don't reset combos between songs in a course!
m_Judgement.Reset(); m_Judgement.Reset();
m_iNumTapNotes = pNoteData->GetNumTapNotes(); if(m_ScoreKeeper) delete m_ScoreKeeper;
m_iTapNotesHit = 0; m_ScoreKeeper = new ScoreKeeperMAX2(GAMESTATE->m_pCurNotes[m_PlayerNumber], *this, pn);
m_lScore = 0;
m_iMeter = GAMESTATE->m_pCurNotes[m_PlayerNumber] ? GAMESTATE->m_pCurNotes[m_PlayerNumber]->m_iMeter : 5;
m_fScoreMultiplier = float(m_iMeter * 1000000) / float ((m_iNumTapNotes * (m_iNumTapNotes + 1)) / 2);
ASSERT(m_fScoreMultiplier >= 0.0);
if( m_pScore ) if( m_pScore )
m_pScore->Init( pn ); m_pScore->Init( pn );
@@ -257,7 +260,7 @@ void Player::Update( float fDeltaTime )
if( bSteppedOnTapNote && fLife == 0 ) // the player has not pressed the button for a long time! if( bSteppedOnTapNote && fLife == 0 ) // the player has not pressed the button for a long time!
{ {
hns = HNS_NG; hns = HNS_NG;
HandleNoteScore( hns, tns ); HandleHoldNoteScore( hns, tns );
m_HoldJudgement[hn.m_iTrack].SetHoldJudgement( HNS_NG ); m_HoldJudgement[hn.m_iTrack].SetHoldJudgement( HNS_NG );
m_NoteField.m_HoldNoteScores[i] = HNS_NG; // update the NoteField display m_NoteField.m_HoldNoteScores[i] = HNS_NG; // update the NoteField display
} }
@@ -267,7 +270,7 @@ void Player::Update( float fDeltaTime )
{ {
fLife = 1; fLife = 1;
hns = HNS_OK; hns = HNS_OK;
HandleNoteScore( hns, tns ); HandleHoldNoteScore( hns, tns );
m_GhostArrowRow.TapNote( StyleI.col, TNS_PERFECT, true ); // bright ghost flash m_GhostArrowRow.TapNote( StyleI.col, TNS_PERFECT, true ); // bright ghost flash
m_HoldJudgement[hn.m_iTrack].SetHoldJudgement( HNS_OK ); m_HoldJudgement[hn.m_iTrack].SetHoldJudgement( HNS_OK );
m_NoteField.m_fHoldNoteLife[i] = fLife; // update the NoteField display m_NoteField.m_fHoldNoteLife[i] = fLife; // update the NoteField display
@@ -576,80 +579,30 @@ void Player::CrossedRow( int iNoteRow )
void Player::HandleNoteScore( TapNoteScore score, int iNumTapsInRow ) void Player::HandleNoteScore( TapNoteScore score, int iNumTapsInRow )
{ {
printf("SCORE 1\n");
ASSERT( iNumTapsInRow >= 1 ); ASSERT( iNumTapsInRow >= 1 );
// don't accumulate points if AutoPlay is on. // don't accumulate points if AutoPlay is on.
if( PREFSMAN->m_bAutoPlay && !GAMESTATE->m_bDemonstration ) if( PREFSMAN->m_bAutoPlay && !GAMESTATE->m_bDemonstration )
return; return;
// update dance points for Oni lifemeter if(m_ScoreKeeper)
GAMESTATE->m_iActualDancePoints[m_PlayerNumber] += iNumTapsInRow * TapNoteScoreToDancePoints( score ); m_ScoreKeeper->HandleNoteScore(score, iNumTapsInRow);
GAMESTATE->m_TapNoteScores[m_PlayerNumber][score] += iNumTapsInRow;
if( m_pLifeMeter )
m_pLifeMeter->ChangeLife( score );
if( m_pLifeMeter )
m_pLifeMeter->OnDancePointsChange(); // update oni life meter
//A single step's points are calculated as follows:
//
//p = score multiplier (Perfect = 10, Great = 5, other = 0)
//N = total number of steps and freeze steps
//S = The sum of all integers from 1 to N (the total number of steps/freeze steps)
//n = number of the current step or freeze step (varies from 1 to N)
//B = Base value of the song (1,000,000 X the number of feet difficulty) - All edit data is rated as 5 feet
//So, the score for one step is:
//one_step_score = p * (B/S) * n
//
//*IMPORTANT* : Double steps (U+L, D+R, etc.) count as two steps instead of one, so if you get a double L+R on the 112th step of a song, you score is calculated with a Perfect/Great/whatever for both the 112th and 113th steps. Got it? Now, through simple algebraic manipulation
//S = 1+...+N = (1+N)*N/2 (1 through N added together)
//Okay, time for an example:
//
//So, for example, suppose we wanted to calculate the step score of a "Great" on the 57th step of a 441 step, 8-foot difficulty song (I'm just making this one up):
//
//S = (1 + 441)*441 / 2
//= 194,222 / 2
//= 97,461
//StepScore = p * (B/S) * n
//= 5 * (8,000,000 / 97,461) * 57
//= 5 * (82) * 57 (The 82 is rounded down from 82.08411...)
//= 23,370
//Remember this is just the score for the step, not the cumulative score up to the 57th step. Also, please note that I am currently checking into rounding errors with the system and if there are any, how they are resolved in the system.
//
//Note: if you got all Perfect on this song, you would get (p=10)*B, which is 80,000,000. In fact, the maximum possible score for any song is the number of feet difficulty X 10,000,000.
//3dfsux:
//I redid this code so it will store the score as a long, then correct the score for each song based on that value.
// lScore == p * n
// m_fScoreMultiplier = (B/S)
// keeping these seperate for as long as possible improves accuracy.
int p; // score multiplier
switch( score )
{
case TNS_PERFECT: p = 10; break;
case TNS_GREAT: p = 5; break;
default: p = 0; break;
}
for( int i=0; i<iNumTapsInRow; i++ )
m_lScore += p * ++m_iTapNotesHit;
ASSERT(m_lScore >= 0);
if (m_pScore) if (m_pScore)
m_pScore->SetScore(GAMESTATE->m_fScore[m_PlayerNumber] = m_lScore * m_fScoreMultiplier); m_pScore->SetScore(GAMESTATE->m_fScore[m_PlayerNumber]);
} }
void Player::HandleNoteScore( HoldNoteScore score, TapNoteScore TapNoteScore ) void Player::HandleHoldNoteScore( HoldNoteScore score, TapNoteScore TapNoteScore )
{ {
// don't accumulate points if AutoPlay is on. // don't accumulate points if AutoPlay is on.
if( PREFSMAN->m_bAutoPlay && !GAMESTATE->m_bDemonstration ) if( PREFSMAN->m_bAutoPlay && !GAMESTATE->m_bDemonstration )
return; return;
// update dance points totals if(m_ScoreKeeper) {
GAMESTATE->m_iActualDancePoints[m_PlayerNumber] += HoldNoteScoreToDancePoints( score ); m_ScoreKeeper->HandleHoldNoteScore(score, TapNoteScore);
GAMESTATE->m_HoldNoteScores[m_PlayerNumber][score] ++; }
if( m_pLifeMeter ) { if( m_pLifeMeter ) {
if( score == HNS_NG ) { if( score == HNS_NG ) {
+4 -8
View File
@@ -31,6 +31,7 @@
#include "GrayArrowRow.h" #include "GrayArrowRow.h"
#include "GhostArrowRow.h" #include "GhostArrowRow.h"
#include "NoteDataWithScoring.h" #include "NoteDataWithScoring.h"
#include "ScoreKeeper.h"
#define SAMPLE_COUNT 16 #define SAMPLE_COUNT 16
@@ -41,6 +42,7 @@ public:
virtual void Update( float fDeltaTime ); virtual void Update( float fDeltaTime );
virtual void DrawPrimitives(); virtual void DrawPrimitives();
~Player();
void Load( PlayerNumber player_no, NoteData* pNoteData, LifeMeter* pLM, ScoreDisplay* pScore ); void Load( PlayerNumber player_no, NoteData* pNoteData, LifeMeter* pLM, ScoreDisplay* pScore );
void CrossedRow( int iNoteRow ); void CrossedRow( int iNoteRow );
@@ -53,18 +55,12 @@ protected:
int UpdateTapNotesMissedOlderThan( float fMissIfOlderThanThisBeat ); int UpdateTapNotesMissedOlderThan( float fMissIfOlderThanThisBeat );
void OnRowDestroyed( int iStepIndex ); void OnRowDestroyed( int iStepIndex );
void HandleNoteScore( TapNoteScore score, int iNumTapsInRow ); void HandleNoteScore( TapNoteScore score, int iNumTapsInRow );
void HandleNoteScore( HoldNoteScore score, TapNoteScore TapNoteScore ); void HandleHoldNoteScore( HoldNoteScore score, TapNoteScore TapNoteScore );
static float GetMaxBeatDifference(); static float GetMaxBeatDifference();
PlayerNumber m_PlayerNumber; PlayerNumber m_PlayerNumber;
int m_iNumTapNotes; // num of TapNotes for the current notes needed by scoring
int m_iTapNotesHit; // number of notes judged so far, needed by scoring
int m_iMeter; // meter of current steps, needed by scoring
long m_lScore;
float m_fScoreMultiplier;
float m_fOffset[SAMPLE_COUNT];//for AutoAdjust float m_fOffset[SAMPLE_COUNT];//for AutoAdjust
int m_iOffsetSample; // int m_iOffsetSample; //
@@ -82,5 +78,5 @@ protected:
LifeMeter* m_pLifeMeter; LifeMeter* m_pLifeMeter;
ScoreDisplay* m_pScore; ScoreDisplay* m_pScore;
ScoreKeeper* m_ScoreKeeper;
}; };
+3
View File
@@ -0,0 +1,3 @@
#include "stdafx.h"
#include "ScoreKeeper.h"
+42
View File
@@ -0,0 +1,42 @@
#ifndef SCOREKEEPER_H
#define SCOREKEEPER_H 1
/*
-----------------------------------------------------------------------------
Class: ScoreKeeper
Abstract class to handle scorekeeping, stat-taking, etc.
Stat handling is in here because that can differ between games, too; for
example, some games count double taps as a single note in scoring and
some count per-tap.
Results are injected directly into GameState.
Copyright (c) 2001-2002 by the person(s) listed below. All rights reserved.
Chris Danford
Glenn Maynard
-----------------------------------------------------------------------------
*/
#include "Actor.h"
#include "NoteData.h"
class ScoreKeeper: public Actor {
protected:
int m_PlayerNumber;
/* Common toggles that this class handles directly: */
/* If true, doubles count as 2+ in stat counts; if false, doubles count as
* only one. */ /* (not yet) */
// bool Stats_DoublesCount;
public:
ScoreKeeper(int pn) { m_PlayerNumber=pn; }
virtual void DrawPrimitives() { }
virtual void HandleNoteScore( TapNoteScore score, int iNumTapsInRow ) { }
virtual void HandleHoldNoteScore( HoldNoteScore score, TapNoteScore TapNoteScore ) { }
};
#endif
+95
View File
@@ -0,0 +1,95 @@
#include "stdafx.h"
#include "ScoreKeeperMAX2.h"
#include "GameState.h"
ScoreKeeperMAX2::ScoreKeeperMAX2(Notes *notes, NoteDataWithScoring &data, int pn_):
ScoreKeeper(pn_)
{
// Stats_DoublesCount = true;
int Meter = notes? notes->m_iMeter : 5;
int m_iNumTapNotes = data.GetNumTapNotes();
int sum = (m_iNumTapNotes * (m_iNumTapNotes + 1)) / 2;
if(sum)
m_fScoreMultiplier = float(Meter * 1000000) / sum;
else /* avoid div/0 on empty songs */
m_fScoreMultiplier = 0.f;
ASSERT(m_fScoreMultiplier >= 0.0);
m_iTapNotesHit = 0;
m_lScore = 0;
}
void ScoreKeeperMAX2::HandleNoteScore( TapNoteScore score, int iNumTapsInRow )
{
ScoreKeeper::HandleNoteScore(score, iNumTapsInRow);
ASSERT( iNumTapsInRow >= 1 );
// update dance points for Oni lifemeter
GAMESTATE->m_iActualDancePoints[m_PlayerNumber] += iNumTapsInRow * TapNoteScoreToDancePoints( score );
GAMESTATE->m_TapNoteScores[m_PlayerNumber][score] += iNumTapsInRow;
/*
A single step's points are calculated as follows:
p = score multiplier (Perfect = 10, Great = 5, other = 0)
N = total number of steps and freeze steps
S = The sum of all integers from 1 to N (the total number of steps/freeze steps)
n = number of the current step or freeze step (varies from 1 to N)
B = Base value of the song (1,000,000 X the number of feet difficulty) - All edit data is rated as 5 feet
So, the score for one step is:
one_step_score = p * (B/S) * n
*IMPORTANT* : Double steps (U+L, D+R, etc.) count as two steps instead of one, so
if you get a double L+R on the 112th step of a song, you score is calculated with a
Perfect/Great/whatever for both the 112th and 113th steps. Got it? Now, through simple
algebraic manipulation
S = 1+...+N = (1+N)*N/2 (1 through N added together)
Okay, time for an example:
So, for example, suppose we wanted to calculate the step score of a "Great" on the 57th step of a 441 step, 8-foot difficulty song (I'm just making this one up):
S = (1 + 441)*441 / 2
= 194,222 / 2
= 97,461
StepScore = p * (B/S) * n
= 5 * (8,000,000 / 97,461) * 57
= 5 * (82) * 57 (The 82 is rounded down from 82.08411...)
= 23,370
Remember this is just the score for the step, not the cumulative score up to the 57th step. Also, please note that I am currently checking into rounding errors with the system and if there are any, how they are resolved in the system.
Note: if you got all Perfect on this song, you would get (p=10)*B, which is 80,000,000. In fact, the maximum possible score for any song is the number of feet difficulty X 10,000,000.
3dfsux:
I redid this code so it will store the score as a long, then correct the score for each song based on that value.
lScore == p * n
m_fScoreMultiplier = (B/S)
keeping these seperate for as long as possible improves accuracy.
*/
int p; // score multiplier
switch( score )
{
case TNS_PERFECT: p = 10; break;
case TNS_GREAT: p = 5; break;
default: p = 0; break;
}
for( int i=0; i<iNumTapsInRow; i++ )
m_lScore += p * ++m_iTapNotesHit;
ASSERT(m_lScore >= 0);
GAMESTATE->m_fScore[m_PlayerNumber] = m_lScore * m_fScoreMultiplier;
}
void ScoreKeeperMAX2::HandleHoldNoteScore( HoldNoteScore score, TapNoteScore TapNoteScore )
{
// update dance points totals
GAMESTATE->m_HoldNoteScores[m_PlayerNumber][score] ++;
GAMESTATE->m_iActualDancePoints[m_PlayerNumber] += HoldNoteScoreToDancePoints( score );
}
+33
View File
@@ -0,0 +1,33 @@
#ifndef SCOREKEEPER_MAX2_H
#define SCOREKEEPER_MAX2_H 1
/*
-----------------------------------------------------------------------------
Class: ScoreKeeperMAX2
Class to handle scorekeeping, MAX2-style.
Copyright (c) 2001-2002 by the person(s) listed below. All rights reserved.
Chris Danford
Glenn Maynard
-----------------------------------------------------------------------------
*/
#include "ScoreKeeper.h"
#include "Notes.h"
#include "NoteDataWithScoring.h"
class ScoreKeeperMAX2: public ScoreKeeper
{
long m_lScore;
float m_fScoreMultiplier;
int m_iTapNotesHit; // number of notes judged so far, needed by scoring
public:
ScoreKeeperMAX2(Notes *notes, NoteDataWithScoring &data, int pn);
void HandleNoteScore( TapNoteScore score, int iNumTapsInRow );
void HandleHoldNoteScore( HoldNoteScore score, TapNoteScore TapNoteScore );
};
#endif
+16
View File
@@ -1082,6 +1082,22 @@ SOURCE=.\ScoreDisplayOni.cpp
SOURCE=.\ScoreDisplayOni.h SOURCE=.\ScoreDisplayOni.h
# End Source File # End Source File
# Begin Source File
SOURCE=.\ScoreKeeper.cpp
# End Source File
# Begin Source File
SOURCE=.\ScoreKeeper.h
# End Source File
# Begin Source File
SOURCE=.\ScoreKeeperMAX2.cpp
# End Source File
# Begin Source File
SOURCE=.\ScoreKeeperMAX2.h
# End Source File
# End Group # End Group
# Begin Group "Screens" # Begin Group "Screens"
+12
View File
@@ -952,6 +952,18 @@ cl /Zl /nologo /c verstub.cpp /Fo$(IntDir)\
<File <File
RelativePath="ScoreDisplayOni.h"> RelativePath="ScoreDisplayOni.h">
</File> </File>
<File
RelativePath="ScoreKeeper.cpp">
</File>
<File
RelativePath="ScoreKeeper.h">
</File>
<File
RelativePath="ScoreKeeperMAX2.cpp">
</File>
<File
RelativePath="ScoreKeeperMAX2.h">
</File>
</Filter> </Filter>
<Filter <Filter
Name="Rage" Name="Rage"