Files
itgmania212121/src/ScoreKeeperNormal.cpp
T

690 lines
23 KiB
C++
Raw Normal View History

2011-03-17 01:47:30 -04:00
#include "global.h"
#include "ScoreKeeperNormal.h"
#include "GameState.h"
#include "PrefsManager.h"
#include "GamePreferences.h"
#include "Steps.h"
#include "ScreenManager.h"
#include "GameState.h"
#include "Course.h"
#include "SongManager.h"
#include "NoteDataUtil.h"
#include "NoteData.h"
#include "RageLog.h"
#include "StageStats.h"
#include "ProfileManager.h"
#include "NetworkSyncManager.h"
#include "PlayerState.h"
#include "Game.h"
#include "Style.h"
#include "Song.h"
#include "TimingData.h"
#include "NoteDataWithScoring.h"
void PercentScoreWeightInit( size_t /*ScoreEvent*/ i, RString &sNameOut, int &defaultValueOut )
{
sNameOut = "PercentScoreWeight" + ScoreEventToString( (ScoreEvent)i );
switch( i )
{
2012-12-27 16:59:35 -05:00
default:
FAIL_M(ssprintf("Invalid ScoreEvent: %i", i));
2011-03-17 01:47:30 -04:00
case SE_W1: defaultValueOut = 3; break;
case SE_W2: defaultValueOut = 2; break;
case SE_W3: defaultValueOut = 1; break;
case SE_W4: defaultValueOut = 0; break;
case SE_W5: defaultValueOut = 0; break;
case SE_Miss: defaultValueOut = 0; break;
case SE_HitMine: defaultValueOut = -2; break;
case SE_CheckpointHit: defaultValueOut = 0; break;
case SE_CheckpointMiss: defaultValueOut = 0; break;
case SE_Held: defaultValueOut = 3; break;
case SE_LetGo: defaultValueOut = 0; break;
}
}
void GradeWeightInit( size_t /*ScoreEvent*/ i, RString &sNameOut, int &defaultValueOut )
{
sNameOut = "GradeWeight" + ScoreEventToString( (ScoreEvent)i );
switch( i )
{
2012-12-27 16:59:35 -05:00
default:
FAIL_M(ssprintf("Invalid ScoreEvent: %i", i));
2011-03-17 01:47:30 -04:00
case SE_W1: defaultValueOut = 2; break;
case SE_W2: defaultValueOut = 2; break;
case SE_W3: defaultValueOut = 1; break;
case SE_W4: defaultValueOut = 0; break;
case SE_W5: defaultValueOut = -4; break;
case SE_Miss: defaultValueOut = -8; break;
case SE_HitMine: defaultValueOut = -8; break;
case SE_CheckpointHit: defaultValueOut = 0; break;
case SE_CheckpointMiss: defaultValueOut = 0; break;
case SE_Held: defaultValueOut = 6; break;
case SE_LetGo: defaultValueOut = 0; break;
}
}
static Preference1D<int> g_iPercentScoreWeight( PercentScoreWeightInit, NUM_ScoreEvent );
static Preference1D<int> g_iGradeWeight( GradeWeightInit, NUM_ScoreEvent );
ScoreKeeperNormal::ScoreKeeperNormal( PlayerState *pPlayerState, PlayerStageStats *pPlayerStageStats ):
ScoreKeeper(pPlayerState, pPlayerStageStats)
{
}
void ScoreKeeperNormal::Load(
const vector<Song*>& apSongs,
const vector<Steps*>& apSteps,
const vector<AttackArray> &asModifiers )
{
m_apSteps = apSteps;
ASSERT( apSongs.size() == apSteps.size() );
ASSERT( apSongs.size() == asModifiers.size() );
// True if a jump is one to combo, false if combo is purely based on tap count.
m_ComboIsPerRow.Load( "Gameplay", "ComboIsPerRow" );
2011-05-26 22:22:55 -04:00
m_MissComboIsPerRow.Load( "Gameplay", "MissComboIsPerRow" );
2011-03-17 01:47:30 -04:00
m_MinScoreToContinueCombo.Load( "Gameplay", "MinScoreToContinueCombo" );
m_MinScoreToMaintainCombo.Load( "Gameplay", "MinScoreToMaintainCombo" );
m_MaxScoreToIncrementMissCombo.Load( "Gameplay", "MaxScoreToIncrementMissCombo" );
m_MineHitIncrementsMissCombo.Load( "Gameplay", "MineHitIncrementsMissCombo" );
m_AvoidMineIncrementsCombo.Load( "Gameplay", "AvoidMineIncrementsCombo" );
// Toasty triggers (idea from 3.9+)
// Multiple toasty support doesn't seem to be working right now.
// Since it's causing more problems than solutions, I'm going back to
// the old way of a single toasty trigger for now.
//m_vToastyTriggers.Load( "Gameplay", "ToastyTriggersAt" );
m_ToastyTrigger.Load( "Gameplay", "ToastyTriggersAt" );
// Fill in STATSMAN->m_CurStageStats, calculate multiplier
int iTotalPossibleDancePoints = 0;
int iTotalPossibleGradePoints = 0;
for( unsigned i=0; i<apSteps.size(); i++ )
{
Song* pSong = apSongs[i];
ASSERT( pSong != NULL );
2011-03-17 01:47:30 -04:00
Steps* pSteps = apSteps[i];
ASSERT( pSteps != NULL );
2011-03-17 01:47:30 -04:00
const AttackArray &aa = asModifiers[i];
NoteData ndTemp;
pSteps->GetNoteData( ndTemp );
// We might have been given lots of songs; don't keep them in memory uncompressed.
pSteps->Compress();
const Style* pStyle = GAMESTATE->GetCurrentStyle();
NoteData nd;
pStyle->GetTransformedNoteDataForStyle( m_pPlayerState->m_PlayerNumber, ndTemp, nd );
/* Compute RadarValues before applying any user-selected mods. Apply
* Course mods and count them in the "pre" RadarValues because they're
* forced and not chosen by the user. */
NoteDataUtil::TransformNoteData( nd, aa, pSteps->m_StepsType, pSong );
RadarValues rvPre;
GAMESTATE->SetProcessedTimingData(pSteps->GetTimingData());
2011-03-17 01:47:30 -04:00
NoteDataUtil::CalculateRadarValues( nd, pSong->m_fMusicLengthSeconds, rvPre );
/* Apply user transforms to find out how the notes will really look.
*
* XXX: This is brittle: if we end up combining mods for a song differently
* than ScreenGameplay, we'll end up with the wrong data. We should probably
* have eg. GAMESTATE->GetOptionsForCourse(po,so,pn) to get options based on
* the last call to StoreSelectedOptions and the modifiers list, but that'd
* mean moving the queues in ScreenGameplay to GameState ... */
NoteDataUtil::TransformNoteData( nd, m_pPlayerState->m_PlayerOptions.GetStage(), pSteps->m_StepsType );
RadarValues rvPost;
NoteDataUtil::CalculateRadarValues( nd, pSong->m_fMusicLengthSeconds, rvPost );
GAMESTATE->SetProcessedTimingData(NULL);
2011-03-17 01:47:30 -04:00
iTotalPossibleDancePoints += this->GetPossibleDancePoints( rvPre, rvPost );
iTotalPossibleGradePoints += this->GetPossibleGradePoints( rvPre, rvPost );
}
m_pPlayerStageStats->m_iPossibleDancePoints = iTotalPossibleDancePoints;
m_pPlayerStageStats->m_iPossibleGradePoints = iTotalPossibleGradePoints;
m_iScoreRemainder = 0;
m_iCurToastyCombo = 0;
//m_iCurToastyTrigger = 0;
//m_iNextToastyAt = 0;
m_iMaxScoreSoFar = 0;
m_iPointBonus = 0;
m_iNumTapsAndHolds = 0;
m_iNumNotesHitThisRow = 0;
m_bIsLastSongInCourse = false;
Message msg( "ScoreChanged" );
msg.SetParam( "PlayerNumber", m_pPlayerState->m_PlayerNumber );
msg.SetParam( "MultiPlayer", m_pPlayerState->m_mp );
MESSAGEMAN->Broadcast( msg );
memset( m_ComboBonusFactor, 0, sizeof(m_ComboBonusFactor) );
m_iRoundTo = 1;
2011-03-17 01:47:30 -04:00
}
2012-12-27 00:00:28 -05:00
void ScoreKeeperNormal::OnNextSong( int, const Steps* pSteps, const NoteData* )
2011-03-17 01:47:30 -04:00
{
m_bIsBeginner = pSteps->GetDifficulty() == Difficulty_Beginner && !GAMESTATE->IsCourseMode();
m_iTapNotesHit = 0;
2011-06-08 16:14:11 -04:00
GAMESTATE->SetProcessedTimingData(NULL);
2011-03-17 01:47:30 -04:00
}
void ScoreKeeperNormal::AddTapScore( TapNoteScore tns )
{
2012-08-02 00:07:05 -05:00
if(tns==TNS_HitMine || tns==TNS_AvoidMine || tns==TNS_CheckpointHit || tns==TNS_CheckpointMiss)
AddScoreInternal( tns );
2011-03-17 01:47:30 -04:00
}
void ScoreKeeperNormal::AddHoldScore( HoldNoteScore hns )
{
2012-04-12 11:40:34 -05:00
if( hns == HNS_Held )
AddScoreInternal( TNS_W1 );
2011-03-17 01:47:30 -04:00
}
void ScoreKeeperNormal::AddTapRowScore( TapNoteScore score, const NoteData &nd, int iRow )
{
AddScoreInternal( score );
}
extern ThemeMetric<bool> PENALIZE_TAP_SCORE_NONE;
void ScoreKeeperNormal::HandleTapScoreNone()
{
if( PENALIZE_TAP_SCORE_NONE )
{
m_pPlayerStageStats->m_iCurCombo = 0;
if( m_pPlayerState->m_PlayerNumber != PLAYER_INVALID )
MESSAGEMAN->Broadcast( enum_add2(Message_CurrentComboChangedP1,m_pPlayerState->m_PlayerNumber) );
}
// TODO: networking code
}
2012-12-28 13:41:41 -08:00
void ScoreKeeperNormal::AddScoreInternal( TapNoteScore score )
2011-03-17 01:47:30 -04:00
{
2012-12-28 13:41:41 -08:00
int &iScore = m_pPlayerStageStats->m_iScore;
int &iCurMaxScore = m_pPlayerStageStats->m_iCurMaxScore;
int p = 0;
switch( score )
{
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;
}
iScore += p;
iCurMaxScore += 5;
if( iScore < 0 )
iScore = 0;
ASSERT_M( iScore >= 0, "iScore < 0" );
// LOG->Trace( "score: %i", iScore );
2011-03-17 01:47:30 -04:00
}
void ScoreKeeperNormal::HandleTapScore( const TapNote &tn )
{
TapNoteScore tns = tn.result.tns;
if( tn.type == TapNote::mine )
{
if( tns == TNS_HitMine )
{
if( !m_pPlayerStageStats->m_bFailed )
m_pPlayerStageStats->m_iActualDancePoints += TapNoteScoreToDancePoints( TNS_HitMine );
m_pPlayerStageStats->m_iTapNoteScores[TNS_HitMine] += 1;
if( m_MineHitIncrementsMissCombo )
HandleComboInternal( 0, 0, 1 );
}
if( tns == TNS_AvoidMine && m_AvoidMineIncrementsCombo )
HandleComboInternal( 1, 0, 0 );
NSMAN->ReportScore(
m_pPlayerState->m_PlayerNumber,
tns,
m_pPlayerStageStats->m_iScore,
m_pPlayerStageStats->m_iCurCombo,
tn.result.fTapNoteOffset
);
Message msg( "ScoreChanged" );
msg.SetParam( "PlayerNumber", m_pPlayerState->m_PlayerNumber );
msg.SetParam( "MultiPlayer", m_pPlayerState->m_mp );
MESSAGEMAN->Broadcast( msg );
}
AddTapScore( tns );
}
void ScoreKeeperNormal::HandleHoldCheckpointScore( const NoteData &nd, int iRow, int iNumHoldsHeldThisRow, int iNumHoldsMissedThisRow )
{
2011-07-09 13:09:03 -04:00
HandleTapNoteScoreInternal(iNumHoldsMissedThisRow == 0 ? TNS_CheckpointHit:TNS_CheckpointMiss,
TNS_CheckpointHit, iRow);
2011-03-17 01:47:30 -04:00
HandleComboInternal( iNumHoldsHeldThisRow, 0, iNumHoldsMissedThisRow, iRow );
}
2011-07-09 13:09:03 -04:00
void ScoreKeeperNormal::HandleTapNoteScoreInternal( TapNoteScore tns, TapNoteScore maximum, int row )
2011-03-17 01:47:30 -04:00
{
// Update dance points.
if( !m_pPlayerStageStats->m_bFailed )
m_pPlayerStageStats->m_iActualDancePoints += TapNoteScoreToDancePoints( tns );
2011-07-09 13:09:03 -04:00
// update judged row totals. Respect Combo segments here.
TimingData &td = *GAMESTATE->m_pCurSteps[m_pPlayerState->m_PlayerNumber]->GetTimingData();
2011-07-14 23:15:48 -04:00
ComboSegment *cs = td.GetComboSegmentAtRow(row);
2011-07-09 14:07:13 -04:00
if (tns == TNS_CheckpointHit || tns >= m_MinScoreToContinueCombo)
2011-07-09 13:09:03 -04:00
{
2011-07-14 23:15:48 -04:00
m_pPlayerStageStats->m_iTapNoteScores[tns] += cs->GetCombo();
2011-07-09 13:09:03 -04:00
}
2011-07-09 14:07:13 -04:00
else if (tns == TNS_CheckpointMiss || tns < m_MinScoreToMaintainCombo)
2011-07-09 13:09:03 -04:00
{
2011-07-14 23:15:48 -04:00
m_pPlayerStageStats->m_iTapNoteScores[tns] += cs->GetMissCombo();
2011-07-09 13:09:03 -04:00
}
else
{
m_pPlayerStageStats->m_iTapNoteScores[tns] += 1;
}
2011-03-17 01:47:30 -04:00
// increment the current total possible dance score
m_pPlayerStageStats->m_iCurPossibleDancePoints += TapNoteScoreToDancePoints( maximum );
}
void ScoreKeeperNormal::HandleComboInternal( int iNumHitContinueCombo, int iNumHitMaintainCombo, int iNumBreakCombo, int iRow )
{
// Regular combo
if( m_ComboIsPerRow )
{
iNumHitContinueCombo = min( iNumHitContinueCombo, 1 );
iNumHitMaintainCombo = min( iNumHitMaintainCombo, 1 );
iNumBreakCombo = min( iNumBreakCombo, 1 );
}
if( iNumHitContinueCombo > 0 || iNumHitMaintainCombo > 0 )
{
m_pPlayerStageStats->m_iCurMissCombo = 0;
}
TimingData &td = *GAMESTATE->m_pCurSteps[m_pPlayerState->m_PlayerNumber]->GetTimingData();
2011-03-17 01:47:30 -04:00
if( iNumBreakCombo == 0 )
{
2011-07-14 23:15:48 -04:00
int multiplier = ( iRow == -1 ? 1 : td.GetComboSegmentAtRow( iRow )->GetCombo() );
2011-03-17 01:47:30 -04:00
m_pPlayerStageStats->m_iCurCombo += iNumHitContinueCombo * multiplier;
}
else
{
m_pPlayerStageStats->m_iCurCombo = 0;
2011-07-14 23:15:48 -04:00
int multiplier = ( iRow == -1 ? 1 : td.GetComboSegmentAtRow(iRow)->GetMissCombo());
2011-07-09 02:28:15 -04:00
m_pPlayerStageStats->m_iCurMissCombo += ( m_MissComboIsPerRow ? 1 : iNumBreakCombo ) * multiplier;
2011-03-17 01:47:30 -04:00
}
}
void ScoreKeeperNormal::HandleRowComboInternal( TapNoteScore tns, int iNumTapsInRow, int iRow )
{
if( m_ComboIsPerRow )
{
iNumTapsInRow = min( iNumTapsInRow, 1);
}
TimingData &td = *GAMESTATE->m_pCurSteps[m_pPlayerState->m_PlayerNumber]->GetTimingData();
2011-03-17 01:47:30 -04:00
if ( tns >= m_MinScoreToContinueCombo )
{
m_pPlayerStageStats->m_iCurMissCombo = 0;
2011-07-14 23:15:48 -04:00
int multiplier = ( iRow == -1 ? 1 : td.GetComboSegmentAtRow( iRow )->GetCombo() );
2011-03-17 01:47:30 -04:00
m_pPlayerStageStats->m_iCurCombo += iNumTapsInRow * multiplier;
}
else if ( tns < m_MinScoreToMaintainCombo )
{
m_pPlayerStageStats->m_iCurCombo = 0;
if( tns <= m_MaxScoreToIncrementMissCombo )
2011-07-09 02:28:15 -04:00
{
2011-07-14 23:15:48 -04:00
int multiplier = ( iRow == -1 ? 1 : td.GetComboSegmentAtRow(iRow)->GetMissCombo());
2011-07-09 02:28:15 -04:00
m_pPlayerStageStats->m_iCurMissCombo += ( m_MissComboIsPerRow ? 1 : iNumTapsInRow ) * multiplier;
}
2011-03-17 01:47:30 -04:00
}
}
void ScoreKeeperNormal::GetRowCounts( const NoteData &nd, int iRow,
int &iNumHitContinueCombo, int &iNumHitMaintainCombo,
int &iNumBreakCombo )
{
iNumHitContinueCombo = iNumHitMaintainCombo = iNumBreakCombo = 0;
for( int track = 0; track < nd.GetNumTracks(); ++track )
{
const TapNote &tn = nd.GetTapNote( track, iRow );
if( tn.type != TapNote::tap && tn.type != TapNote::hold_head && tn.type != TapNote::lift )
continue;
TapNoteScore tns = tn.result.tns;
if( tns >= m_MinScoreToContinueCombo )
++iNumHitContinueCombo;
else if( tns >= m_MinScoreToMaintainCombo )
++iNumHitMaintainCombo;
else
++iNumBreakCombo;
}
}
void ScoreKeeperNormal::HandleTapRowScore( const NoteData &nd, int iRow )
{
int iNumHitContinueCombo, iNumHitMaintainCombo, iNumBreakCombo;
GetRowCounts( nd, iRow, iNumHitContinueCombo, iNumHitMaintainCombo, iNumBreakCombo );
int iNumTapsInRow = iNumHitContinueCombo + iNumHitMaintainCombo + iNumBreakCombo;
if( iNumTapsInRow <= 0 )
return;
m_iNumNotesHitThisRow = iNumTapsInRow;
TapNoteScore scoreOfLastTap = NoteDataWithScoring::LastTapNoteWithResult( nd, iRow ).result.tns;
2011-07-09 13:09:03 -04:00
HandleTapNoteScoreInternal( scoreOfLastTap, TNS_W1, iRow );
2011-03-17 01:47:30 -04:00
if ( GAMESTATE->GetCurrentGame()->m_bCountNotesSeparately )
{
HandleComboInternal( iNumHitContinueCombo, iNumHitMaintainCombo, iNumBreakCombo, iRow );
}
else
{
HandleRowComboInternal( scoreOfLastTap, iNumTapsInRow, iRow ); //This should work?
}
if( m_pPlayerState->m_PlayerNumber != PLAYER_INVALID )
MESSAGEMAN->Broadcast( enum_add2(Message_CurrentComboChangedP1,m_pPlayerState->m_PlayerNumber) );
AddTapRowScore( scoreOfLastTap, nd, iRow ); // only score once per row
// handle combo logic
#ifndef DEBUG
if( (GamePreferences::m_AutoPlay != PC_HUMAN || m_pPlayerState->m_PlayerOptions.GetCurrent().m_fPlayerAutoPlay != 0)
&& !GAMESTATE->m_bDemonstrationOrJukebox ) // cheaters always prosper >:D -aj comment edit
{
m_iCurToastyCombo = 0;
return;
}
#endif //DEBUG
// Toasty combo
//vector<int> iToastyMilestones;
switch( scoreOfLastTap )
{
case TNS_W1:
case TNS_W2:
m_iCurToastyCombo += iNumTapsInRow;
/*
// compile the list of toasty triggers
{
Lua *L = LUA->Get();
m_vToastyTriggers.PushSelf(L);
LuaHelpers::ReadArrayFromTable(iToastyMilestones, L);
lua_pop( L, 1 );
LUA->Release(L);
}
// find out which one we're at.
if(m_iCurToastyTrigger <= int(iToastyMilestones.size()))
{
m_iNextToastyAt = iToastyMilestones[m_iCurToastyTrigger];
}
else // out of index value? then don't make it toasty!
{
m_iNextToastyAt = -1;
}
*/
if( m_iCurToastyCombo >= m_ToastyTrigger &&
m_iCurToastyCombo - iNumTapsInRow < m_ToastyTrigger &&
!GAMESTATE->m_bDemonstrationOrJukebox )
{
SCREENMAN->PostMessageToTopScreen( SM_PlayToasty, 0 );
Message msg("ToastyAchieved");
msg.SetParam( "PlayerNumber", m_pPlayerState->m_PlayerNumber );
msg.SetParam( "ToastyCombo", m_iCurToastyCombo );
MESSAGEMAN->Broadcast(msg);
// TODO: keep a pointer to the Profile. Don't index with m_PlayerNumber
PROFILEMAN->IncrementToastiesCount( m_pPlayerState->m_PlayerNumber );
//m_iCurToastyTrigger++;
}
break;
default:
m_iCurToastyCombo = 0;
Message msg("ToastyDropped");
msg.SetParam( "PlayerNumber", m_pPlayerState->m_PlayerNumber );
MESSAGEMAN->Broadcast(msg);
break;
}
// TODO: Remove indexing with PlayerNumber
PlayerNumber pn = m_pPlayerState->m_PlayerNumber;
float offset = NoteDataWithScoring::LastTapNoteWithResult( nd, iRow ).result.fTapNoteOffset;
NSMAN->ReportScore( pn, scoreOfLastTap,
m_pPlayerStageStats->m_iScore,
m_pPlayerStageStats->m_iCurCombo, offset );
Message msg( "ScoreChanged" );
msg.SetParam( "PlayerNumber", m_pPlayerState->m_PlayerNumber );
msg.SetParam( "MultiPlayer", m_pPlayerState->m_mp );
msg.SetParam( "ToastyCombo", m_iCurToastyCombo );
MESSAGEMAN->Broadcast( msg );
}
void ScoreKeeperNormal::HandleHoldScore( const TapNote &tn )
{
HoldNoteScore holdScore = tn.HoldResult.hns;
// update dance points totals
if( !m_pPlayerStageStats->m_bFailed )
m_pPlayerStageStats->m_iActualDancePoints += HoldNoteScoreToDancePoints( holdScore );
m_pPlayerStageStats->m_iCurPossibleDancePoints += HoldNoteScoreToDancePoints( HNS_Held );
m_pPlayerStageStats->m_iHoldNoteScores[holdScore] ++;
// increment the current total possible dance score
m_pPlayerStageStats->m_iCurPossibleDancePoints += HoldNoteScoreToDancePoints( HNS_Held );
AddHoldScore( holdScore );
// TODO: Remove indexing with PlayerNumber
PlayerNumber pn = m_pPlayerState->m_PlayerNumber;
NSMAN->ReportScore(
pn,
holdScore+TapNoteScore_Invalid,
m_pPlayerStageStats->m_iScore,
m_pPlayerStageStats->m_iCurCombo,
tn.result.fTapNoteOffset );
Message msg( "ScoreChanged" );
msg.SetParam( "PlayerNumber", m_pPlayerState->m_PlayerNumber );
msg.SetParam( "MultiPlayer", m_pPlayerState->m_mp );
MESSAGEMAN->Broadcast( msg );
}
int ScoreKeeperNormal::GetPossibleDancePoints( const RadarValues& radars )
{
/* Note: If W1 timing is disabled or not active (not course mode),
* W2 will be used instead. */
int NumTaps = int(radars[RadarCategory_TapsAndHolds]);
int NumHolds = int(radars[RadarCategory_Holds]);
int NumRolls = int(radars[RadarCategory_Rolls]);
return
NumTaps*TapNoteScoreToDancePoints(TNS_W1, false) +
NumHolds*HoldNoteScoreToDancePoints(HNS_Held, false) +
NumRolls*HoldNoteScoreToDancePoints(HNS_Held, false);
}
int ScoreKeeperNormal::GetPossibleDancePoints( const RadarValues& fOriginalRadars, const RadarValues& fPostRadars )
{
/* The logic here is that if you use a modifier that adds notes, you should
* have to hit the new notes to get a high grade. However, if you use one
* that removes notes, they should simply be counted as misses. */
return max(
GetPossibleDancePoints(fOriginalRadars),
GetPossibleDancePoints(fPostRadars) );
}
int ScoreKeeperNormal::GetPossibleGradePoints( const RadarValues& radars )
{
/* Note: if W1 timing is disabled or not active (not course mode),
* W2 will be used instead. */
int NumTaps = int(radars[RadarCategory_TapsAndHolds]);
int NumHolds = int(radars[RadarCategory_Holds]);
int NumRolls = int(radars[RadarCategory_Rolls]);
return
NumTaps*TapNoteScoreToGradePoints(TNS_W1, false) +
NumHolds*HoldNoteScoreToGradePoints(HNS_Held, false) +
NumRolls*HoldNoteScoreToGradePoints(HNS_Held, false);
}
int ScoreKeeperNormal::GetPossibleGradePoints( const RadarValues& fOriginalRadars, const RadarValues& fPostRadars )
{
/* The logic here is that if you use a modifier that adds notes, you should
* have to hit the new notes to get a high grade. However, if you use one
* that removes notes, they should simply be counted as misses. */
return max(
GetPossibleGradePoints(fOriginalRadars),
GetPossibleGradePoints(fPostRadars) );
}
int ScoreKeeperNormal::TapNoteScoreToDancePoints( TapNoteScore tns ) const
{
return TapNoteScoreToDancePoints( tns, m_bIsBeginner );
}
int ScoreKeeperNormal::HoldNoteScoreToDancePoints( HoldNoteScore hns ) const
{
return HoldNoteScoreToDancePoints( hns, m_bIsBeginner );
}
int ScoreKeeperNormal::TapNoteScoreToGradePoints( TapNoteScore tns ) const
{
return TapNoteScoreToGradePoints( tns, m_bIsBeginner );
}
int ScoreKeeperNormal::HoldNoteScoreToGradePoints( HoldNoteScore hns ) const
{
return HoldNoteScoreToGradePoints( hns, m_bIsBeginner );
}
int ScoreKeeperNormal::TapNoteScoreToDancePoints( TapNoteScore tns, bool bBeginner )
{
if( !GAMESTATE->ShowW1() && tns == TNS_W1 )
tns = TNS_W2;
/* This is used for Oni percentage displays. Grading values are currently in
* StageStats::GetGrade. */
int iWeight = 0;
switch( tns )
{
DEFAULT_FAIL( tns );
case TNS_None: iWeight = 0; break;
case TNS_HitMine: iWeight = g_iPercentScoreWeight[SE_HitMine]; break;
case TNS_Miss: iWeight = g_iPercentScoreWeight[SE_Miss]; break;
case TNS_W5: iWeight = g_iPercentScoreWeight[SE_W5]; break;
case TNS_W4: iWeight = g_iPercentScoreWeight[SE_W4]; break;
case TNS_W3: iWeight = g_iPercentScoreWeight[SE_W3]; break;
case TNS_W2: iWeight = g_iPercentScoreWeight[SE_W2]; break;
case TNS_W1: iWeight = g_iPercentScoreWeight[SE_W1]; break;
case TNS_CheckpointHit: iWeight = g_iPercentScoreWeight[SE_CheckpointHit]; break;
case TNS_CheckpointMiss:iWeight = g_iPercentScoreWeight[SE_CheckpointMiss]; break;
}
if( bBeginner && PREFSMAN->m_bMercifulBeginner )
iWeight = max( 0, iWeight );
return iWeight;
}
int ScoreKeeperNormal::HoldNoteScoreToDancePoints( HoldNoteScore hns, bool bBeginner )
{
int iWeight = 0;
switch( hns )
{
DEFAULT_FAIL( hns );
case HNS_None: iWeight = 0; break;
case HNS_LetGo: iWeight = g_iPercentScoreWeight[SE_LetGo]; break;
case HNS_Held: iWeight = g_iPercentScoreWeight[SE_Held]; break;
}
if( bBeginner && PREFSMAN->m_bMercifulBeginner )
iWeight = max( 0, iWeight );
return iWeight;
}
int ScoreKeeperNormal::TapNoteScoreToGradePoints( TapNoteScore tns, bool bBeginner )
{
if( !GAMESTATE->ShowW1() && tns == TNS_W1 )
tns = TNS_W2;
/* This is used for Oni percentage displays. Grading values are currently in
* StageStats::GetGrade. */
int iWeight = 0;
switch( tns )
{
DEFAULT_FAIL( tns );
case TNS_None: iWeight = 0; break;
case TNS_AvoidMine: iWeight = 0; break;
case TNS_HitMine: iWeight = g_iGradeWeight[SE_HitMine]; break;
case TNS_Miss: iWeight = g_iGradeWeight[SE_Miss]; break;
case TNS_W5: iWeight = g_iGradeWeight[SE_W5]; break;
case TNS_W4: iWeight = g_iGradeWeight[SE_W4]; break;
case TNS_W3: iWeight = g_iGradeWeight[SE_W3]; break;
case TNS_W2: iWeight = g_iGradeWeight[SE_W2]; break;
case TNS_W1: iWeight = g_iGradeWeight[SE_W1]; break;
case TNS_CheckpointHit: iWeight = g_iGradeWeight[SE_CheckpointHit]; break;
case TNS_CheckpointMiss:iWeight = g_iGradeWeight[SE_CheckpointMiss]; break;
}
if( bBeginner && PREFSMAN->m_bMercifulBeginner )
iWeight = max( 0, iWeight );
return iWeight;
}
int ScoreKeeperNormal::HoldNoteScoreToGradePoints( HoldNoteScore hns, bool bBeginner )
{
int iWeight = 0;
switch( hns )
{
DEFAULT_FAIL( hns );
case HNS_None: iWeight = 0; break;
case HNS_LetGo: iWeight = g_iGradeWeight[SE_LetGo]; break;
case HNS_Held: iWeight = g_iGradeWeight[SE_Held]; break;
}
if( bBeginner && PREFSMAN->m_bMercifulBeginner )
iWeight = max( 0, iWeight );
return iWeight;
}
/*
* (c) 2001-2004 Chris Danford, Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/