2005-02-16 03:25:45 +00:00
|
|
|
#include "global.h"
|
|
|
|
|
#include "StatsManager.h"
|
|
|
|
|
#include "GameState.h"
|
2005-02-16 19:40:09 +00:00
|
|
|
#include "Foreach.h"
|
2005-02-23 04:32:45 +00:00
|
|
|
#include "ProfileManager.h"
|
|
|
|
|
#include "PrefsManager.h"
|
|
|
|
|
#include "Steps.h"
|
2005-02-16 03:25:45 +00:00
|
|
|
|
|
|
|
|
StatsManager* STATSMAN = NULL; // global object accessable from anywhere in the program
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
StatsManager::StatsManager()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2005-02-16 19:40:09 +00:00
|
|
|
StageStats AccumStageStats( const vector<StageStats>& vss )
|
|
|
|
|
{
|
|
|
|
|
StageStats ssreturn;
|
|
|
|
|
|
2005-04-25 06:06:47 +00:00
|
|
|
if( !vss.empty() )
|
|
|
|
|
{
|
|
|
|
|
ssreturn.pStyle = vss[0].pStyle;
|
|
|
|
|
ssreturn.playMode = vss[0].playMode;
|
|
|
|
|
}
|
|
|
|
|
|
2005-02-16 19:40:09 +00:00
|
|
|
FOREACH_CONST( StageStats, vss, ss )
|
|
|
|
|
ssreturn.AddStats( *ss );
|
|
|
|
|
|
2005-04-20 06:13:06 +00:00
|
|
|
unsigned uNumSongs = ssreturn.vpPlayedSongs.size();
|
2005-02-16 19:40:09 +00:00
|
|
|
|
2005-04-25 11:45:16 +00:00
|
|
|
if( uNumSongs == 0 )
|
|
|
|
|
return ssreturn; // don't divide by 0 below
|
2005-02-16 19:40:09 +00:00
|
|
|
|
|
|
|
|
/* Scale radar percentages back down to roughly 0..1. Don't scale RADAR_NUM_TAPS_AND_HOLDS
|
|
|
|
|
* and the rest, which are counters. */
|
|
|
|
|
// FIXME: Weight each song by the number of stages it took to account for
|
|
|
|
|
// long, marathon.
|
|
|
|
|
FOREACH_EnabledPlayer( pn )
|
|
|
|
|
{
|
|
|
|
|
for( int r = 0; r < RADAR_NUM_TAPS_AND_HOLDS; r++)
|
|
|
|
|
{
|
|
|
|
|
ssreturn.m_player[pn].radarPossible[r] /= uNumSongs;
|
|
|
|
|
ssreturn.m_player[pn].radarActual[r] /= uNumSongs;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ssreturn;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void StatsManager::GetFinalEvalStageStats( StageStats& statsOut ) const
|
|
|
|
|
{
|
|
|
|
|
statsOut.Init();
|
|
|
|
|
|
|
|
|
|
vector<StageStats> vssToCount;
|
|
|
|
|
|
|
|
|
|
// Show stats only for the latest 3 normal songs + passed extra stages
|
|
|
|
|
int PassedRegularSongsLeft = 3;
|
|
|
|
|
for( int i = (int)m_vPlayedStageStats.size()-1; i >= 0; --i )
|
|
|
|
|
{
|
|
|
|
|
const StageStats &ss = m_vPlayedStageStats[i];
|
|
|
|
|
|
|
|
|
|
if( !ss.OnePassed() )
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if( ss.StageType == StageStats::STAGE_NORMAL )
|
|
|
|
|
{
|
|
|
|
|
if( PassedRegularSongsLeft == 0 )
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
--PassedRegularSongsLeft;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vssToCount.push_back( ss );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
statsOut = AccumStageStats( vssToCount );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void StatsManager::CalcAccumStageStats()
|
|
|
|
|
{
|
|
|
|
|
m_AccumStageStats = AccumStageStats( m_vPlayedStageStats );
|
|
|
|
|
}
|
|
|
|
|
|
2005-02-23 04:32:45 +00:00
|
|
|
/* This data is added to each player profile, and to the machine profile per-player. */
|
|
|
|
|
void AddPlayerStatsToProfile( Profile *pProfile, const StageStats &ss, PlayerNumber pn )
|
|
|
|
|
{
|
|
|
|
|
ss.AssertValid( pn );
|
|
|
|
|
CHECKPOINT;
|
|
|
|
|
|
|
|
|
|
StyleID sID;
|
|
|
|
|
sID.FromStyle( ss.pStyle );
|
|
|
|
|
|
2005-04-20 06:13:06 +00:00
|
|
|
ASSERT( ss.vpPlayedSongs.size() == ss.m_player[pn].vpPlayedSteps.size() );
|
|
|
|
|
for( unsigned i=0; i<ss.vpPlayedSongs.size(); i++ )
|
2005-02-23 04:32:45 +00:00
|
|
|
{
|
2005-04-20 06:13:06 +00:00
|
|
|
Steps *pSteps = ss.m_player[pn].vpPlayedSteps[i];
|
2005-02-23 04:32:45 +00:00
|
|
|
|
|
|
|
|
pProfile->m_iNumSongsPlayedByPlayMode[ss.playMode]++;
|
|
|
|
|
pProfile->m_iNumSongsPlayedByStyle[sID] ++;
|
|
|
|
|
pProfile->m_iNumSongsPlayedByDifficulty[pSteps->GetDifficulty()] ++;
|
|
|
|
|
|
|
|
|
|
int iMeter = clamp( pSteps->GetMeter(), 0, MAX_METER );
|
|
|
|
|
pProfile->m_iNumSongsPlayedByMeter[iMeter] ++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pProfile->m_iTotalDancePoints += ss.m_player[pn].iActualDancePoints;
|
|
|
|
|
|
|
|
|
|
if( ss.StageType == StageStats::STAGE_EXTRA || ss.StageType == StageStats::STAGE_EXTRA2 )
|
|
|
|
|
{
|
|
|
|
|
if( ss.m_player[pn].bFailed )
|
|
|
|
|
++pProfile->m_iNumExtraStagesFailed;
|
|
|
|
|
else
|
|
|
|
|
++pProfile->m_iNumExtraStagesPassed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If you fail in a course, you passed all but the final song.
|
|
|
|
|
// FIXME: Not true. If playing with 2 players, one player could have failed earlier.
|
|
|
|
|
if( !ss.m_player[pn].bFailed )
|
|
|
|
|
{
|
|
|
|
|
pProfile->m_iNumStagesPassedByPlayMode[ss.playMode] ++;
|
|
|
|
|
pProfile->m_iNumStagesPassedByGrade[ss.m_player[pn].GetGrade()] ++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void StatsManager::CommitStatsToProfiles()
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
// Add step totals. Use radarActual, since the player might have failed part way
|
|
|
|
|
// through the song, in which case we don't want to give credit for the rest of the
|
|
|
|
|
// song.
|
|
|
|
|
//
|
|
|
|
|
FOREACH_HumanPlayer( pn )
|
|
|
|
|
{
|
2005-02-23 19:29:49 +00:00
|
|
|
int iNumTapsAndHolds = (int) m_CurStageStats.m_player[pn].radarActual[RADAR_NUM_TAPS_AND_HOLDS];
|
|
|
|
|
int iNumJumps = (int) m_CurStageStats.m_player[pn].radarActual[RADAR_NUM_JUMPS];
|
|
|
|
|
int iNumHolds = (int) m_CurStageStats.m_player[pn].radarActual[RADAR_NUM_HOLDS];
|
2005-04-25 11:42:19 +00:00
|
|
|
int iNumRolls = (int) m_CurStageStats.m_player[pn].radarActual[RADAR_NUM_ROLLS];
|
2005-02-23 19:29:49 +00:00
|
|
|
int iNumMines = (int) m_CurStageStats.m_player[pn].radarActual[RADAR_NUM_MINES];
|
|
|
|
|
int iNumHands = (int) m_CurStageStats.m_player[pn].radarActual[RADAR_NUM_HANDS];
|
|
|
|
|
float fCaloriesBurned = m_CurStageStats.m_player[pn].fCaloriesBurned;
|
2005-04-25 11:42:19 +00:00
|
|
|
PROFILEMAN->AddStepTotals( pn, iNumTapsAndHolds, iNumJumps, iNumHolds, iNumRolls, iNumMines, iNumHands, fCaloriesBurned );
|
2005-02-23 04:32:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Update profile stats
|
|
|
|
|
Profile* pMachineProfile = PROFILEMAN->GetMachineProfile();
|
|
|
|
|
|
2005-02-23 19:29:49 +00:00
|
|
|
int iGameplaySeconds = (int)truncf(m_CurStageStats.fGameplaySeconds);
|
2005-02-23 04:32:45 +00:00
|
|
|
|
|
|
|
|
pMachineProfile->m_iTotalGameplaySeconds += iGameplaySeconds;
|
|
|
|
|
pMachineProfile->m_iCurrentCombo = 0;
|
2005-04-20 06:13:06 +00:00
|
|
|
pMachineProfile->m_iNumTotalSongsPlayed += m_CurStageStats.vpPlayedSongs.size();
|
2005-02-23 04:32:45 +00:00
|
|
|
|
|
|
|
|
CHECKPOINT;
|
|
|
|
|
FOREACH_HumanPlayer( pn )
|
|
|
|
|
{
|
|
|
|
|
CHECKPOINT;
|
|
|
|
|
|
|
|
|
|
Profile* pPlayerProfile = PROFILEMAN->GetProfile( pn );
|
|
|
|
|
if( pPlayerProfile )
|
|
|
|
|
{
|
|
|
|
|
pPlayerProfile->m_iTotalGameplaySeconds += iGameplaySeconds;
|
|
|
|
|
pPlayerProfile->m_iCurrentCombo =
|
|
|
|
|
PREFSMAN->m_bComboContinuesBetweenSongs ?
|
2005-02-23 19:29:49 +00:00
|
|
|
m_CurStageStats.m_player[pn].iCurCombo :
|
2005-02-23 04:32:45 +00:00
|
|
|
0;
|
2005-04-20 06:13:06 +00:00
|
|
|
pPlayerProfile->m_iNumTotalSongsPlayed += m_CurStageStats.vpPlayedSongs.size();
|
2005-02-23 04:32:45 +00:00
|
|
|
}
|
|
|
|
|
|
2005-02-23 22:52:03 +00:00
|
|
|
AddPlayerStatsToProfile( pMachineProfile, m_CurStageStats, pn );
|
2005-02-23 04:32:45 +00:00
|
|
|
|
|
|
|
|
if( pPlayerProfile )
|
2005-02-23 22:52:03 +00:00
|
|
|
AddPlayerStatsToProfile( pPlayerProfile, m_CurStageStats, pn );
|
2005-02-23 04:32:45 +00:00
|
|
|
|
|
|
|
|
CHECKPOINT;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2005-02-16 19:40:09 +00:00
|
|
|
|
2005-02-16 03:25:45 +00:00
|
|
|
// lua start
|
|
|
|
|
#include "LuaBinding.h"
|
|
|
|
|
|
|
|
|
|
template<class T>
|
|
|
|
|
class LunaStatsManager : public Luna<T>
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
LunaStatsManager() { LUA->Register( Register ); }
|
|
|
|
|
|
|
|
|
|
static int GetCurStageStats( T* p, lua_State *L ) { p->m_CurStageStats.PushSelf(L); return 1; }
|
2005-02-16 19:40:09 +00:00
|
|
|
static int GetAccumStageStats( T* p, lua_State *L ) { p->GetAccumStageStats().PushSelf(L); return 1; }
|
2005-04-15 11:51:13 +00:00
|
|
|
static int Reset( T* p, lua_State *L ) { p->Reset(); return 1; }
|
2005-05-29 01:50:12 +00:00
|
|
|
static int GetFinalGrade( T* p, lua_State *L )
|
|
|
|
|
{
|
|
|
|
|
PlayerNumber pn = (PlayerNumber)IArg(1);
|
|
|
|
|
|
|
|
|
|
if( !GAMESTATE->IsHumanPlayer(pn) )
|
|
|
|
|
lua_pushnumber( L, GRADE_NO_DATA );
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
StageStats stats;
|
|
|
|
|
p->GetFinalEvalStageStats( stats );
|
|
|
|
|
lua_pushnumber( L, stats.m_player[pn].GetGrade() );
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int OneGotGrade( T* p, lua_State *L )
|
|
|
|
|
{
|
|
|
|
|
int n = IArg(1);
|
|
|
|
|
Grade g = (Grade) IArg(2);
|
|
|
|
|
|
|
|
|
|
bool bRet = false;
|
|
|
|
|
FOREACH_HumanPlayer( pn )
|
|
|
|
|
if( GetGrade( n, pn ) == g )
|
|
|
|
|
bRet = true;
|
|
|
|
|
|
|
|
|
|
lua_pushboolean( L, bRet );
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2005-02-16 03:25:45 +00:00
|
|
|
|
|
|
|
|
static void Register(lua_State *L)
|
|
|
|
|
{
|
|
|
|
|
ADD_METHOD( GetCurStageStats )
|
2005-02-16 19:40:09 +00:00
|
|
|
ADD_METHOD( GetAccumStageStats )
|
2005-04-15 11:51:13 +00:00
|
|
|
ADD_METHOD( Reset )
|
2005-05-29 01:50:12 +00:00
|
|
|
ADD_METHOD( GetFinalGrade )
|
|
|
|
|
ADD_METHOD( OneGotGrade )
|
2005-04-15 11:51:13 +00:00
|
|
|
|
2005-02-16 03:25:45 +00:00
|
|
|
Luna<T>::Register( L );
|
2005-02-16 17:35:58 +00:00
|
|
|
|
|
|
|
|
// Add global singleton if constructed already. If it's not constructed yet,
|
|
|
|
|
// then we'll register it later when we reinit Lua just before
|
|
|
|
|
// initializing the display.
|
|
|
|
|
if( STATSMAN )
|
|
|
|
|
{
|
|
|
|
|
lua_pushstring(L, "STATSMAN");
|
|
|
|
|
STATSMAN->PushSelf( LUA->L );
|
|
|
|
|
lua_settable(L, LUA_GLOBALSINDEX);
|
|
|
|
|
}
|
2005-02-16 03:25:45 +00:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
LUA_REGISTER_CLASS( StatsManager )
|
|
|
|
|
// lua end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Old Lua
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
static Grade GetBestGrade()
|
|
|
|
|
{
|
|
|
|
|
Grade g = NUM_GRADES;
|
|
|
|
|
FOREACH_EnabledPlayer( pn )
|
|
|
|
|
g = min( g, STATSMAN->m_CurStageStats.m_player[pn].GetGrade() );
|
|
|
|
|
return g;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static Grade GetWorstGrade()
|
|
|
|
|
{
|
2005-03-31 06:14:28 +00:00
|
|
|
Grade g = GRADE_TIER01;
|
2005-02-16 03:25:45 +00:00
|
|
|
FOREACH_EnabledPlayer( pn )
|
|
|
|
|
g = max( g, STATSMAN->m_CurStageStats.m_player[pn].GetGrade() );
|
|
|
|
|
return g;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#include "LuaFunctions.h"
|
|
|
|
|
LuaFunction_NoArgs( GetStagesPlayed, (int) STATSMAN->m_vPlayedStageStats.size() );
|
|
|
|
|
LuaFunction_NoArgs( GetBestGrade, GetBestGrade() );
|
|
|
|
|
LuaFunction_NoArgs( GetWorstGrade, GetWorstGrade() );
|
|
|
|
|
LuaFunction_NoArgs( OnePassed, STATSMAN->m_CurStageStats.OnePassed() );
|
|
|
|
|
LuaFunction_NoArgs( AllFailed, STATSMAN->m_CurStageStats.AllFailed() );
|
2005-05-29 02:21:24 +00:00
|
|
|
LuaFunction( Grade, StringToGrade( SArg(1) ) );
|
2005-02-16 03:25:45 +00:00
|
|
|
|
|
|
|
|
const StageStats *GetStageStatsN( int n )
|
|
|
|
|
{
|
|
|
|
|
if( n == (int) STATSMAN->m_vPlayedStageStats.size() )
|
|
|
|
|
return &STATSMAN->m_CurStageStats;
|
|
|
|
|
if( n > (int) STATSMAN->m_vPlayedStageStats.size() )
|
|
|
|
|
return NULL;
|
|
|
|
|
return &STATSMAN->m_vPlayedStageStats[n];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* GetGrade(0) returns the first grade; GetGrade(1) returns the second grade, and
|
|
|
|
|
* and so on. GetGrade(GetStagesPlayed()) returns the current grade (from STATSMAN->m_CurStageStats).
|
|
|
|
|
* If beyond the current song played, return GRADE_NO_DATA. */
|
|
|
|
|
Grade GetGrade( int n, PlayerNumber pn )
|
|
|
|
|
{
|
|
|
|
|
const StageStats *pStats = GetStageStatsN( n );
|
|
|
|
|
if( pStats == NULL )
|
|
|
|
|
return GRADE_NO_DATA;
|
|
|
|
|
return pStats->m_player[pn].GetGrade();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Grade GetBestFinalGrade()
|
|
|
|
|
{
|
|
|
|
|
Grade top_grade = GRADE_FAILED;
|
|
|
|
|
StageStats stats;
|
2005-02-16 19:40:09 +00:00
|
|
|
STATSMAN->GetFinalEvalStageStats( stats );
|
2005-02-16 03:25:45 +00:00
|
|
|
FOREACH_HumanPlayer( p )
|
|
|
|
|
top_grade = min( top_grade, stats.m_player[p].GetGrade() );
|
|
|
|
|
return top_grade;
|
|
|
|
|
}
|
|
|
|
|
LuaFunction_NoArgs( GetBestFinalGrade, GetBestFinalGrade() );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* (c) 2001-2004 Chris Danford
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|