Files
itgmania212121/stepmania/src/StatsManager.cpp
T

378 lines
11 KiB
C++
Raw Normal View History

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"
#include "ProfileManager.h"
2005-07-01 05:07:22 +00:00
#include "Profile.h"
#include "PrefsManager.h"
#include "Steps.h"
2005-07-01 05:07:22 +00:00
#include "StyleUtil.h"
#include "LuaManager.h"
2005-02-16 03:25:45 +00:00
StatsManager* STATSMAN = NULL; // global object accessable from anywhere in the program
StatsManager::StatsManager()
{
// Register with Lua.
{
Lua *L = LUA->Get();
lua_pushstring( L, "STATSMAN" );
2006-09-23 03:06:29 +00:00
this->PushSelf( L );
lua_settable(L, LUA_GLOBALSINDEX);
LUA->Release( L );
}
}
StatsManager::~StatsManager()
{
// Unregister with Lua.
LUA->UnsetGlobal( "STATSMAN" );
2005-02-16 03:25:45 +00:00
}
2005-06-02 04:32:51 +00:00
void StatsManager::Reset()
{
m_CurStageStats.Init();
m_vPlayedStageStats.clear();
2006-07-03 00:04:30 +00:00
m_AccumPlayedStageStats.Init();
2005-06-02 04:32:51 +00:00
2006-07-03 00:04:30 +00:00
CalcAccumPlayedStageStats();
2005-06-02 04:32:51 +00:00
}
2006-07-03 00:04:30 +00:00
static StageStats AccumPlayedStageStats( const vector<StageStats>& vss )
2005-02-16 19:40:09 +00:00
{
StageStats ssreturn;
if( !vss.empty() )
{
ssreturn.m_pStyle = vss[0].m_pStyle;
ssreturn.m_playMode = vss[0].m_playMode;
}
2005-02-16 19:40:09 +00:00
FOREACH_CONST( StageStats, vss, ss )
ssreturn.AddStats( *ss );
unsigned uNumSongs = ssreturn.m_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 RadarCategory_TapsAndHolds
2005-02-16 19:40:09 +00:00
* and the rest, which are counters. */
// FIXME: Weight each song by the number of stages it took to account for
// long, marathon.
2005-08-23 20:49:30 +00:00
FOREACH_EnabledPlayer( p )
2005-02-16 19:40:09 +00:00
{
for( int r = 0; r < RadarCategory_TapsAndHolds; r++)
2005-02-16 19:40:09 +00:00
{
ssreturn.m_player[p].m_radarPossible[r] /= uNumSongs;
ssreturn.m_player[p].m_radarActual[r] /= uNumSongs;
2005-08-23 20:49:30 +00:00
}
}
FOREACH_EnabledMultiPlayer( p )
{
for( int r = 0; r < RadarCategory_TapsAndHolds; r++)
2005-08-23 20:49:30 +00:00
{
ssreturn.m_multiPlayer[p].m_radarPossible[r] /= uNumSongs;
ssreturn.m_multiPlayer[p].m_radarActual[r] /= uNumSongs;
2005-02-16 19:40:09 +00:00
}
}
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;
2008-03-29 11:41:16 +00:00
if( ss.m_Stage != Stage_Extra1 && ss.m_Stage != Stage_Extra2 )
2005-02-16 19:40:09 +00:00
{
if( PassedRegularSongsLeft == 0 )
break;
--PassedRegularSongsLeft;
}
vssToCount.push_back( ss );
}
2006-07-03 00:04:30 +00:00
statsOut = AccumPlayedStageStats( vssToCount );
2005-02-16 19:40:09 +00:00
}
2006-07-03 00:04:30 +00:00
void StatsManager::CalcAccumPlayedStageStats()
2005-02-16 19:40:09 +00:00
{
2006-07-03 00:04:30 +00:00
m_AccumPlayedStageStats = AccumPlayedStageStats( m_vPlayedStageStats );
2005-02-16 19:40:09 +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.m_pStyle );
ASSERT( (int) ss.m_vpPlayedSongs.size() == ss.m_player[pn].m_iStepsPlayed );
for( int i=0; i<ss.m_player[pn].m_iStepsPlayed; i++ )
{
Steps *pSteps = ss.m_player[pn].m_vpPossibleSteps[i];
pProfile->m_iNumSongsPlayedByPlayMode[ss.m_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].m_iActualDancePoints;
2008-03-29 11:41:16 +00:00
if( ss.m_Stage == Stage_Extra1 || ss.m_Stage == Stage_Extra2 )
{
if( ss.m_player[pn].m_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].m_bFailed )
{
pProfile->m_iNumStagesPassedByPlayMode[ss.m_playMode] ++;
pProfile->m_iNumStagesPassedByGrade[ss.m_player[pn].GetGrade()] ++;
}
}
2007-04-25 16:22:30 +00:00
void StatsManager::CommitStatsToProfiles( const StageStats *pSS )
{
2007-07-13 10:42:15 +00:00
if( GAMESTATE->m_bMultiplayer )
return;
//
// 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 )
{
2007-04-25 16:22:30 +00:00
int iNumTapsAndHolds = (int) pSS->m_player[pn].m_radarActual[RadarCategory_TapsAndHolds];
int iNumJumps = (int) pSS->m_player[pn].m_radarActual[RadarCategory_Jumps];
int iNumHolds = (int) pSS->m_player[pn].m_radarActual[RadarCategory_Holds];
int iNumRolls = (int) pSS->m_player[pn].m_radarActual[RadarCategory_Rolls];
int iNumMines = (int) pSS->m_player[pn].m_radarActual[RadarCategory_Mines];
int iNumHands = (int) pSS->m_player[pn].m_radarActual[RadarCategory_Hands];
float fCaloriesBurned = pSS->m_player[pn].m_fCaloriesBurned;
2005-04-25 11:42:19 +00:00
PROFILEMAN->AddStepTotals( pn, iNumTapsAndHolds, iNumJumps, iNumHolds, iNumRolls, iNumMines, iNumHands, fCaloriesBurned );
}
// Update profile stats
Profile* pMachineProfile = PROFILEMAN->GetMachineProfile();
2007-04-25 16:22:30 +00:00
int iGameplaySeconds = (int)truncf(pSS->m_fGameplaySeconds);
pMachineProfile->m_iTotalGameplaySeconds += iGameplaySeconds;
2007-04-25 16:22:30 +00:00
pMachineProfile->m_iNumTotalSongsPlayed += pSS->m_vpPlayedSongs.size();
CHECKPOINT;
FOREACH_HumanPlayer( pn )
{
CHECKPOINT;
Profile* pPlayerProfile = PROFILEMAN->GetProfile( pn );
if( pPlayerProfile )
{
pPlayerProfile->m_iTotalGameplaySeconds += iGameplaySeconds;
2007-04-25 16:22:30 +00:00
pPlayerProfile->m_iNumTotalSongsPlayed += pSS->m_vpPlayedSongs.size();
}
2007-04-25 16:22:30 +00:00
AddPlayerStatsToProfile( pMachineProfile, *pSS, pn );
if( pPlayerProfile )
2007-04-25 16:22:30 +00:00
AddPlayerStatsToProfile( pPlayerProfile, *pSS, pn );
CHECKPOINT;
}
}
2007-04-19 14:34:42 +00:00
void StatsManager::UnjoinPlayer( PlayerNumber pn )
{
/* A player has been unjoined. Clear his data from m_vPlayedStageStats, and
* purge any m_vPlayedStageStats that no longer have any player data because
* all of the players that were playing at the time have been unjoined. */
FOREACH( StageStats, m_vPlayedStageStats, ss )
ss->m_player[pn] = PlayerStageStats();
for( int i = 0; i < (int) m_vPlayedStageStats.size(); ++i )
{
StageStats &ss = m_vPlayedStageStats[i];
bool bIsActive = false;
FOREACH_PlayerNumber( p )
if( ss.m_player[p].m_bJoined )
bIsActive = true;
FOREACH_MultiPlayer( mp )
if( ss.m_multiPlayer[mp].m_bJoined )
bIsActive = true;
if( bIsActive )
continue;
m_vPlayedStageStats.erase( m_vPlayedStageStats.begin()+i );
--i;
}
}
2007-04-19 14:34:42 +00:00
void StatsManager::GetStepsInUse( set<Steps*> &apInUseOut ) const
{
for( int i = 0; i < (int) m_vPlayedStageStats.size(); ++i )
{
FOREACH_PlayerNumber( pn )
{
const PlayerStageStats &pss = m_vPlayedStageStats[i].m_player[pn];
apInUseOut.insert( pss.m_vpPossibleSteps.begin(), pss.m_vpPossibleSteps.end() );
}
FOREACH_MultiPlayer( mp )
{
const PlayerStageStats &pss = m_vPlayedStageStats[i].m_multiPlayer[mp];
apInUseOut.insert( pss.m_vpPossibleSteps.begin(), pss.m_vpPossibleSteps.end() );
}
}
2007-04-19 14:34:42 +00:00
}
2005-02-16 19:40:09 +00:00
2005-02-16 03:25:45 +00:00
// lua start
#include "LuaBinding.h"
2005-06-20 05:02:03 +00:00
class LunaStatsManager: public Luna<StatsManager>
2005-02-16 03:25:45 +00:00
{
public:
static int GetCurStageStats( T* p, lua_State *L ) { p->m_CurStageStats.PushSelf(L); return 1; }
2007-03-14 04:26:32 +00:00
static int GetPlayedStageStats( T* p, lua_State *L )
{
int iAgo = IArg(1);
int iIndex = p->m_vPlayedStageStats.size() - iAgo;
if( iIndex < 0 || iIndex >= (int) p->m_vPlayedStageStats.size() )
return 0;
p->m_vPlayedStageStats[iIndex].PushSelf(L);
return 1;
}
2006-04-21 00:12:59 +00:00
static int Reset( T* p, lua_State *L ) { p->Reset(); return 0; }
2007-03-14 04:26:32 +00:00
static int GetAccumPlayedStageStats( T* p, lua_State *L ) { p->GetAccumPlayedStageStats().PushSelf(L); return 1; }
2005-05-29 01:50:12 +00:00
static int GetFinalGrade( T* p, lua_State *L )
{
2006-09-27 01:48:30 +00:00
PlayerNumber pn = Enum::Check<PlayerNumber>(L, 1);
2005-05-29 01:50:12 +00:00
if( !GAMESTATE->IsHumanPlayer(pn) )
lua_pushnumber( L, Grade_NoData );
2005-05-29 01:50:12 +00:00
else
{
StageStats stats;
p->GetFinalEvalStageStats( stats );
lua_pushnumber( L, stats.m_player[pn].GetGrade() );
}
return 1;
}
2005-05-30 00:42:31 +00:00
static int GetStagesPlayed( T* p, lua_State *L ) { lua_pushnumber( L, p->m_vPlayedStageStats.size() ); return 1; }
2005-05-29 01:50:12 +00:00
2005-05-30 00:42:31 +00:00
static int GetBestGrade( T* p, lua_State *L )
2005-05-29 01:50:12 +00:00
{
Grade g = NUM_Grade;
2005-05-30 00:42:31 +00:00
FOREACH_EnabledPlayer( pn )
g = min( g, STATSMAN->m_CurStageStats.m_player[pn].GetGrade() );
lua_pushnumber( L, g );
return 1;
}
2005-05-29 01:50:12 +00:00
2005-05-30 00:42:31 +00:00
static int GetWorstGrade( T* p, lua_State *L )
{
Grade g = Grade_Tier01;
2005-05-30 00:42:31 +00:00
FOREACH_EnabledPlayer( pn )
g = max( g, STATSMAN->m_CurStageStats.m_player[pn].GetGrade() );
lua_pushnumber( L, g );
2005-05-29 01:50:12 +00:00
return 1;
}
2005-02-16 03:25:45 +00:00
2006-09-29 09:44:56 +00:00
static int GetBestFinalGrade( T* p, lua_State *L )
{
Grade top_grade = Grade_Failed;
StageStats stats;
p->GetFinalEvalStageStats( stats );
FOREACH_HumanPlayer( p )
{
// If this player failed any stage, then their final grade is an F.
bool bPlayerFailedOneStage = false;
FOREACH_CONST( StageStats, STATSMAN->m_vPlayedStageStats, ss )
{
if( ss->m_player[p].m_bFailed )
2006-09-29 09:44:56 +00:00
{
bPlayerFailedOneStage = true;
break;
}
}
if( bPlayerFailedOneStage )
continue;
top_grade = min( top_grade, stats.m_player[p].GetGrade() );
}
Enum::Push( L, top_grade );
return 1;
}
2006-09-27 20:30:29 +00:00
LunaStatsManager()
2005-02-16 03:25:45 +00:00
{
ADD_METHOD( GetCurStageStats );
2007-03-14 04:26:32 +00:00
ADD_METHOD( GetPlayedStageStats );
2006-07-03 00:04:30 +00:00
ADD_METHOD( GetAccumPlayedStageStats );
ADD_METHOD( Reset );
ADD_METHOD( GetFinalGrade );
ADD_METHOD( GetStagesPlayed );
ADD_METHOD( GetBestGrade );
ADD_METHOD( GetWorstGrade );
2006-09-29 09:44:56 +00:00
ADD_METHOD( GetBestFinalGrade );
2005-02-16 03:25:45 +00:00
}
};
LUA_REGISTER_CLASS( StatsManager )
// lua end
/*
* (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.
*/