Attempted addition of brand new scoring system.
This commit is contained in:
+14
-152
@@ -163,117 +163,23 @@ void ScoreKeeperNormal::Load(
|
||||
|
||||
void ScoreKeeperNormal::OnNextSong( int iSongInCourseIndex, const Steps* pSteps, const NoteData* pNoteData )
|
||||
{
|
||||
/*
|
||||
Note on NONSTOP Mode scoring
|
||||
|
||||
Nonstop mode requires the player to play 4 songs in succession, with the total maximum possible score for
|
||||
the four song set being 100,000,000. This comes from the sum of the four stages' maximum possible scores,
|
||||
which, regardless of song or difficulty is:
|
||||
|
||||
10,000,000 for the first song
|
||||
20,000,000 for the second song
|
||||
30,000,000 for the third song
|
||||
40,000,000 for the fourth song
|
||||
|
||||
We extend this to work with nonstop courses of any length.
|
||||
|
||||
We also keep track of this scoring type in endless, with 100mil per iteration
|
||||
of all songs, though this score isn't actually seen anywhere right now.
|
||||
*/
|
||||
// Calculate the score multiplier
|
||||
m_iMaxPossiblePoints = 0;
|
||||
if( GAMESTATE->IsCourseMode() )
|
||||
{
|
||||
const int numSongsInCourse = m_apSteps.size();
|
||||
ASSERT( numSongsInCourse != 0 );
|
||||
|
||||
const int iIndex = iSongInCourseIndex % numSongsInCourse;
|
||||
m_bIsLastSongInCourse = (iIndex+1 == numSongsInCourse);
|
||||
|
||||
if( numSongsInCourse < 10 )
|
||||
{
|
||||
const int courseMult = (numSongsInCourse * (numSongsInCourse + 1)) / 2;
|
||||
ASSERT(courseMult >= 0);
|
||||
|
||||
m_iMaxPossiblePoints = (100000000 * (iIndex+1)) / courseMult;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* When we have lots of songs, the scale above biases too much: in a
|
||||
* course with 50 songs, the first song is worth 80k, the last 4mil, which
|
||||
* is too much of a difference.
|
||||
*
|
||||
* With this, each song in a 50-song course will be worth 2mil. */
|
||||
m_iMaxPossiblePoints = 100000000 / numSongsInCourse;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// long ver and marathon ver songs have higher max possible scores
|
||||
int iLengthMultiplier = GameState::GetNumStagesMultiplierForSong( GAMESTATE->m_pCurSong );
|
||||
|
||||
/* This is no longer just simple additive/subtractive scoring,
|
||||
* but start with capping the score at the size of the score counter. */
|
||||
m_iMaxPossiblePoints = 10 * 10000000 * iLengthMultiplier;
|
||||
}
|
||||
ASSERT( m_iMaxPossiblePoints >= 0 );
|
||||
m_iMaxScoreSoFar += m_iMaxPossiblePoints;
|
||||
|
||||
GAMESTATE->SetProcessedTimingData(const_cast<TimingData *>(&pSteps->m_Timing));
|
||||
|
||||
m_iNumTapsAndHolds = pNoteData->GetNumRowsWithTapOrHoldHead() + pNoteData->GetNumHoldNotes()
|
||||
+ pNoteData->GetNumRolls();
|
||||
|
||||
m_iPointBonus = m_iMaxPossiblePoints;
|
||||
m_pPlayerStageStats->m_iMaxScore = m_iMaxScoreSoFar;
|
||||
|
||||
/* MercifulBeginner shouldn't clamp weights in course mode, even if a beginner
|
||||
* song is in a course, since that makes PlayerStageStats::GetGrade hard. */
|
||||
m_bIsBeginner = pSteps->GetDifficulty() == Difficulty_Beginner && !GAMESTATE->IsCourseMode();
|
||||
|
||||
ASSERT( m_iPointBonus >= 0 );
|
||||
|
||||
m_iTapNotesHit = 0;
|
||||
|
||||
GAMESTATE->SetProcessedTimingData(NULL);
|
||||
}
|
||||
|
||||
static int GetScore(int p, int Z, int S, int n)
|
||||
{
|
||||
/* There's a problem with the scoring system described below. Z/S is truncated
|
||||
* to an int. However, in some cases we can end up with very small base scores.
|
||||
* Each song in a 50-song nonstop course will be worth 2mil, which is a base of
|
||||
* 200k; Z/S will end up being zero.
|
||||
*
|
||||
* If we rearrange the equation to (p*Z*n) / S, this problem goes away.
|
||||
* (To do that, we need to either use 64-bit ints or rearrange it a little
|
||||
* more and use floats, since p*Z*n won't fit a 32-bit int.) However, this
|
||||
* changes the scoring rules slightly.
|
||||
*/
|
||||
|
||||
#if 0
|
||||
// This is the actual method described below.
|
||||
return p * (Z / S) * n;
|
||||
#elif 1
|
||||
// This doesn't round down Z/S.
|
||||
return int(int64_t(p) * n * Z / S);
|
||||
#else
|
||||
// This also doesn't round down Z/S. Use this if you don't have 64-bit ints.
|
||||
return int(p * n * (float(Z) / S));
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void ScoreKeeperNormal::AddTapScore( TapNoteScore tns )
|
||||
{
|
||||
AddScoreInternal( tns );
|
||||
}
|
||||
|
||||
void ScoreKeeperNormal::AddHoldScore( HoldNoteScore hns )
|
||||
{
|
||||
if( hns == HNS_Held )
|
||||
AddScoreInternal( TNS_W1 );
|
||||
else if ( hns == HNS_LetGo )
|
||||
AddScoreInternal( TNS_W4 ); // required for subtractive score display to work properly.
|
||||
}
|
||||
|
||||
void ScoreKeeperNormal::AddTapRowScore( TapNoteScore score, const NoteData &nd, int iRow )
|
||||
@@ -300,71 +206,27 @@ void ScoreKeeperNormal::AddScoreInternal( TapNoteScore score )
|
||||
int &iScore = m_pPlayerStageStats->m_iScore;
|
||||
int &iCurMaxScore = m_pPlayerStageStats->m_iCurMaxScore;
|
||||
|
||||
// See Aaron In Japan for more details about the scoring formulas.
|
||||
// Note: this assumes no custom scoring systems are in use.
|
||||
int p = 0; // score multiplier
|
||||
int p = 0;
|
||||
|
||||
switch( score )
|
||||
{
|
||||
case TNS_W1: p = 10; break;
|
||||
case TNS_W2: p = GAMESTATE->ShowW1()? 9:10; break;
|
||||
case TNS_W3: p = 5; break;
|
||||
case TNS_W1: p = 5; break;
|
||||
case TNS_W2: p = 4; break;
|
||||
case TNS_W3: p = 3; break;
|
||||
case TNS_W4: p = 2; break;
|
||||
case TNS_CheckpointHit:
|
||||
case TNS_W5: p = 1; break;
|
||||
case TNS_HitMine: p = -1; break;
|
||||
default: p = 0; break;
|
||||
}
|
||||
|
||||
m_iTapNotesHit++;
|
||||
iScore += p;
|
||||
iCurMaxScore += 5;
|
||||
|
||||
const int N = m_iNumTapsAndHolds;
|
||||
const int sum = (N * (N + 1)) / 2;
|
||||
const int Z = m_iMaxPossiblePoints/10;
|
||||
if( iScore < 0 )
|
||||
iScore = 0;
|
||||
|
||||
// Don't use a multiplier if the player has failed
|
||||
if( m_pPlayerStageStats->m_bFailed )
|
||||
{
|
||||
iScore += p;
|
||||
// make score evenly divisible by 5
|
||||
// only update this on the next step, to make it less *obvious*
|
||||
/* Round to the nearest 5, instead of always rounding down, so a base score
|
||||
* of 9 will round to 10, not 5. */
|
||||
if (p > 0)
|
||||
iScore = ((iScore+2) / 5) * 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
iScore += GetScore(p, Z, sum, m_iTapNotesHit);
|
||||
const int &iCurrentCombo = m_pPlayerStageStats->m_iCurCombo;
|
||||
iScore += m_ComboBonusFactor[score] * iCurrentCombo;
|
||||
}
|
||||
|
||||
// Subtract the maximum this step could have been worth from the bonus.
|
||||
m_iPointBonus -= GetScore(10, Z, sum, m_iTapNotesHit);
|
||||
// And add the maximum this step could have been worth to the max score up to now.
|
||||
iCurMaxScore += GetScore(10, Z, sum, m_iTapNotesHit);
|
||||
|
||||
if ( m_iTapNotesHit == m_iNumTapsAndHolds && score >= TNS_W2 )
|
||||
{
|
||||
if( !m_pPlayerStageStats->m_bFailed )
|
||||
iScore += m_iPointBonus;
|
||||
if ( m_bIsLastSongInCourse )
|
||||
{
|
||||
iScore += 100000000 - m_iMaxScoreSoFar;
|
||||
iCurMaxScore += 100000000 - m_iMaxScoreSoFar;
|
||||
|
||||
/* If we're in Endless mode, we'll come around here again, so reset
|
||||
* the bonus counter. */
|
||||
m_iMaxScoreSoFar = 0;
|
||||
}
|
||||
iCurMaxScore += m_iPointBonus;
|
||||
}
|
||||
|
||||
ASSERT_M( iScore >= 0, "iScore < 0 before re-rounding" );
|
||||
|
||||
// Undo rounding from the last tap, and re-round.
|
||||
iScore += m_iScoreRemainder;
|
||||
m_iScoreRemainder = (iScore % m_iRoundTo);
|
||||
iScore = iScore - m_iScoreRemainder;
|
||||
|
||||
ASSERT_M( iScore >= 0, "iScore < 0 after re-rounding" );
|
||||
ASSERT_M( iScore >= 0, "iScore < 0" );
|
||||
|
||||
// LOG->Trace( "score: %i", iScore );
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user