void ScoreDisplayOni::Update( float fDelta ) { ScoreDisplay::Update( fDelta ); float fSecsIntoPlay = 0; if( GAMESTATE->IsPlayerEnabled(m_PlayerNumber) ) fSecsIntoPlay = g_CurStageStats.fAliveSeconds[m_PlayerNumber]; m_text.SetText( SecondsToMMSSMsMs(fSecsIntoPlay) ); }
void ScoreDisplayAliveTime::UpdateNumber() { float fSecsIntoPlay = 0; ASSERT( m_PlayerNumber != PLAYER_INVALID ); if( GAMESTATE->IsPlayerEnabled(m_PlayerNumber) ) fSecsIntoPlay = STATSMAN->GetAccumStageStats().m_player[m_PlayerNumber].fAliveSeconds + STATSMAN->m_CurStageStats.m_player[m_PlayerNumber].fAliveSeconds; SetText( SecondsToMMSSMsMs(fSecsIntoPlay) ); }
ScreenEndlessBreak::ScreenEndlessBreak( CString sName ) : Screen( sName ) { LOG->Trace("ScreenEndlessBreak()"); ASSERT(GAMESTATE->GetNumPlayersEnabled() > 0); // This should never happen.. but just in case PostScreenMessage( SM_BreakInitiated, 0 ); if( (int)PREFSMAN->m_ShowDancingCharacters != 0 ) { if( GAMESTATE->GetNumPlayersEnabled() == 1 ) if( GAMESTATE->m_pCurCharacters[0] != NULL ) m_sprBreakPicture.LoadTABreakFromCharacter( GAMESTATE->m_pCurCharacters[0] ); else m_sprBreakPicture.Load( THEME->GetPathG("Common","fallback takingabreak") ); else if( GAMESTATE->GetNumPlayersEnabled() > 1 ) // More than 1 player is present. { PlayerNumber pn; do { pn = (PlayerNumber)(rand()%NUM_PLAYERS); if( GAMESTATE->IsPlayerEnabled(pn) && (GAMESTATE->m_pCurCharacters[pn] != NULL) ) { m_sprBreakPicture.LoadTABreakFromCharacter( GAMESTATE->m_pCurCharacters[pn] ); break; } } while( !GAMESTATE->IsPlayerEnabled(pn) ); } } else // Characters not enabled. m_sprBreakPicture.Load( THEME->GetPathG("Common","fallback takingabreak") ); m_sprBreakPicture.SetX( SCREEN_CENTER_X ); m_sprBreakPicture.SetY( SCREEN_CENTER_Y ); this->AddChild(&m_sprBreakPicture); // Set up our countdown clock. m_fCountdownSecs = (float)(PREFSMAN->m_iEndlessBreakLength*60); // Stored in minutes. //BitmapText stuff m_textTimeRemaining.LoadFromFont( THEME->GetPathF("Common","normal") ); m_textTimeRemaining.SetText( SecondsToMMSSMsMs(m_fCountdownSecs) ); m_textTimeRemaining.SetX( SCREEN_CENTER_X ); m_textTimeRemaining.SetY( SCREEN_CENTER_Y ); //Transition stuff m_In.Load( THEME->GetPathB("ScreenEndlessBreak","In") ); this->AddChild(&m_In); m_In.StartTransitioning(); m_Out.Load( THEME->GetPathB("ScreenEndlessBreak","Out") ); this->AddChild(&m_Out); m_bExiting = false; }
void ScreenEndlessBreak::Update(float fDeltaTime) { m_textTimeRemaining.SetText( SecondsToMMSSMsMs(m_fCountdownSecs) ); if( !m_bExiting ) if(m_fCountdownSecs <= 0) { m_bExiting = true; SCREENMAN->PopTopScreen(SM_BreakCompleted); // Destroy this screen and let ScreenGameplay get the message. m_Out.StartTransitioning(); } else //m_fCountdownSecs--; m_fCountdownSecs = (m_fCountdownSecs - fDeltaTime); Screen::Update( fDeltaTime ); }
void ScreenSystemLayer::UpdateSkips() { if( !PREFSMAN->m_bTimestamping && !PREFSMAN->m_bLogSkips ) return; /* Use our own timer, so we ignore `/tab. */ const float UpdateTime = SkipTimer.GetDeltaTime(); /* FPS is 0 for a little while after we load a screen; don't report * during this time. Do clear the timer, though, so we don't report * a big "skip" after this period passes. */ if( !DISPLAY->GetFPS() ) return; /* We want to display skips. We expect to get updates of about 1.0/FPS ms. */ const float ExpectedUpdate = 1.0f / DISPLAY->GetFPS(); /* These are thresholds for severity of skips. The smallest * is slightly above expected, to tolerate normal jitter. */ const float Thresholds[] = { ExpectedUpdate * 2.0f, ExpectedUpdate * 4.0f, 0.1f, -1 }; int skip = 0; while( Thresholds[skip] != -1 && UpdateTime > Thresholds[skip] ) skip++; if( skip ) { CString time(SecondsToMMSSMsMs(RageTimer::GetTimeSinceStartFast())); static const RageColor colors[] = { RageColor(0,0,0,0), /* unused */ RageColor(0.2f,0.2f,1,1), /* light blue */ RageColor(1,1,0,1), /* yellow */ RageColor(1,0.2f,0.2f,1) /* light red */ }; if( PREFSMAN->m_bTimestamping ) AddTimestampLine( ssprintf("%s: %.0fms (%.0f)", time.c_str(), 1000*UpdateTime, UpdateTime/ExpectedUpdate), colors[skip] ); if( PREFSMAN->m_bLogSkips ) LOG->Trace( "Frame skip: %.0fms (%.0f)", 1000*UpdateTime, UpdateTime/ExpectedUpdate ); } }
void ScreenSystemLayer::Update( float fDeltaTime ) { Screen::Update(fDeltaTime); if( PREFSMAN && (bool)PREFSMAN->m_bShowStats ) { m_textStats.SetDiffuse( RageColor(1,1,1,0.7f) ); m_textStats.SetText( DISPLAY->GetStats() ); } else { m_textStats.SetDiffuse( RageColor(1,1,1,0) ); /* hide */ } UpdateSkips(); if( PREFSMAN->m_bTimestamping ) m_textTime.SetText( SecondsToMMSSMsMs(RageTimer::GetTimeSinceStartFast()) ); }
float ScreenRanking::SetPage( PageToShow pts ) { bool bBanner = false; bool bBannerFrame = false; bool bShowCategory = false; bool bShowCourseTitle = false; bool bShowStepsType = false; bool bShowBullets = false; bool bShowNames = false; bool bShowScores = false; bool bShowPoints = false; bool bShowTime = false; bool bShowDifficulty = false; bool bShowStepsScore = false; bool bShowCourseDifficulty = false; bool bShowCourseScore = false; switch( pts.type ) { case PAGE_TYPE_CATEGORY: bBanner = false; bBannerFrame = false; bShowCategory = true; bShowCourseTitle = false; bShowStepsType = true; bShowBullets = true; bShowNames = true; bShowScores = true; bShowPoints = false; bShowTime = false; bShowDifficulty = false; bShowStepsScore = false; break; case PAGE_TYPE_TRAIL: bBanner = true; bBannerFrame = true; bShowCategory = false; bShowCourseTitle = true; bShowStepsType = true; bShowBullets = true; bShowNames = true; bShowScores = !pts.pCourse->IsOni(); bShowPoints = pts.pCourse->IsOni(); bShowTime = pts.pCourse->IsOni(); bShowDifficulty = false; bShowStepsScore = false; break; case PAGE_TYPE_ALL_STEPS: bBanner = false; bBannerFrame = false; bShowCategory = false; bShowCourseTitle = false; bShowStepsType = true; bShowBullets = false; bShowNames = false; bShowScores = false; bShowPoints = false; bShowTime = false; bShowDifficulty = true; bShowStepsScore = true; break; case PAGE_TYPE_ALL_COURSES: bShowStepsType = true; bShowCourseScore = true; bShowCourseDifficulty = true; break; default: ASSERT(0); } // Reset m_Banner.SetHidden( !bBanner ); if( bBanner ) { m_Banner.Reset(); SET_XY_AND_ON_COMMAND( m_Banner ); } m_sprBannerFrame.SetHidden( !bBannerFrame ); if( bBannerFrame ) { m_sprBannerFrame.Reset(); SET_XY_AND_ON_COMMAND( m_sprBannerFrame ); } m_textCategory.SetHidden( !bShowCategory ); if( bShowCategory ) { m_textCategory.Reset(); SET_XY_AND_ON_COMMAND( m_textCategory ); } m_textCourseTitle.SetHidden( !bShowCourseTitle ); if( bShowCourseTitle ) { m_textCourseTitle.Reset(); SET_XY_AND_ON_COMMAND( m_textCourseTitle ); } m_textStepsType.SetHidden( !bShowStepsType ); if( bShowStepsType ) { m_textStepsType.Reset(); SET_XY_AND_ON_COMMAND( m_textStepsType ); } // UGLY: We have to call AddChild every time we re-load an AutoActor // because the internal Actor* changes. if( (Actor*)m_sprPageType ) this->RemoveChild( m_sprPageType ); m_sprPageType.Load( THEME->GetPathG(m_sName, "PageType "+PageTypeToString(pts.type)) ); m_sprPageType->SetName( "PageType" ); this->AddChild( m_sprPageType ); SET_XY_AND_ON_COMMAND( m_sprPageType ); { for( int l=0; l<NUM_RANKING_LINES; l++ ) { m_sprBullets[l].SetHidden( !bShowBullets ); if( bShowBullets ) { m_sprBullets[l].Reset(); m_sprBullets[l].StopAnimating(); m_sprBullets[l].SetState( l ); m_sprBullets[l].SetXY( BULLET_X(l), BULLET_Y(l) ); ON_COMMAND( m_sprBullets[l] ); } m_textNames[l].SetHidden( !bShowNames ); if( bShowNames ) { m_textNames[l].Reset(); m_textNames[l].SetXY( NAME_X(l), NAME_Y(l) ); m_textNames[l].SetDiffuse( STEPS_TYPE_COLOR(pts.colorIndex) ); ON_COMMAND( m_textNames[l] ); } m_textScores[l].SetHidden( !bShowScores ); if( bShowScores ) { m_textScores[l].Reset(); m_textScores[l].SetXY( SCORE_X(l), SCORE_Y(l) ); m_textScores[l].SetDiffuse( STEPS_TYPE_COLOR(pts.colorIndex) ); ON_COMMAND( m_textScores[l] ); } m_textPoints[l].SetHidden( !bShowPoints ); if( bShowPoints ) { m_textPoints[l].Reset(); m_textPoints[l].SetXY( POINTS_X(l), POINTS_Y(l) ); m_textPoints[l].SetDiffuse( STEPS_TYPE_COLOR(pts.colorIndex) ); ON_COMMAND( m_textPoints[l] ); } m_textTime[l].SetHidden( !bShowTime ); if( bShowTime ) { m_textTime[l].Reset(); m_textTime[l].SetXY( TIME_X(l), TIME_Y(l) ); m_textTime[l].SetDiffuse( STEPS_TYPE_COLOR(pts.colorIndex) ); ON_COMMAND( m_textTime[l] ); } } } { for( vector<Difficulty>::iterator dc_iter=m_vDiffsToShow.begin(); dc_iter!=m_vDiffsToShow.end(); dc_iter++ ) { m_sprDifficulty[*dc_iter]->SetHidden( !bShowDifficulty ); if( bShowDifficulty ) { m_sprDifficulty[*dc_iter]->Reset(); m_sprDifficulty[*dc_iter]->SetXY( DIFFICULTY_X(*dc_iter), DIFFICULTY_Y ); ON_COMMAND( m_sprDifficulty[*dc_iter] ); } } m_ListScoreRowItems.SetHidden( !bShowStepsScore ); if( bShowStepsScore ) { m_ListScoreRowItems.Reset(); SET_XY_AND_ON_COMMAND( m_ListScoreRowItems ); vector<Actor*> vpActors; for( unsigned i=0; i<m_vpStepsScoreRowItem.size(); i++ ) vpActors.push_back( m_vpStepsScoreRowItem[i] ); m_ListScoreRowItems.Load( vpActors, SONG_SCORE_ROWS_TO_SHOW, SCREEN_WIDTH, ROW_SPACING_Y, false, SONG_SCORE_SECONDS_PER_ROW, 0, false ); for( unsigned s=0; s<m_vpStepsScoreRowItem.size(); s++ ) { StepsScoreRowItem *pStepsScoreRowItems = m_vpStepsScoreRowItem[s]; pStepsScoreRowItems->m_sprSongFrame.Reset(); pStepsScoreRowItems->m_sprSongFrame.SetXY( SONG_FRAME_OFFSET_X, SONG_FRAME_OFFSET_Y ); pStepsScoreRowItems->m_sprSongFrame.SetUseZBuffer( true ); ON_COMMAND( pStepsScoreRowItems->m_sprSongFrame ); pStepsScoreRowItems->m_textSongTitle.Reset(); pStepsScoreRowItems->m_textSongTitle.SetXY( SONG_TITLE_OFFSET_X, SONG_TITLE_OFFSET_Y ); pStepsScoreRowItems->m_textSongTitle.SetUseZBuffer( true ); ON_COMMAND( pStepsScoreRowItems->m_textSongTitle ); for( vector<Difficulty>::iterator dc_iter=m_vDiffsToShow.begin(); dc_iter!=m_vDiffsToShow.end(); dc_iter++ ) { pStepsScoreRowItems->m_textStepsScore[*dc_iter].Reset(); pStepsScoreRowItems->m_textStepsScore[*dc_iter].SetXY( STEPS_SCORE_OFFSET_X(*dc_iter), STEPS_SCORE_OFFSET_Y ); pStepsScoreRowItems->m_textStepsScore[*dc_iter].SetUseZBuffer( true ); pStepsScoreRowItems->m_textStepsScore[*dc_iter].SetDiffuse( STEPS_TYPE_COLOR(pts.colorIndex) ); ON_COMMAND( pStepsScoreRowItems->m_textStepsScore[*dc_iter] ); } } } } { FOREACH_ShownCourseDifficulty(d) { m_sprCourseDifficulty[d]->SetHidden( !bShowCourseDifficulty ); if( bShowCourseDifficulty ) { m_sprCourseDifficulty[d]->Reset(); m_sprCourseDifficulty[d]->SetXY( COURSE_DIFFICULTY_X(d), COURSE_DIFFICULTY_Y ); ON_COMMAND( m_sprCourseDifficulty[d] ); } } m_ListCourseRowItems.SetHidden( !bShowCourseScore ); if( bShowCourseScore ) { m_ListCourseRowItems.Reset(); SET_XY_AND_ON_COMMAND( m_ListCourseRowItems ); vector<Actor*> vpActors; for( unsigned i=0; i<m_vpCourseScoreRowItem.size(); i++ ) vpActors.push_back( m_vpCourseScoreRowItem[i] ); m_ListCourseRowItems.Load( vpActors, SONG_SCORE_ROWS_TO_SHOW, SCREEN_WIDTH, ROW_SPACING_Y, false, SONG_SCORE_SECONDS_PER_ROW, 0, false ); for( unsigned s=0; s<m_vpCourseScoreRowItem.size(); s++ ) { CourseScoreRowItem *pCourseScoreRowItem = m_vpCourseScoreRowItem[s]; pCourseScoreRowItem->m_sprSongFrame.Reset(); pCourseScoreRowItem->m_sprSongFrame.SetXY( SONG_FRAME_OFFSET_X, SONG_FRAME_OFFSET_Y ); pCourseScoreRowItem->m_sprSongFrame.SetUseZBuffer( true ); ON_COMMAND( pCourseScoreRowItem->m_sprSongFrame ); pCourseScoreRowItem->m_textSongTitle.Reset(); pCourseScoreRowItem->m_textSongTitle.SetXY( SONG_TITLE_OFFSET_X, SONG_TITLE_OFFSET_Y ); pCourseScoreRowItem->m_textSongTitle.SetUseZBuffer( true ); ON_COMMAND( pCourseScoreRowItem->m_textSongTitle ); FOREACH_ShownCourseDifficulty(d) { pCourseScoreRowItem->m_textStepsScore[d].Reset(); pCourseScoreRowItem->m_textStepsScore[d].SetXY( COURSE_SCORE_OFFSET_X(d), COURSE_SCORE_OFFSET_Y ); pCourseScoreRowItem->m_textStepsScore[d].SetUseZBuffer( true ); pCourseScoreRowItem->m_textStepsScore[d].SetDiffuse( STEPS_TYPE_COLOR(pts.colorIndex) ); ON_COMMAND( pCourseScoreRowItem->m_textStepsScore[d] ); } } } } // get ranking feat list // // init page // switch( pts.type ) { case PAGE_TYPE_CATEGORY: { m_textCategory.SetText( ssprintf("Type %c", 'A'+pts.category) ); m_textStepsType.SetText( GameManager::StepsTypeToThemedString(pts.nt) ); for( int l=0; l<NUM_RANKING_LINES; l++ ) { HighScoreList& hsl = PROFILEMAN->GetMachineProfile()->GetCategoryHighScoreList(pts.nt,pts.category); HighScore hs; bool bRecentHighScore = false; if( l < (int)hsl.vHighScores.size() ) { hs = hsl.vHighScores[l]; CString *psName = &hsl.vHighScores[l].sName; bRecentHighScore = find( GAMESTATE->m_vpsNamesThatWereFilled.begin(), GAMESTATE->m_vpsNamesThatWereFilled.end(), psName ) != GAMESTATE->m_vpsNamesThatWereFilled.end(); } else { hs.sName = NO_SCORE_NAME; } m_textNames[l].SetText( hs.GetDisplayName() ); m_textScores[l].SetText( ssprintf("%09i",hs.iScore) ); m_textNames[l].SetDiffuse( STEPS_TYPE_COLOR(pts.colorIndex) ); m_textScores[l].SetDiffuse( STEPS_TYPE_COLOR(pts.colorIndex) ); if( bRecentHighScore ) { m_textNames[l].SetEffectGlowBlink(0.1f); m_textScores[l].SetEffectGlowBlink(0.1f); } else { m_textNames[l].SetEffectNone(); m_textScores[l].SetEffectNone(); } } } return SECONDS_PER_PAGE; case PAGE_TYPE_TRAIL: { m_textCourseTitle.SetText( pts.pCourse->GetFullDisplayTitle() ); m_Banner.LoadFromCourse( pts.pCourse ); m_textStepsType.SetText( GameManager::StepsTypeToThemedString(pts.nt) ); const HighScoreList &hsl = PROFILEMAN->GetMachineProfile()->GetCourseHighScoreList( pts.pCourse, pts.pTrail ); for( int l=0; l<NUM_RANKING_LINES; l++ ) { HighScore hs; bool bRecentHighScore = false; if( l < (int)hsl.vHighScores.size() ) { hs = hsl.vHighScores[l]; const CString *psName = &hsl.vHighScores[l].sName; bRecentHighScore = find( GAMESTATE->m_vpsNamesThatWereFilled.begin(), GAMESTATE->m_vpsNamesThatWereFilled.end(), psName ) != GAMESTATE->m_vpsNamesThatWereFilled.end(); } else { hs.sName = NO_SCORE_NAME; } m_textNames[l].SetText( hs.GetDisplayName() ); if( pts.pCourse->IsOni() ) { m_textPoints[l].SetText( ssprintf("%04d",hs.iScore) ); m_textTime[l].SetText( SecondsToMMSSMsMs(hs.fSurviveSeconds) ); m_textScores[l].SetText( "" ); } else { m_textPoints[l].SetText( "" ); m_textTime[l].SetText( "" ); m_textScores[l].SetText( ssprintf("%09d",hs.iScore) ); } m_textNames[l].SetDiffuse( STEPS_TYPE_COLOR(pts.colorIndex) ); m_textPoints[l].SetDiffuse( STEPS_TYPE_COLOR(pts.colorIndex) ); m_textTime[l].SetDiffuse( STEPS_TYPE_COLOR(pts.colorIndex) ); m_textScores[l].SetDiffuse( STEPS_TYPE_COLOR(pts.colorIndex) ); if( bRecentHighScore ) { m_textNames[l].SetEffectGlowBlink(0.1f); m_textScores[l].SetEffectGlowBlink(0.1f); } else { m_textNames[l].SetEffectNone(); m_textScores[l].SetEffectNone(); } } } return SECONDS_PER_PAGE; case PAGE_TYPE_ALL_STEPS: { m_textStepsType.SetText( GameManager::StepsTypeToThemedString(pts.nt) ); for( unsigned s=0; s<m_vpStepsScoreRowItem.size(); s++ ) { StepsScoreRowItem *pStepsScoreRowItem = m_vpStepsScoreRowItem[s]; const Song* pSong = pStepsScoreRowItem->m_pSong; pStepsScoreRowItem->m_textSongTitle.SetText( pSong->GetFullDisplayTitle() ); for( vector<Difficulty>::iterator dc_iter = m_vDiffsToShow.begin(); dc_iter != m_vDiffsToShow.end(); dc_iter++ ) { const Steps* pSteps = pSong->GetStepsByDifficulty( pts.nt, *dc_iter, false ); BitmapText* pTextStepsScore = &pStepsScoreRowItem->m_textStepsScore[*dc_iter]; if( pSteps == NULL ) { pTextStepsScore->SetHidden( true ); } else { HighScoreList &hsl = PROFILEMAN->GetMachineProfile()->GetStepsHighScoreList(pSong,pSteps); HighScore hs = hsl.GetTopScore(); bool bRecentHighScore = false; if( !hsl.vHighScores.empty() ) { hs = hsl.GetTopScore(); const CString *psName = &hsl.GetTopScore().sName; bRecentHighScore = find( GAMESTATE->m_vpsNamesThatWereFilled.begin(), GAMESTATE->m_vpsNamesThatWereFilled.end(), psName ) != GAMESTATE->m_vpsNamesThatWereFilled.end(); } else { hs.sName = NO_SCORE_NAME; } CString s; s = hs.GetDisplayName() + "\n"; s += ssprintf( "%0*.*f%%", PERCENT_TOTAL_SIZE, PERCENT_DECIMAL_PLACES, hs.fPercentDP*100 ); pTextStepsScore->SetText( s ); } } } } return m_ListScoreRowItems.GetSecondsForCompleteScrollThrough(); case PAGE_TYPE_ALL_COURSES: { m_textStepsType.SetText( GameManager::StepsTypeToThemedString(pts.nt) ); for( unsigned c=0; c<m_vpCourseScoreRowItem.size(); c++ ) { CourseScoreRowItem *pCourseScoreRowItem = m_vpCourseScoreRowItem[c]; const Course* pCourse = pCourseScoreRowItem->m_pCourse; pCourseScoreRowItem->m_textSongTitle.SetText( pCourse->GetFullDisplayTitle() ); FOREACH_ShownCourseDifficulty( cd ) { BitmapText* pTextStepsScore = &pCourseScoreRowItem->m_textStepsScore[cd]; Trail *pTrail = pCourse->GetTrail( pts.nt, cd ); pTextStepsScore->SetHidden( pTrail==NULL ); if( pTrail == NULL ) continue; const HighScoreList &hsl = PROFILEMAN->GetMachineProfile()->GetCourseHighScoreList( pCourse, pTrail ); HighScore hs; bool bRecentHighScore = false; if( !hsl.vHighScores.empty() ) { hs = hsl.vHighScores[0]; const CString *psName = &hsl.GetTopScore().sName; bRecentHighScore = find( GAMESTATE->m_vpsNamesThatWereFilled.begin(), GAMESTATE->m_vpsNamesThatWereFilled.end(), psName ) != GAMESTATE->m_vpsNamesThatWereFilled.end(); } else { hs.sName = NO_SCORE_NAME; } CString s; s = hs.GetDisplayName() + "\n"; s += ssprintf( "%0*.*f%%", PERCENT_TOTAL_SIZE, PERCENT_DECIMAL_PLACES, hs.fPercentDP*100 ); pTextStepsScore->SetText( s ); } } } return m_ListCourseRowItems.GetSecondsForCompleteScrollThrough(); default: ASSERT(0); return 0; } }
CString SecondsToMMSSMsMsMs( float fSecs ) { const int iMinsDisplay = (int)fSecs/60; const int iSecsDisplay = (int)fSecs - iMinsDisplay*60; const int iLeftoverDisplay = (int) ( (fSecs - iMinsDisplay*60 - iSecsDisplay) * 1000 ); CString sReturn = ssprintf( "%02d:%02d.%03d", iMinsDisplay, iSecsDisplay, min(999,iLeftoverDisplay) ); return sReturn; } #include "LuaFunctions.h" #include "LuaManager.h" LuaFunction( SecondsToMMSS, SecondsToMMSS( IArg(1) ) ) LuaFunction( SecondsToHHMMSS, SecondsToHHMMSS( IArg(1) ) ) LuaFunction( SecondsToMSSMsMs, SecondsToMSSMsMs( FArg(1) ) ) LuaFunction( SecondsToMMSSMsMs, SecondsToMMSSMsMs( FArg(1) ) ) LuaFunction( SecondsToMMSSMsMsMs, SecondsToMMSSMsMsMs( FArg(1) ) ) CString PrettyPercent( float fNumerator, float fDenominator) { return ssprintf("%0.2f%%",fNumerator/fDenominator*100); } CString Commify( int iNum ) { CString sNum = ssprintf("%d",iNum); CString sReturn; for( unsigned i=0; i<sNum.length(); i++ ) { char cDigit = sNum[sNum.length()-1-i]; if( i!=0 && i%3 == 0 )