2004-03-25 22:13:51 +00:00
|
|
|
/*
|
|
|
|
|
* SM_GainFocus/SM_LoseFocus: These are sent to screens when they become the
|
|
|
|
|
* topmost screen, or stop being the topmost screen.
|
|
|
|
|
*
|
|
|
|
|
* A few subtleties:
|
|
|
|
|
*
|
|
|
|
|
* With delayed screens (eg. ScreenGameplay being pre-loaded by ScreenStage), SM_GainFocus
|
|
|
|
|
* isn't sent until the loaded screen actually is activated (put on the stack).
|
|
|
|
|
*
|
|
|
|
|
* With normal screen loads, the new screen is loaded before the old screen is destroyed.
|
|
|
|
|
* This means that the old dtor is called *after* the new ctor. If some global properties
|
|
|
|
|
* (eg. GAMESTATE) are being unset by the old screen's destructor, and set by the new
|
|
|
|
|
* screen's constructor, they'll happen in the wrong order. Use SM_GainFocus and
|
|
|
|
|
* SM_LoseFocus, instead.
|
|
|
|
|
*
|
|
|
|
|
* SM_LoseFocus is always sent after SM_GainFocus, and vice-versa: you can't gain focus
|
|
|
|
|
* if you already have it, and you can't lose focus if you don't have it.
|
|
|
|
|
*/
|
|
|
|
|
|
2004-06-08 01:24:17 +00:00
|
|
|
#include "global.h"
|
2002-05-20 08:59:37 +00:00
|
|
|
#include "ScreenManager.h"
|
|
|
|
|
#include "IniFile.h"
|
|
|
|
|
#include "GameConstantsAndTypes.h"
|
2002-07-23 01:41:40 +00:00
|
|
|
#include "PrefsManager.h"
|
2002-05-20 08:59:37 +00:00
|
|
|
#include "RageLog.h"
|
2003-11-05 19:56:21 +00:00
|
|
|
#include "ActorUtil.h"
|
2002-08-13 23:26:46 +00:00
|
|
|
#include "GameState.h"
|
2002-08-27 03:59:22 +00:00
|
|
|
#include "RageException.h"
|
2002-10-24 07:11:21 +00:00
|
|
|
#include "RageTimer.h"
|
2004-07-08 00:10:34 +00:00
|
|
|
#include "GameSoundManager.h"
|
2002-11-11 04:53:31 +00:00
|
|
|
#include "ThemeManager.h"
|
2002-12-30 00:13:47 +00:00
|
|
|
#include "RageDisplay.h"
|
2003-02-22 01:58:56 +00:00
|
|
|
#include "Screen.h"
|
2003-03-03 10:03:02 +00:00
|
|
|
#include "SongManager.h"
|
2003-03-28 00:49:01 +00:00
|
|
|
#include "BitmapText.h"
|
|
|
|
|
#include "Quad.h"
|
2003-04-18 23:55:20 +00:00
|
|
|
#include "RageTextureManager.h"
|
2003-09-08 07:21:41 +00:00
|
|
|
#include "ProfileManager.h"
|
2003-11-05 04:56:41 +00:00
|
|
|
#include "ThemeManager.h"
|
2004-01-03 03:42:40 +00:00
|
|
|
#include "MemoryCardManager.h"
|
2004-05-08 19:22:51 +00:00
|
|
|
#include "CodeDetector.h"
|
2004-05-10 02:06:29 +00:00
|
|
|
#include "StepMania.h"
|
2002-05-20 08:59:37 +00:00
|
|
|
|
|
|
|
|
ScreenManager* SCREENMAN = NULL; // global and accessable from anywhere in our program
|
|
|
|
|
|
|
|
|
|
|
2004-01-03 03:42:40 +00:00
|
|
|
#define CREDITS_PRESS_START THEME->GetMetric ("ScreenSystemLayer","CreditsPressStart")
|
|
|
|
|
#define CREDITS_INSERT_CARD THEME->GetMetric ("ScreenSystemLayer","CreditsInsertCard")
|
|
|
|
|
#define CREDITS_CARD_ERROR THEME->GetMetric ("ScreenSystemLayer","CreditsCardError")
|
|
|
|
|
#define CREDITS_CARD_TOO_LATE THEME->GetMetric ("ScreenSystemLayer","CreditsCardTooLate")
|
2004-08-09 05:01:24 +00:00
|
|
|
#define CREDITS_CARD_NO_NAME THEME->GetMetric ("ScreenSystemLayer","CreditsCardNoName")
|
2004-01-03 20:14:09 +00:00
|
|
|
#define CREDITS_FREE_PLAY THEME->GetMetric ("ScreenSystemLayer","CreditsFreePlay")
|
|
|
|
|
#define CREDITS_CREDITS THEME->GetMetric ("ScreenSystemLayer","CreditsCredits")
|
|
|
|
|
#define CREDITS_NOT_PRESENT THEME->GetMetric ("ScreenSystemLayer","CreditsNotPresent")
|
2004-01-03 03:42:40 +00:00
|
|
|
#define CREDITS_JOIN_ONLY THEME->GetMetricB("ScreenSystemLayer","CreditsJoinOnly")
|
2002-08-13 23:26:46 +00:00
|
|
|
|
2004-01-03 03:42:40 +00:00
|
|
|
const int NUM_SKIPS_TO_SHOW = 5;
|
2003-03-15 02:44:54 +00:00
|
|
|
|
2003-03-15 00:02:54 +00:00
|
|
|
/* This screen is drawn on top of everything else, and receives updates,
|
|
|
|
|
* but not input. */
|
|
|
|
|
class ScreenSystemLayer: public Screen
|
|
|
|
|
{
|
|
|
|
|
BitmapText m_textStats;
|
2004-01-03 03:42:40 +00:00
|
|
|
BitmapText m_textMessage;
|
|
|
|
|
BitmapText m_textCredits[NUM_PLAYERS];
|
|
|
|
|
BitmapText m_textTime;
|
|
|
|
|
BitmapText m_textSkips[NUM_SKIPS_TO_SHOW];
|
2003-03-15 02:44:54 +00:00
|
|
|
int m_LastSkip;
|
|
|
|
|
Quad m_SkipBackground;
|
|
|
|
|
|
|
|
|
|
RageTimer SkipTimer;
|
2004-01-26 23:06:50 +00:00
|
|
|
void AddTimestampLine( const CString &txt, RageColor color );
|
2003-03-15 02:44:54 +00:00
|
|
|
void UpdateTimestampAndSkips();
|
2003-03-15 00:02:54 +00:00
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
ScreenSystemLayer();
|
|
|
|
|
void SystemMessage( CString sMessage );
|
2003-11-20 11:55:45 +00:00
|
|
|
void SystemMessageNoAnimate( CString sMessage );
|
2004-01-03 20:34:16 +00:00
|
|
|
void ReloadCreditsText();
|
2003-03-15 00:02:54 +00:00
|
|
|
void RefreshCreditsMessages();
|
|
|
|
|
void Update( float fDeltaTime );
|
|
|
|
|
};
|
|
|
|
|
|
2003-04-12 06:16:12 +00:00
|
|
|
ScreenSystemLayer::ScreenSystemLayer() : Screen("ScreenSystemLayer")
|
2002-05-20 08:59:37 +00:00
|
|
|
{
|
2004-01-03 03:42:40 +00:00
|
|
|
this->AddChild(&m_textMessage);
|
2003-03-15 00:02:54 +00:00
|
|
|
this->AddChild(&m_textStats);
|
2004-01-03 03:42:40 +00:00
|
|
|
this->AddChild(&m_textTime);
|
2004-05-24 06:10:11 +00:00
|
|
|
FOREACH_PlayerNumber( p )
|
2004-01-03 03:42:40 +00:00
|
|
|
this->AddChild(&m_textCredits[p]);
|
2003-03-15 02:44:54 +00:00
|
|
|
|
2003-11-07 20:43:17 +00:00
|
|
|
|
2003-03-15 02:44:54 +00:00
|
|
|
/* "Was that a skip?" This displays a message when an update takes
|
|
|
|
|
* abnormally long, to quantify skips more precisely, verify them
|
|
|
|
|
* when they're subtle, and show the time it happened, so you can pinpoint
|
|
|
|
|
* the time in the log. Put a dim quad behind it to make it easier to
|
|
|
|
|
* read. */
|
|
|
|
|
m_LastSkip = 0;
|
|
|
|
|
const float SKIP_LEFT = 320.0f, SKIP_TOP = 60.0f,
|
|
|
|
|
SKIP_WIDTH = 160.0f, SKIP_Y_DIST = 16.0f;
|
|
|
|
|
|
|
|
|
|
m_SkipBackground.StretchTo(RectF(SKIP_LEFT-8, SKIP_TOP-8,
|
2004-01-03 03:42:40 +00:00
|
|
|
SKIP_LEFT+SKIP_WIDTH, SKIP_TOP+SKIP_Y_DIST*NUM_SKIPS_TO_SHOW));
|
2004-08-17 20:38:24 +00:00
|
|
|
m_SkipBackground.SetDiffuse( RageColor(0,0,0,0.4f) );
|
|
|
|
|
m_SkipBackground.SetHidden( !PREFSMAN->m_bTimestamping );
|
2003-03-15 02:44:54 +00:00
|
|
|
this->AddChild(&m_SkipBackground);
|
|
|
|
|
|
2004-01-03 03:42:40 +00:00
|
|
|
for( int i=0; i<NUM_SKIPS_TO_SHOW; i++ )
|
2003-03-15 02:44:54 +00:00
|
|
|
{
|
|
|
|
|
/* This is somewhat big. Let's put it on the right side, where it'll
|
|
|
|
|
* obscure the 2P side during gameplay; there's nowhere to put it that
|
|
|
|
|
* doesn't obscure something, and it's just a diagnostic. */
|
2004-01-03 03:42:40 +00:00
|
|
|
m_textSkips[i].LoadFromFont( THEME->GetPathToF("Common normal") );
|
|
|
|
|
m_textSkips[i].SetXY( SKIP_LEFT, SKIP_TOP + SKIP_Y_DIST*i );
|
|
|
|
|
m_textSkips[i].SetHorizAlign( Actor::align_left );
|
|
|
|
|
m_textSkips[i].SetVertAlign( Actor::align_top );
|
|
|
|
|
m_textSkips[i].SetZoom( 0.5f );
|
|
|
|
|
m_textSkips[i].SetDiffuse( RageColor(1,1,1,0) );
|
2004-03-20 02:59:08 +00:00
|
|
|
m_textSkips[i].SetShadowLength( 0 );
|
2004-01-03 03:42:40 +00:00
|
|
|
this->AddChild(&m_textSkips[i]);
|
2003-03-15 02:44:54 +00:00
|
|
|
}
|
2004-01-03 03:42:40 +00:00
|
|
|
|
2004-01-03 20:34:16 +00:00
|
|
|
ReloadCreditsText();
|
2004-01-21 05:18:16 +00:00
|
|
|
/* This will be done when we set up the first screen, after GAMESTATE->Reset has
|
|
|
|
|
* been called. */
|
|
|
|
|
// RefreshCreditsMessages();
|
2003-03-15 00:02:54 +00:00
|
|
|
}
|
|
|
|
|
|
2004-01-03 20:34:16 +00:00
|
|
|
void ScreenSystemLayer::ReloadCreditsText()
|
|
|
|
|
{
|
|
|
|
|
m_textMessage.LoadFromFont( THEME->GetPathToF("ScreenSystemLayer message") );
|
|
|
|
|
m_textMessage.SetName( "Message" );
|
|
|
|
|
SET_XY_AND_ON_COMMAND( m_textMessage );
|
|
|
|
|
|
|
|
|
|
m_textStats.LoadFromFont( THEME->GetPathToF("ScreenSystemLayer stats") );
|
|
|
|
|
m_textStats.SetName( "Stats" );
|
|
|
|
|
SET_XY_AND_ON_COMMAND( m_textStats );
|
|
|
|
|
|
|
|
|
|
m_textTime.LoadFromFont( THEME->GetPathToF("ScreenSystemLayer time") );
|
|
|
|
|
m_textTime.SetName( "Time" );
|
2004-08-17 20:38:24 +00:00
|
|
|
m_textTime.SetHidden( !PREFSMAN->m_bTimestamping );
|
2004-01-03 20:34:16 +00:00
|
|
|
SET_XY_AND_ON_COMMAND( m_textTime );
|
|
|
|
|
|
2004-05-24 06:10:11 +00:00
|
|
|
FOREACH_PlayerNumber( p )
|
2004-01-03 20:34:16 +00:00
|
|
|
{
|
|
|
|
|
m_textCredits[p].LoadFromFont( THEME->GetPathToF("ScreenManager credits") );
|
|
|
|
|
m_textCredits[p].SetName( ssprintf("CreditsP%d",p+1) );
|
|
|
|
|
SET_XY_AND_ON_COMMAND( &m_textCredits[p] );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-03-15 00:02:54 +00:00
|
|
|
void ScreenSystemLayer::SystemMessage( CString sMessage )
|
|
|
|
|
{
|
2004-01-03 03:42:40 +00:00
|
|
|
m_textMessage.FinishTweening();
|
|
|
|
|
m_textMessage.SetText( sMessage );
|
|
|
|
|
m_textMessage.SetDiffuseAlpha( 1 );
|
|
|
|
|
m_textMessage.SetX( -640 );
|
|
|
|
|
m_textMessage.BeginTweening( 0.5f );
|
|
|
|
|
m_textMessage.SetX( 4 );
|
|
|
|
|
m_textMessage.BeginTweening( 5 );
|
|
|
|
|
m_textMessage.BeginTweening( 0.5f );
|
|
|
|
|
m_textMessage.SetDiffuse( RageColor(1,1,1,0) );
|
2003-03-15 00:02:54 +00:00
|
|
|
}
|
|
|
|
|
|
2003-11-20 11:55:45 +00:00
|
|
|
void ScreenSystemLayer::SystemMessageNoAnimate( CString sMessage )
|
|
|
|
|
{
|
2004-01-03 03:42:40 +00:00
|
|
|
m_textMessage.FinishTweening();
|
|
|
|
|
m_textMessage.SetText( sMessage );
|
|
|
|
|
m_textMessage.SetX( 4 );
|
|
|
|
|
m_textMessage.SetDiffuseAlpha( 1 );
|
|
|
|
|
m_textMessage.BeginTweening( 5 );
|
|
|
|
|
m_textMessage.BeginTweening( 0.5f );
|
|
|
|
|
m_textMessage.SetDiffuse( RageColor(1,1,1,0) );
|
2003-11-20 11:55:45 +00:00
|
|
|
}
|
|
|
|
|
|
2003-03-15 00:02:54 +00:00
|
|
|
void ScreenSystemLayer::RefreshCreditsMessages()
|
|
|
|
|
{
|
|
|
|
|
// update joined
|
2004-05-24 06:10:11 +00:00
|
|
|
FOREACH_PlayerNumber( p )
|
2003-03-15 00:02:54 +00:00
|
|
|
{
|
2004-01-03 03:42:40 +00:00
|
|
|
CString sCredits;
|
2003-11-07 20:43:17 +00:00
|
|
|
|
2004-08-29 07:21:36 +00:00
|
|
|
bool bShowCreditsMessage;
|
|
|
|
|
if( GAMESTATE->m_bIsOnSystemMenu )
|
|
|
|
|
bShowCreditsMessage = true;
|
|
|
|
|
else if( GAMESTATE->m_bPlayersFinalized )
|
|
|
|
|
bShowCreditsMessage = !GAMESTATE->IsPlayerEnabled( p );
|
|
|
|
|
else
|
|
|
|
|
bShowCreditsMessage = !GAMESTATE->m_bSideIsJoined[p];
|
2004-06-13 05:13:21 +00:00
|
|
|
|
|
|
|
|
if( !bShowCreditsMessage )
|
2003-11-07 20:43:17 +00:00
|
|
|
{
|
2004-06-13 05:13:21 +00:00
|
|
|
MemoryCardState mcs = MEMCARDMAN->GetCardState( p );
|
|
|
|
|
Profile* pProfile = PROFILEMAN->GetProfile( p );
|
2004-08-09 05:01:24 +00:00
|
|
|
switch( mcs )
|
2003-11-09 10:14:52 +00:00
|
|
|
{
|
2004-08-09 05:01:24 +00:00
|
|
|
case MEMORY_CARD_STATE_NO_CARD:
|
|
|
|
|
if( pProfile ) // this is a local machine profile
|
|
|
|
|
sCredits = pProfile->GetDisplayName();
|
|
|
|
|
else if( GAMESTATE->PlayersCanJoin() )
|
|
|
|
|
sCredits = CREDITS_INSERT_CARD;
|
|
|
|
|
else
|
2004-01-03 03:42:40 +00:00
|
|
|
sCredits = "";
|
2004-08-09 05:01:24 +00:00
|
|
|
break;
|
|
|
|
|
case MEMORY_CARD_STATE_WRITE_ERROR:
|
|
|
|
|
sCredits = CREDITS_CARD_ERROR;
|
|
|
|
|
break;
|
|
|
|
|
case MEMORY_CARD_STATE_TOO_LATE:
|
|
|
|
|
sCredits = CREDITS_CARD_TOO_LATE;
|
|
|
|
|
break;
|
|
|
|
|
case MEMORY_CARD_STATE_READY:
|
|
|
|
|
if( !MEMCARDMAN->GetName(p).empty() )
|
|
|
|
|
sCredits = MEMCARDMAN->GetName(p);
|
|
|
|
|
else
|
|
|
|
|
sCredits = CREDITS_CARD_NO_NAME;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
ASSERT(0);
|
2003-11-09 01:09:35 +00:00
|
|
|
}
|
2003-11-07 20:43:17 +00:00
|
|
|
}
|
2004-06-13 05:13:21 +00:00
|
|
|
else // bShowCreditsMessage
|
2003-11-07 20:43:17 +00:00
|
|
|
{
|
2004-06-09 08:14:21 +00:00
|
|
|
switch( PREFSMAN->GetCoinMode() )
|
2004-01-03 03:42:40 +00:00
|
|
|
{
|
|
|
|
|
case COIN_HOME:
|
2004-01-03 20:14:09 +00:00
|
|
|
if( GAMESTATE->PlayersCanJoin() )
|
|
|
|
|
sCredits = CREDITS_PRESS_START;
|
|
|
|
|
else
|
|
|
|
|
sCredits = CREDITS_NOT_PRESENT;
|
2004-01-03 03:42:40 +00:00
|
|
|
break;
|
|
|
|
|
case COIN_PAY:
|
|
|
|
|
{
|
2004-07-26 02:58:04 +00:00
|
|
|
int Credits = GAMESTATE->m_iCoins / PREFSMAN->m_iCoinsPerCredit;
|
2004-01-03 03:42:40 +00:00
|
|
|
int Coins = GAMESTATE->m_iCoins % PREFSMAN->m_iCoinsPerCredit;
|
2004-07-26 02:58:04 +00:00
|
|
|
sCredits = CREDITS_CREDITS;
|
2004-07-26 04:47:33 +00:00
|
|
|
if( Credits > 0 || PREFSMAN->m_iCoinsPerCredit == 1 )
|
2004-07-26 02:58:04 +00:00
|
|
|
sCredits += ssprintf(" %d", Credits);
|
2004-07-26 04:47:33 +00:00
|
|
|
if( PREFSMAN->m_iCoinsPerCredit > 1 )
|
|
|
|
|
sCredits += ssprintf(" %d/%d", Coins, PREFSMAN->m_iCoinsPerCredit );
|
2004-01-03 03:42:40 +00:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case COIN_FREE:
|
2004-01-03 20:14:09 +00:00
|
|
|
if( GAMESTATE->PlayersCanJoin() )
|
|
|
|
|
sCredits = CREDITS_FREE_PLAY;
|
|
|
|
|
else
|
|
|
|
|
sCredits = CREDITS_NOT_PRESENT;
|
2004-01-03 03:42:40 +00:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
ASSERT(0);
|
|
|
|
|
}
|
2003-03-15 00:02:54 +00:00
|
|
|
}
|
2003-11-01 19:36:52 +00:00
|
|
|
|
2004-01-03 03:42:40 +00:00
|
|
|
if( CREDITS_JOIN_ONLY && !GAMESTATE->PlayersCanJoin() )
|
|
|
|
|
sCredits = "";
|
|
|
|
|
m_textCredits[p].SetText( sCredits );
|
2003-03-15 00:02:54 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2004-01-26 23:06:50 +00:00
|
|
|
void ScreenSystemLayer::AddTimestampLine( const CString &txt, RageColor color )
|
|
|
|
|
{
|
|
|
|
|
m_textSkips[m_LastSkip].SetText( txt );
|
|
|
|
|
m_textSkips[m_LastSkip].StopTweening();
|
|
|
|
|
m_textSkips[m_LastSkip].SetDiffuse( RageColor(1,1,1,1) );
|
|
|
|
|
m_textSkips[m_LastSkip].BeginTweening( 0.2f );
|
|
|
|
|
m_textSkips[m_LastSkip].SetDiffuse( color );
|
|
|
|
|
m_textSkips[m_LastSkip].BeginTweening( 3.0f );
|
|
|
|
|
m_textSkips[m_LastSkip].BeginTweening( 0.2f );
|
|
|
|
|
m_textSkips[m_LastSkip].SetDiffuse( RageColor(1,1,1,0) );
|
|
|
|
|
|
|
|
|
|
m_LastSkip++;
|
|
|
|
|
m_LastSkip %= NUM_SKIPS_TO_SHOW;
|
|
|
|
|
}
|
|
|
|
|
|
2003-03-15 02:44:54 +00:00
|
|
|
void ScreenSystemLayer::UpdateTimestampAndSkips()
|
|
|
|
|
{
|
|
|
|
|
/* 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())
|
|
|
|
|
{
|
|
|
|
|
/* 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)
|
|
|
|
|
{
|
2004-02-22 19:51:46 +00:00
|
|
|
CString time(SecondsToMMSSMsMs(RageTimer::GetTimeSinceStart()));
|
|
|
|
|
|
2003-03-15 02:44:54 +00:00
|
|
|
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 */
|
|
|
|
|
};
|
2004-01-26 23:06:50 +00:00
|
|
|
|
2004-01-30 06:39:06 +00:00
|
|
|
if( PREFSMAN->m_bTimestamping )
|
|
|
|
|
AddTimestampLine( ssprintf("%s: %.0fms (%.0f)", time.c_str(), 1000*UpdateTime, UpdateTime/ExpectedUpdate),
|
|
|
|
|
colors[skip] );
|
2004-03-06 07:21:15 +00:00
|
|
|
if( PREFSMAN->m_bLogSkips )
|
2004-01-29 21:02:51 +00:00
|
|
|
LOG->Trace( "Frame skip: %.0fms (%.0f)", 1000*UpdateTime, UpdateTime/ExpectedUpdate );
|
2003-03-15 02:44:54 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2004-08-17 20:38:24 +00:00
|
|
|
if( PREFSMAN->m_bTimestamping )
|
|
|
|
|
m_textTime.SetText( SecondsToMMSSMsMs(RageTimer::GetTimeSinceStart()) );
|
2003-03-15 02:44:54 +00:00
|
|
|
}
|
|
|
|
|
|
2003-03-15 00:02:54 +00:00
|
|
|
void ScreenSystemLayer::Update( float fDeltaTime )
|
|
|
|
|
{
|
|
|
|
|
Screen::Update(fDeltaTime);
|
|
|
|
|
|
|
|
|
|
if( PREFSMAN && PREFSMAN->m_bShowStats )
|
|
|
|
|
{
|
2003-05-24 05:44:31 +00:00
|
|
|
m_textStats.SetDiffuse( RageColor(1,1,1,0.7f) );
|
2003-03-15 00:02:54 +00:00
|
|
|
|
|
|
|
|
/* If FPS == 0, we don't have stats yet. */
|
|
|
|
|
if(DISPLAY->GetFPS())
|
|
|
|
|
m_textStats.SetText( ssprintf(
|
|
|
|
|
"%i FPS\n%i av FPS\n%i VPF",
|
|
|
|
|
DISPLAY->GetFPS(), DISPLAY->GetCumFPS(),
|
|
|
|
|
DISPLAY->GetVPF()) );
|
|
|
|
|
else
|
|
|
|
|
m_textStats.SetText( "-- FPS\n-- av FPS\n-- VPF" );
|
|
|
|
|
} else
|
|
|
|
|
m_textStats.SetDiffuse( RageColor(1,1,1,0) ); /* hide */
|
|
|
|
|
|
2003-03-15 02:44:54 +00:00
|
|
|
UpdateTimestampAndSkips();
|
2003-03-15 00:02:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ScreenManager::ScreenManager()
|
|
|
|
|
{
|
|
|
|
|
m_SystemLayer = new ScreenSystemLayer;
|
|
|
|
|
|
|
|
|
|
m_ScreenBuffered = NULL;
|
2003-11-12 08:13:02 +00:00
|
|
|
|
|
|
|
|
m_MessageSendOnPop = SM_None;
|
2002-05-20 08:59:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ScreenManager::~ScreenManager()
|
|
|
|
|
{
|
2002-07-31 19:40:40 +00:00
|
|
|
LOG->Trace( "ScreenManager::~ScreenManager()" );
|
2002-05-20 08:59:37 +00:00
|
|
|
|
2002-08-23 06:50:48 +00:00
|
|
|
EmptyDeleteQueue();
|
|
|
|
|
|
2003-03-09 00:55:49 +00:00
|
|
|
// delete current Screens
|
2002-10-31 02:20:11 +00:00
|
|
|
for( unsigned i=0; i<m_ScreenStack.size(); i++ )
|
2003-03-15 00:02:54 +00:00
|
|
|
delete m_ScreenStack[i];
|
|
|
|
|
delete m_ScreenBuffered;
|
|
|
|
|
delete m_SystemLayer;
|
2002-05-20 08:59:37 +00:00
|
|
|
}
|
|
|
|
|
|
2004-08-21 17:20:30 +00:00
|
|
|
void ScreenManager::ReloadCommonSounds()
|
|
|
|
|
{
|
|
|
|
|
// reload common sounds
|
|
|
|
|
m_soundStart.Load( THEME->GetPathS("Common","start") );
|
|
|
|
|
m_soundCoin.Load( THEME->GetPathS("Common","coin") );
|
|
|
|
|
m_soundInvalid.Load( THEME->GetPathS("Common","invalid") );
|
|
|
|
|
m_soundScreenshot.Load( THEME->GetPathS("Common","screenshot") );
|
|
|
|
|
m_soundBack.Load( THEME->GetPathS("Common","back") );
|
|
|
|
|
}
|
|
|
|
|
|
2002-08-23 06:50:48 +00:00
|
|
|
void ScreenManager::EmptyDeleteQueue()
|
|
|
|
|
{
|
2003-04-24 19:42:06 +00:00
|
|
|
if(!m_ScreensToDelete.size())
|
|
|
|
|
return;
|
|
|
|
|
|
2002-08-23 06:50:48 +00:00
|
|
|
// delete all ScreensToDelete
|
2002-10-31 02:20:11 +00:00
|
|
|
for( unsigned i=0; i<m_ScreensToDelete.size(); i++ )
|
2002-08-23 06:50:48 +00:00
|
|
|
SAFE_DELETE( m_ScreensToDelete[i] );
|
2002-05-20 08:59:37 +00:00
|
|
|
|
2002-10-24 20:15:24 +00:00
|
|
|
m_ScreensToDelete.clear();
|
2003-04-24 19:26:06 +00:00
|
|
|
|
2003-04-24 19:42:06 +00:00
|
|
|
/* Now that we've actually deleted a screen, it makes sense to clear out
|
2003-04-24 19:26:06 +00:00
|
|
|
* cached textures. */
|
|
|
|
|
TEXTUREMAN->DeleteCachedTextures();
|
2003-04-24 19:51:27 +00:00
|
|
|
TEXTUREMAN->DiagnosticOutput();
|
2002-08-23 06:50:48 +00:00
|
|
|
}
|
2002-05-20 08:59:37 +00:00
|
|
|
|
2004-02-16 05:30:31 +00:00
|
|
|
Screen *ScreenManager::GetTopScreen()
|
|
|
|
|
{
|
|
|
|
|
if( m_ScreenStack.empty() )
|
|
|
|
|
return NULL;
|
|
|
|
|
return m_ScreenStack[m_ScreenStack.size()-1];
|
|
|
|
|
}
|
|
|
|
|
|
2002-05-20 08:59:37 +00:00
|
|
|
void ScreenManager::Update( float fDeltaTime )
|
|
|
|
|
{
|
2003-01-19 21:51:46 +00:00
|
|
|
// Only update the topmost screen on the stack.
|
|
|
|
|
|
|
|
|
|
/* Screens take some time to load. If we don't do this, then screens
|
|
|
|
|
* receive an initial update that includes all of the time they spent
|
|
|
|
|
* loading, which will chop off their tweens.
|
|
|
|
|
*
|
|
|
|
|
* We don't want to simply cap update times; for example, the stage
|
|
|
|
|
* screen sets a 4 second timer, preps the gameplay screen, and then
|
|
|
|
|
* displays the prepped screen after the timer runs out; this lets the
|
|
|
|
|
* load time be masked (as long as the load takes less than 4 seconds).
|
|
|
|
|
* If we cap that large update delta from the screen load, the update
|
|
|
|
|
* to load the new screen will come after 4 seconds plus the load time.
|
|
|
|
|
*
|
2003-04-25 03:41:38 +00:00
|
|
|
* So, let's just zero the first update for every screen.
|
2003-01-19 21:51:46 +00:00
|
|
|
*/
|
2003-04-25 03:41:38 +00:00
|
|
|
ASSERT( !m_ScreenStack.empty() || m_DelayedScreen != "" ); // Why play the game if there is nothing showing?
|
|
|
|
|
|
|
|
|
|
if( !m_ScreenStack.empty() )
|
|
|
|
|
{
|
2004-02-16 05:30:31 +00:00
|
|
|
Screen* pScreen = GetTopScreen();
|
2003-04-25 03:41:38 +00:00
|
|
|
if( pScreen->IsFirstUpdate() )
|
|
|
|
|
pScreen->Update( 0 );
|
|
|
|
|
else
|
|
|
|
|
pScreen->Update( fDeltaTime );
|
|
|
|
|
}
|
2003-03-15 00:02:54 +00:00
|
|
|
|
|
|
|
|
m_SystemLayer->Update( fDeltaTime );
|
2003-04-03 22:34:22 +00:00
|
|
|
|
|
|
|
|
EmptyDeleteQueue();
|
2003-04-25 03:41:38 +00:00
|
|
|
|
|
|
|
|
if(m_DelayedScreen.size() != 0)
|
|
|
|
|
{
|
|
|
|
|
/* We have a screen to display. Delete the current screens and load it. */
|
2004-03-25 22:13:51 +00:00
|
|
|
ClearScreenStack();
|
2003-04-25 03:41:38 +00:00
|
|
|
EmptyDeleteQueue();
|
2003-04-25 04:16:34 +00:00
|
|
|
|
|
|
|
|
/* This is the purpose of delayed screen loads: clear out the texture cache
|
|
|
|
|
* now, while there's (mostly) nothing loaded. */
|
|
|
|
|
TEXTUREMAN->DeleteCachedTextures();
|
|
|
|
|
TEXTUREMAN->DiagnosticOutput();
|
|
|
|
|
|
2003-04-25 03:41:38 +00:00
|
|
|
LoadDelayedScreen();
|
|
|
|
|
}
|
2002-05-20 08:59:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ScreenManager::Draw()
|
|
|
|
|
{
|
2004-01-30 05:07:26 +00:00
|
|
|
/* If it hasn't been updated yet, skip the render. We can't call Update(0), since
|
|
|
|
|
* that'll confuse the "zero out the next update after loading a screen logic.
|
|
|
|
|
* If we don't render, don't call BeginFrame or EndFrame. That way, we won't
|
|
|
|
|
* clear the buffer, and we won't wait for vsync. */
|
|
|
|
|
if( m_ScreenStack.back()->IsFirstUpdate() )
|
2003-04-25 03:41:38 +00:00
|
|
|
return;
|
2004-01-30 05:07:26 +00:00
|
|
|
|
|
|
|
|
DISPLAY->BeginFrame();
|
2003-03-17 01:12:58 +00:00
|
|
|
|
2003-02-20 21:22:18 +00:00
|
|
|
if( !m_ScreenStack.empty() && !m_ScreenStack.back()->IsTransparent() ) // top screen isn't transparent
|
|
|
|
|
m_ScreenStack.back()->Draw();
|
|
|
|
|
else
|
|
|
|
|
for( unsigned i=0; i<m_ScreenStack.size(); i++ ) // Draw all screens bottom to top
|
|
|
|
|
m_ScreenStack[i]->Draw();
|
2003-03-15 00:02:54 +00:00
|
|
|
m_SystemLayer->Draw();
|
2003-04-25 03:41:38 +00:00
|
|
|
|
2003-05-24 05:44:31 +00:00
|
|
|
DISPLAY->EndFrame();
|
2002-05-20 08:59:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ScreenManager::Input( const DeviceInput& DeviceI, const InputEventType type, const GameInput &GameI, const MenuInput &MenuI, const StyleInput &StyleI )
|
|
|
|
|
{
|
2002-09-06 00:31:25 +00:00
|
|
|
// LOG->Trace( "ScreenManager::Input( %d-%d, %d-%d, %d-%d, %d-%d )",
|
|
|
|
|
// DeviceI.device, DeviceI.button, GameI.controller, GameI.button, MenuI.player, MenuI.button, StyleI.player, StyleI.col );
|
2002-05-20 08:59:37 +00:00
|
|
|
|
|
|
|
|
// pass input only to topmost state
|
2002-10-31 02:20:11 +00:00
|
|
|
if( !m_ScreenStack.empty() )
|
|
|
|
|
m_ScreenStack.back()->Input( DeviceI, type, GameI, MenuI, StyleI );
|
2002-05-20 08:59:37 +00:00
|
|
|
}
|
|
|
|
|
|
2002-08-27 03:59:22 +00:00
|
|
|
|
2002-09-03 05:43:58 +00:00
|
|
|
Screen* ScreenManager::MakeNewScreen( CString sClassName )
|
|
|
|
|
{
|
2003-12-18 08:53:38 +00:00
|
|
|
/* By default, RageSounds handles the song timer. When we change screens, reset this;
|
2004-06-06 22:04:08 +00:00
|
|
|
* screens turn this off in SM_GainFocus if they handle timers themselves (edit).
|
|
|
|
|
* XXX: screens should turn this on in SM_LoseFocus if they handle timers themselves, too */
|
2003-12-18 08:53:38 +00:00
|
|
|
SOUND->HandleSongTimer( true );
|
|
|
|
|
|
2003-12-21 02:54:23 +00:00
|
|
|
/* Cleanup song data. This can free up a fair bit of memory, so do it before
|
|
|
|
|
* creating the new screen, to lower peak memory usage slightly. */
|
|
|
|
|
SONGMAN->Cleanup();
|
|
|
|
|
|
2004-04-11 01:45:29 +00:00
|
|
|
RageTimer t;
|
|
|
|
|
LOG->Trace( "Loading screen %s", sClassName.c_str() );
|
2003-03-03 10:03:02 +00:00
|
|
|
Screen *ret = Screen::Create( sClassName );
|
2004-04-11 01:45:29 +00:00
|
|
|
LOG->Trace( "Loaded %s in %f", sClassName.c_str(), t.GetDeltaTime());
|
2002-12-21 07:54:24 +00:00
|
|
|
|
2002-12-29 23:37:41 +00:00
|
|
|
/* Loading probably took a little while. Let's reset stats. This prevents us
|
2002-12-21 07:54:24 +00:00
|
|
|
* from displaying an unnaturally low FPS value, and the next FPS value we
|
|
|
|
|
* display will be accurate, which makes skips in the initial tween-ins more
|
|
|
|
|
* apparent. */
|
|
|
|
|
DISPLAY->ResetStats();
|
|
|
|
|
|
|
|
|
|
return ret;
|
2002-09-03 05:43:58 +00:00
|
|
|
}
|
|
|
|
|
|
2002-09-04 00:25:30 +00:00
|
|
|
void ScreenManager::PrepNewScreen( CString sClassName )
|
|
|
|
|
{
|
2002-09-04 23:40:01 +00:00
|
|
|
ASSERT(m_ScreenBuffered == NULL);
|
|
|
|
|
m_ScreenBuffered = MakeNewScreen(sClassName);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ScreenManager::LoadPreppedScreen()
|
|
|
|
|
{
|
|
|
|
|
ASSERT( m_ScreenBuffered != NULL);
|
2004-01-30 05:07:26 +00:00
|
|
|
SetFromNewScreen( m_ScreenBuffered, false );
|
2003-03-12 01:26:44 +00:00
|
|
|
|
2002-09-04 23:40:01 +00:00
|
|
|
m_ScreenBuffered = NULL;
|
2002-09-04 00:25:30 +00:00
|
|
|
}
|
|
|
|
|
|
2003-03-10 02:29:01 +00:00
|
|
|
void ScreenManager::DeletePreppedScreen()
|
|
|
|
|
{
|
|
|
|
|
SAFE_DELETE( m_ScreenBuffered );
|
2003-04-24 19:26:06 +00:00
|
|
|
TEXTUREMAN->DeleteCachedTextures();
|
2003-03-10 02:29:01 +00:00
|
|
|
}
|
|
|
|
|
|
2004-03-25 22:13:51 +00:00
|
|
|
/* Remove all screens from the stack, sending a SM_LoseFocus message to the top.
|
|
|
|
|
* (There's no need to send them to any lower screens; they don't have focus anyway,
|
|
|
|
|
* and received the message when they actually lost it. */
|
|
|
|
|
void ScreenManager::ClearScreenStack()
|
|
|
|
|
{
|
|
|
|
|
if( m_ScreenStack.size() )
|
|
|
|
|
m_ScreenStack.back()->HandleScreenMessage( SM_LoseFocus );
|
|
|
|
|
|
|
|
|
|
// move current screen(s) to ScreenToDelete
|
|
|
|
|
m_ScreensToDelete.insert(m_ScreensToDelete.end(), m_ScreenStack.begin(), m_ScreenStack.end());
|
|
|
|
|
m_ScreenStack.clear();
|
|
|
|
|
}
|
|
|
|
|
|
2004-01-30 05:07:26 +00:00
|
|
|
/* Add a screen to m_ScreenStack. If Stack is true, it's added to the stack; otherwise any
|
|
|
|
|
* current screens are removed. This is the only function that adds to m_ScreenStack. */
|
|
|
|
|
void ScreenManager::SetFromNewScreen( Screen *pNewScreen, bool Stack )
|
2002-09-04 00:25:30 +00:00
|
|
|
{
|
|
|
|
|
RefreshCreditsMessages();
|
2002-09-23 07:35:47 +00:00
|
|
|
|
2004-01-30 05:07:26 +00:00
|
|
|
if( !Stack )
|
2004-03-25 22:13:51 +00:00
|
|
|
ClearScreenStack();
|
2003-04-25 03:41:38 +00:00
|
|
|
|
2002-10-31 04:23:39 +00:00
|
|
|
m_ScreenStack.push_back( pNewScreen );
|
2003-11-25 21:57:00 +00:00
|
|
|
|
|
|
|
|
PostMessageToTopScreen( SM_GainFocus, 0 );
|
2002-09-04 00:25:30 +00:00
|
|
|
}
|
|
|
|
|
|
2002-08-27 03:59:22 +00:00
|
|
|
void ScreenManager::SetNewScreen( CString sClassName )
|
2002-05-20 08:59:37 +00:00
|
|
|
{
|
2003-04-25 03:41:38 +00:00
|
|
|
m_DelayedScreen = sClassName;
|
|
|
|
|
|
|
|
|
|
/* If we're not delaying screen loads, load it now. Otherwise, we'll load
|
|
|
|
|
* it on the next iteration. Only delay if we already have a screen
|
|
|
|
|
* loaded; otherwise, there's no reason to delay. */
|
|
|
|
|
if(!PREFSMAN->m_bDelayedScreenLoad) // || m_ScreenStack.empty() )
|
|
|
|
|
LoadDelayedScreen();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ScreenManager::LoadDelayedScreen()
|
|
|
|
|
{
|
|
|
|
|
retry:
|
|
|
|
|
CString sClassName = m_DelayedScreen;
|
|
|
|
|
m_DelayedScreen = "";
|
|
|
|
|
|
2002-09-04 00:25:30 +00:00
|
|
|
/* If we prepped a screen but didn't use it, nuke it. */
|
|
|
|
|
SAFE_DELETE( m_ScreenBuffered );
|
2002-09-03 05:43:58 +00:00
|
|
|
|
2003-03-09 00:55:49 +00:00
|
|
|
Screen* pOldTopScreen = m_ScreenStack.empty() ? NULL : m_ScreenStack.back();
|
|
|
|
|
|
2002-08-27 03:59:22 +00:00
|
|
|
// It makes sense that ScreenManager should allocate memory for a new screen since it
|
|
|
|
|
// deletes it later on. This also convention will reduce includes because screens won't
|
|
|
|
|
// have to include each other's headers of other screens.
|
2002-09-03 05:43:58 +00:00
|
|
|
Screen* pNewScreen = MakeNewScreen(sClassName);
|
2002-10-24 07:11:21 +00:00
|
|
|
|
2003-03-09 00:55:49 +00:00
|
|
|
if( pOldTopScreen!=NULL && m_ScreenStack.back()!=pOldTopScreen )
|
|
|
|
|
{
|
|
|
|
|
// While constructing this Screen, it's constructor called
|
|
|
|
|
// SetNewScreen again! That SetNewScreen Command should
|
|
|
|
|
// override this older one.
|
|
|
|
|
SAFE_DELETE( pNewScreen );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2003-04-25 03:41:38 +00:00
|
|
|
if( PREFSMAN->m_bDelayedScreenLoad && m_DelayedScreen != "" )
|
|
|
|
|
{
|
|
|
|
|
/* Same deal: the ctor called SetNewScreen again. Delete the screen
|
|
|
|
|
* we just made, but don't delay again. */
|
|
|
|
|
SAFE_DELETE( pNewScreen );
|
|
|
|
|
goto retry;
|
|
|
|
|
}
|
2004-08-22 21:42:28 +00:00
|
|
|
|
|
|
|
|
bool bWasOnSystemMenu = GAMESTATE->m_bIsOnSystemMenu;
|
2003-02-12 06:25:51 +00:00
|
|
|
|
2003-02-12 11:43:08 +00:00
|
|
|
/* If this is a system menu, don't let the operator key touch it!
|
|
|
|
|
However, if you add an options screen, please include it here -- Miryokuteki */
|
2003-03-16 22:51:29 +00:00
|
|
|
if( sClassName == "ScreenOptionsMenu" ||
|
|
|
|
|
sClassName == "ScreenMachineOptions" ||
|
|
|
|
|
sClassName == "ScreenInputOptions" ||
|
|
|
|
|
sClassName == "ScreenGraphicOptions" ||
|
|
|
|
|
sClassName == "ScreenGameplayOptions" ||
|
|
|
|
|
sClassName == "ScreenMapControllers" ||
|
|
|
|
|
sClassName == "ScreenAppearanceOptions" ||
|
|
|
|
|
sClassName == "ScreenEdit" ||
|
|
|
|
|
sClassName == "ScreenEditMenu" ||
|
|
|
|
|
sClassName == "ScreenSoundOptions" )
|
2003-03-09 00:55:49 +00:00
|
|
|
GAMESTATE->m_bIsOnSystemMenu = true;
|
|
|
|
|
else
|
|
|
|
|
GAMESTATE->m_bIsOnSystemMenu = false;
|
2004-08-22 21:42:28 +00:00
|
|
|
|
|
|
|
|
// If we're exiting a system menu, persist settings in case we don't exit normally
|
|
|
|
|
if( bWasOnSystemMenu && !GAMESTATE->m_bIsOnSystemMenu )
|
|
|
|
|
PREFSMAN->SaveGlobalPrefsToDisk();
|
2004-01-03 21:02:46 +00:00
|
|
|
|
2004-01-30 05:07:26 +00:00
|
|
|
LOG->Trace("... SetFromNewScreen");
|
|
|
|
|
SetFromNewScreen( pNewScreen, false );
|
2002-05-20 08:59:37 +00:00
|
|
|
}
|
|
|
|
|
|
2003-11-12 08:13:02 +00:00
|
|
|
void ScreenManager::AddNewScreenToTop( CString sClassName, ScreenMessage messageSendOnPop )
|
2003-02-19 05:46:09 +00:00
|
|
|
{
|
2004-01-26 23:06:50 +00:00
|
|
|
/* Send this before making the new screen, since it might set things that will be re-set
|
|
|
|
|
* in the new screen's ctor. */
|
|
|
|
|
if( m_ScreenStack.size() )
|
|
|
|
|
m_ScreenStack.back()->HandleScreenMessage( SM_LoseFocus );
|
|
|
|
|
|
2003-02-19 05:46:09 +00:00
|
|
|
Screen* pNewScreen = MakeNewScreen(sClassName);
|
2004-01-30 05:07:26 +00:00
|
|
|
SetFromNewScreen( pNewScreen, true );
|
2003-11-12 08:13:02 +00:00
|
|
|
m_MessageSendOnPop = messageSendOnPop;
|
2003-02-19 05:46:09 +00:00
|
|
|
}
|
|
|
|
|
|
2003-03-03 10:03:02 +00:00
|
|
|
#include "ScreenPrompt.h"
|
|
|
|
|
#include "ScreenTextEntry.h"
|
|
|
|
|
#include "ScreenMiniMenu.h"
|
|
|
|
|
|
2003-08-23 18:33:49 +00:00
|
|
|
void ScreenManager::Prompt( ScreenMessage SM_SendWhenDone, CString sText, bool bYesNo, bool bDefaultAnswer, void(*OnYes)(void*), void(*OnNo)(void*), void* pCallbackData )
|
2002-05-20 08:59:37 +00:00
|
|
|
{
|
2004-01-26 23:06:50 +00:00
|
|
|
if( m_ScreenStack.size() )
|
|
|
|
|
m_ScreenStack.back()->HandleScreenMessage( SM_LoseFocus );
|
|
|
|
|
|
2002-08-27 03:59:22 +00:00
|
|
|
// add the new state onto the back of the array
|
2004-01-30 05:07:26 +00:00
|
|
|
Screen *pNewScreen = new ScreenPrompt( sText, bYesNo, bDefaultAnswer, OnYes, OnNo, pCallbackData);
|
|
|
|
|
SetFromNewScreen( pNewScreen, true );
|
|
|
|
|
|
|
|
|
|
m_MessageSendOnPop = SM_SendWhenDone;
|
2002-08-27 03:59:22 +00:00
|
|
|
}
|
2002-05-20 08:59:37 +00:00
|
|
|
|
2004-01-30 05:07:26 +00:00
|
|
|
void ScreenManager::TextEntry( ScreenMessage SM_SendWhenDone, CString sQuestion, CString sInitialAnswer, void(*OnOK)(CString sAnswer), void(*OnCancel)() )
|
2002-08-27 03:59:22 +00:00
|
|
|
{
|
2004-01-26 23:06:50 +00:00
|
|
|
if( m_ScreenStack.size() )
|
|
|
|
|
m_ScreenStack.back()->HandleScreenMessage( SM_LoseFocus );
|
|
|
|
|
|
2002-05-20 08:59:37 +00:00
|
|
|
// add the new state onto the back of the array
|
2004-01-30 05:07:26 +00:00
|
|
|
Screen *pNewScreen = new ScreenTextEntry( "ScreenTextEntry", sQuestion, sInitialAnswer, OnOK, OnCancel );
|
|
|
|
|
SetFromNewScreen( pNewScreen, true );
|
|
|
|
|
|
|
|
|
|
m_MessageSendOnPop = SM_SendWhenDone;
|
2002-05-20 08:59:37 +00:00
|
|
|
}
|
|
|
|
|
|
2003-03-15 19:25:37 +00:00
|
|
|
void ScreenManager::MiniMenu( Menu* pDef, ScreenMessage SM_SendOnOK, ScreenMessage SM_SendOnCancel )
|
2003-02-18 23:15:38 +00:00
|
|
|
{
|
2004-01-26 23:06:50 +00:00
|
|
|
if( m_ScreenStack.size() )
|
|
|
|
|
m_ScreenStack.back()->HandleScreenMessage( SM_LoseFocus );
|
|
|
|
|
|
2003-02-18 23:15:38 +00:00
|
|
|
// add the new state onto the back of the array
|
2004-01-30 05:07:26 +00:00
|
|
|
Screen *pNewScreen = new ScreenMiniMenu( pDef, SM_SendOnOK, SM_SendOnCancel );
|
|
|
|
|
SetFromNewScreen( pNewScreen, true );
|
2003-02-18 23:15:38 +00:00
|
|
|
}
|
|
|
|
|
|
2002-07-27 19:29:51 +00:00
|
|
|
void ScreenManager::PopTopScreen( ScreenMessage SM )
|
2002-05-20 08:59:37 +00:00
|
|
|
{
|
2002-10-31 02:20:11 +00:00
|
|
|
Screen* pScreenToPop = m_ScreenStack.back(); // top menu
|
2003-11-25 21:57:00 +00:00
|
|
|
pScreenToPop->HandleScreenMessage( SM_LoseFocus );
|
2002-10-31 04:11:08 +00:00
|
|
|
m_ScreenStack.erase(m_ScreenStack.end()-1, m_ScreenStack.end());
|
2002-10-31 04:23:39 +00:00
|
|
|
m_ScreensToDelete.push_back( pScreenToPop );
|
2003-11-12 08:13:02 +00:00
|
|
|
|
2003-12-29 03:09:29 +00:00
|
|
|
/* Post to the new top. This must be done now; otherwise, we'll have a single
|
|
|
|
|
* frame between popping and these messages, which can result in a frame where eg.
|
2004-01-26 22:19:33 +00:00
|
|
|
* input is accepted where it shouldn't be. Watch out; sending m_MessageSendOnPop
|
|
|
|
|
* might push another screen (eg. editor menu -> PlayerOptions), which will set
|
|
|
|
|
* a new m_MessageSendOnPop. */
|
|
|
|
|
ScreenMessage MessageToSend = m_MessageSendOnPop;
|
|
|
|
|
m_MessageSendOnPop = SM_None;
|
2003-12-29 03:09:29 +00:00
|
|
|
SendMessageToTopScreen( SM );
|
|
|
|
|
SendMessageToTopScreen( SM_GainFocus );
|
2004-01-26 22:19:33 +00:00
|
|
|
SendMessageToTopScreen( MessageToSend );
|
2002-05-20 08:59:37 +00:00
|
|
|
}
|
|
|
|
|
|
2003-03-25 21:17:29 +00:00
|
|
|
void ScreenManager::PostMessageToTopScreen( ScreenMessage SM, float fDelay )
|
2002-05-20 08:59:37 +00:00
|
|
|
{
|
2002-10-31 02:20:11 +00:00
|
|
|
Screen* pTopScreen = m_ScreenStack.back();
|
2003-03-25 21:17:29 +00:00
|
|
|
pTopScreen->PostScreenMessage( SM, fDelay );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ScreenManager::SendMessageToTopScreen( ScreenMessage SM )
|
|
|
|
|
{
|
|
|
|
|
Screen* pTopScreen = m_ScreenStack.back();
|
|
|
|
|
pTopScreen->HandleScreenMessage( SM );
|
2002-05-20 08:59:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ScreenManager::SystemMessage( CString sMessage )
|
|
|
|
|
{
|
2003-09-15 20:44:25 +00:00
|
|
|
LOG->Trace( "%s", sMessage.c_str() );
|
2003-03-15 00:02:54 +00:00
|
|
|
m_SystemLayer->SystemMessage( sMessage );
|
2002-05-20 08:59:37 +00:00
|
|
|
}
|
|
|
|
|
|
2003-11-20 11:55:45 +00:00
|
|
|
void ScreenManager::SystemMessageNoAnimate( CString sMessage )
|
|
|
|
|
{
|
2004-04-23 00:26:51 +00:00
|
|
|
// LOG->Trace( "%s", sMessage.c_str() ); // don't log because the caller is likely calling us every frame
|
2003-11-20 11:55:45 +00:00
|
|
|
m_SystemLayer->SystemMessageNoAnimate( sMessage );
|
|
|
|
|
}
|
|
|
|
|
|
2002-08-13 23:26:46 +00:00
|
|
|
void ScreenManager::RefreshCreditsMessages()
|
|
|
|
|
{
|
2003-03-15 00:02:54 +00:00
|
|
|
m_SystemLayer->RefreshCreditsMessages();
|
2004-03-13 10:26:51 +00:00
|
|
|
|
|
|
|
|
/* This is called when GAMESTATE->m_bSideIsJoined changes. */
|
|
|
|
|
CString joined;
|
|
|
|
|
FOREACH_PlayerNumber( pn )
|
|
|
|
|
{
|
|
|
|
|
if( GAMESTATE->m_bSideIsJoined[pn] )
|
|
|
|
|
{
|
|
|
|
|
if( joined != "" )
|
|
|
|
|
joined += ", ";
|
|
|
|
|
joined += ssprintf( "P%i", pn+1 );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( joined == "" )
|
|
|
|
|
joined = "none";
|
|
|
|
|
|
|
|
|
|
LOG->MapLog( "JOINED", "Players joined: %s", joined.c_str() );
|
2003-02-12 07:52:20 +00:00
|
|
|
}
|
|
|
|
|
|
2004-01-03 20:34:16 +00:00
|
|
|
void ScreenManager::ReloadCreditsText()
|
|
|
|
|
{
|
|
|
|
|
m_SystemLayer->ReloadCreditsText();
|
|
|
|
|
}
|
|
|
|
|
|
2004-03-25 21:41:11 +00:00
|
|
|
/* Always play these sounds, even if we're in a silent attract loop. */
|
|
|
|
|
void ScreenManager::PlayStartSound()
|
|
|
|
|
{
|
|
|
|
|
RageSoundParams p;
|
|
|
|
|
p.m_Volume = PREFSMAN->m_fSoundVolume;
|
|
|
|
|
m_soundStart.Play( &p );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ScreenManager::PlayCoinSound()
|
|
|
|
|
{
|
|
|
|
|
RageSoundParams p;
|
|
|
|
|
p.m_Volume = PREFSMAN->m_fSoundVolume;
|
|
|
|
|
m_soundCoin.Play( &p );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ScreenManager::PlayInvalidSound()
|
|
|
|
|
{
|
|
|
|
|
RageSoundParams p;
|
|
|
|
|
p.m_Volume = PREFSMAN->m_fSoundVolume;
|
|
|
|
|
m_soundInvalid.Play( &p );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ScreenManager::PlayScreenshotSound()
|
|
|
|
|
{
|
|
|
|
|
RageSoundParams p;
|
|
|
|
|
p.m_Volume = PREFSMAN->m_fSoundVolume;
|
|
|
|
|
m_soundScreenshot.Play( &p );
|
|
|
|
|
}
|
2004-05-01 23:19:33 +00:00
|
|
|
|
|
|
|
|
void ScreenManager::PlayBackSound()
|
|
|
|
|
{
|
|
|
|
|
RageSoundParams p;
|
|
|
|
|
p.m_Volume = PREFSMAN->m_fSoundVolume;
|
|
|
|
|
m_soundBack.Play( &p );
|
|
|
|
|
}
|
2004-06-08 01:24:17 +00:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* (c) 2001-2003 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.
|
|
|
|
|
*/
|