Files
itgmania212121/stepmania/src/ScreenTitleMenu.cpp
T
Chris Danford bcbe615c0d Pass ActorCommand structures to Actor instead of unparsed command strings.
This way, we can potentially do the parsing early and not parse inside of Actor as the command is executing.
2004-11-06 23:13:47 +00:00

421 lines
14 KiB
C++

#include "global.h"
#include "ScreenTitleMenu.h"
#include "ScreenAttract.h"
#include "ScreenManager.h"
#include "GameConstantsAndTypes.h"
#include "RageUtil.h"
#include "StepMania.h"
#include "PrefsManager.h"
#include "RageLog.h"
#include "SongManager.h"
#include "AnnouncerManager.h"
#include "GameState.h"
#include "GameManager.h"
#include "InputMapper.h"
#include "ThemeManager.h"
#include "GameSoundManager.h"
#include "CodeDetector.h"
#include "RageTextureManager.h"
#include "UnlockSystem.h"
#include "ProductInfo.h"
#include "LightsManager.h"
#include "CodeDetector.h"
#include "CommonMetrics.h"
#include "Game.h"
#include "ScreenOptionsMasterPrefs.h"
#define LOGO_ON_COMMAND THEME->GetMetricA("ScreenTitleMenu","LogoOnCommand")
#define LOGO_HOME_ON_COMMAND THEME->GetMetricA("ScreenTitleMenu","LogoHomeOnCommand")
#define VERSION_ON_COMMAND THEME->GetMetricA("ScreenTitleMenu","VersionOnCommand")
#define SONGS_ON_COMMAND THEME->GetMetricA("ScreenTitleMenu","SongsOnCommand")
#define MAX_STAGES_ON_COMMAND THEME->GetMetricA("ScreenTitleMenu","MaxStagesOnCommand")
#define MAX_STAGES_TEXT THEME->GetMetric ("ScreenTitleMenu","MaxStagesText")
#define LIFE_DIFFICULTY_ON_COMMAND THEME->GetMetricA("ScreenTitleMenu","LifeDifficultyOnCommand")
#define HELP_X THEME->GetMetricF("ScreenTitleMenu","HelpX")
#define HELP_Y THEME->GetMetricF("ScreenTitleMenu","HelpY")
#define CHOICES_X THEME->GetMetricF("ScreenTitleMenu","ChoicesX")
#define CHOICES_START_Y THEME->GetMetricF("ScreenTitleMenu","ChoicesStartY")
#define CHOICES_SPACING_Y THEME->GetMetricF("ScreenTitleMenu","ChoicesSpacingY")
#define CHOICES_SHADOW_LENGTH THEME->GetMetricF("ScreenTitleMenu","ChoicesShadowLength")
#define COLOR_NOT_SELECTED THEME->GetMetricC("ScreenTitleMenu","ColorNotSelected")
#define COLOR_SELECTED THEME->GetMetricC("ScreenTitleMenu","ColorSelected")
#define ZOOM_NOT_SELECTED THEME->GetMetricF("ScreenTitleMenu","ZoomNotSelected")
#define ZOOM_SELECTED THEME->GetMetricF("ScreenTitleMenu","ZoomSelected")
#define MENU_TEXT_ALIGN THEME->GetMetricI("ScreenTitleMenu","MenuTextAlign")
#define SECONDS_BETWEEN_COMMENTS THEME->GetMetricF("ScreenTitleMenu","SecondsBetweenComments")
#define SECONDS_BEFORE_ATTRACT THEME->GetMetricF("ScreenTitleMenu","SecondsBeforeAttract")
#define HELP_TEXT( coin_mode ) THEME->GetMetric ("ScreenTitleMenu","HelpText"+Capitalize(CoinModeToString(coin_mode)))
#define MENU_ITEM_CREATE THEME->GetMetricA("ScreenTitleMenu","MenuCommandOnCreate")
#define MENU_ITEM_SELECT_DELAY THEME->GetMetricF("ScreenTitleMenu","MenuCommandSelectDelay")
#define NAME( sChoiceName ) THEME->GetMetric (m_sName,ssprintf("Name%s",sChoiceName.c_str()))
const ScreenMessage SM_PlayComment = ScreenMessage(SM_User+1);
const ScreenMessage SM_GoToAttractLoop = ScreenMessage(SM_User+13);
ScreenTitleMenu::ScreenTitleMenu( CString sClassName ) : ScreenSelect( sClassName )
{
LOG->Trace( "ScreenTitleMenu::ScreenTitleMenu()" );
// Don't show screen title menu (says "Press Start")
// if there are 0 credits and inserted and CoinMode is pay.
if( PREFSMAN->GetCoinMode() == COIN_PAY &&
GAMESTATE->m_iCoins < PREFSMAN->m_iCoinsPerCredit )
{
SCREENMAN->SetNewScreen( INITIAL_SCREEN );
return;
}
/* XXX We really need two common calls: 1, something run when exiting from gameplay
* (to do this reset), and 2, something run when entering gameplay, to apply default
* options. Having special cases in attract screens and the title menu to reset
* things stinks ... */
GAMESTATE->Reset();
LIGHTSMAN->SetLightsMode( LIGHTSMODE_JOINING ); // do this after Reset!
m_sprLogo.Load( THEME->GetPathG("ScreenLogo",GAMESTATE->GetCurrentGame()->m_szName) );
m_sprLogo.Command( PREFSMAN->GetCoinMode()==COIN_HOME ? LOGO_HOME_ON_COMMAND : LOGO_ON_COMMAND );
this->AddChild( &m_sprLogo );
if( PREFSMAN->GetCoinMode() != COIN_HOME )
{
switch( PREFSMAN->GetPremium() )
{
case PrefsManager::DOUBLES_PREMIUM:
m_Premium.LoadFromAniDir( THEME->GetPathToB("ScreenTitleMenu doubles premium") );
this->AddChild( &m_Premium );
break;
case PrefsManager::JOINT_PREMIUM:
m_Premium.LoadFromAniDir( THEME->GetPathToB("ScreenTitleMenu joint premium") );
this->AddChild( &m_Premium );
break;
}
}
m_textVersion.LoadFromFont( THEME->GetPathToF("Common normal") );
m_textVersion.Command( VERSION_ON_COMMAND );
m_textVersion.SetText( PRODUCT_VER );
this->AddChild( &m_textVersion );
m_textSongs.LoadFromFont( THEME->GetPathToF("Common normal") );
m_textSongs.Command( SONGS_ON_COMMAND );
CString text = ssprintf("%d songs in %d groups, %d courses", SONGMAN->GetNumSongs(), SONGMAN->GetNumGroups(), SONGMAN->GetNumCourses() );
if( PREFSMAN->m_bUseUnlockSystem )
text += ssprintf(", %d unlocks", UNLOCKMAN->GetNumUnlocks() );
m_textSongs.SetText( text );
this->AddChild( &m_textSongs );
m_textMaxStages.LoadFromFont( THEME->GetPathF(m_sName,"MaxStages") );
m_textMaxStages.Command( MAX_STAGES_ON_COMMAND );
CString sText =
PREFSMAN->m_bEventMode ?
CString("event mode") :
ssprintf( "%d %s%s max", PREFSMAN->m_iNumArcadeStages, MAX_STAGES_TEXT.c_str(), (PREFSMAN->m_iNumArcadeStages>1)?"s":"" );
m_textMaxStages.SetText( sText );
this->AddChild( &m_textMaxStages );
m_textLifeDifficulty.LoadFromFont( THEME->GetPathF(m_sName,"LifeDifficulty") );
m_textLifeDifficulty.Command( LIFE_DIFFICULTY_ON_COMMAND );
int iLifeDifficulty;
const CStringArray dummy;
LifeDifficulty( iLifeDifficulty, true, dummy );
iLifeDifficulty++; // LifeDifficulty returns an index
m_textLifeDifficulty.SetText( ssprintf( "life difficulty %d", iLifeDifficulty ) );
this->AddChild( &m_textLifeDifficulty );
CString sCoinMode = CoinModeToString((CoinMode)PREFSMAN->GetCoinMode());
m_CoinMode.LoadFromAniDir( THEME->GetPathToB("ScreenTitleMenu "+sCoinMode) );
this->AddChild( &m_CoinMode );
m_textHelp.LoadFromFont( THEME->GetPathToF("ScreenTitleMenu help") );
m_textHelp.SetText( HELP_TEXT((CoinMode)PREFSMAN->GetCoinMode()) );
m_textHelp.SetXY( HELP_X, HELP_Y );
m_textHelp.SetZoom( 0.5f );
m_textHelp.SetEffectDiffuseBlink();
m_textHelp.SetShadowLength( 2 );
this->AddChild( &m_textHelp );
switch( PREFSMAN->GetCoinMode() )
{
case COIN_HOME:
{
for( unsigned i=0; i<m_aModeChoices.size(); i++ )
{
ModeChoice &mc = m_aModeChoices[i];
m_textChoice[i].LoadFromFont( THEME->GetPathToF("ScreenTitleMenu choices") );
m_textChoice[i].SetHorizAlign( (enum Actor::HorizAlign)MENU_TEXT_ALIGN );
m_textChoice[i].SetText( NAME(mc.m_sName) );
m_textChoice[i].SetXY( CHOICES_X, CHOICES_START_Y + i*CHOICES_SPACING_Y );
m_textChoice[i].SetShadowLength( CHOICES_SHADOW_LENGTH );
m_textChoice[i].SetShadowLength( 4 );
this->AddChild( &m_textChoice[i] );
}
}
break;
case COIN_PAY:
case COIN_FREE:
break;
default:
ASSERT(0);
}
// m_AttractOut.Load( THEME->GetPathToB("ScreenTitleMenu out") );
// this->AddChild( &m_AttractOut );
// m_BeginOut.Load( THEME->GetPathToB("ScreenTitleMenu begin out") );
// this->AddChild( &m_BeginOut );
SOUND->PlayOnceFromAnnouncer( "title menu game name" );
m_soundChange.Load( THEME->GetPathToS("ScreenTitleMenu change"),true );
m_Choice = 0;
for( unsigned i=0; i<m_aModeChoices.size(); i++ )
if( i != m_Choice )
{
m_textChoice[i].SetZoom( ZOOM_NOT_SELECTED );
m_textChoice[i].Command( MENU_ITEM_CREATE );
}
else
GainFocus( m_Choice );
SOUND->PlayMusic( THEME->GetPathToS("ScreenTitleMenu music") );
this->PostScreenMessage( SM_PlayComment, SECONDS_BETWEEN_COMMENTS);
this->SortByDrawOrder();
// this->MoveToTail( &m_AttractOut ); // put it in the back so it covers up the stuff we just added
}
ScreenTitleMenu::~ScreenTitleMenu()
{
LOG->Trace( "ScreenTitleMenu::~ScreenTitleMenu()" );
}
void ScreenTitleMenu::UpdateSelectableChoices()
{
}
void ScreenTitleMenu::MoveCursor( bool up )
{
if( PREFSMAN->GetCoinMode() != COIN_HOME )
return;
// if( m_BeginOut.IsTransitioning() )
// return;
TimeToDemonstration.GetDeltaTime(); /* Reset the demonstration timer when a key is pressed. */
LoseFocus( m_Choice );
m_Choice += (up? -1:+1);
wrap( (int&)m_Choice, m_aModeChoices.size() );
m_soundChange.Play();
GainFocus( m_Choice );
}
void ScreenTitleMenu::Input( const DeviceInput& DeviceI, const InputEventType type, const GameInput &GameI, const MenuInput &MenuI, const StyleInput &StyleI )
{
LOG->Trace( "ScreenTitleMenu::Input( %d-%d )", DeviceI.device, DeviceI.button ); // debugging gameport joystick problem
if( type != IET_FIRST_PRESS )
return;
/* If the CoinMode was changed, we need to reload this screen
* so that the right m_aModeChoices will show */
if( ScreenAttract::ChangeCoinModeInput( DeviceI, type, GameI, MenuI, StyleI ) )
{
SCREENMAN->SetNewScreen( "ScreenTitleMenu" );
return;
}
if( m_In.IsTransitioning() || m_Back.IsTransitioning() ) /* not m_Out */
return;
if( MenuI.IsValid() )
{
switch( MenuI.button )
{
case MENU_BUTTON_UP:
case MENU_BUTTON_LEFT:
MoveCursor( true );
break;
case MENU_BUTTON_DOWN:
case MENU_BUTTON_RIGHT:
MoveCursor( false );
break;
case MENU_BUTTON_BACK:
if( m_Out.IsTransitioning() )
break;
Back( SM_GoToAttractLoop );
break;
case MENU_BUTTON_START:
/* return if the choice is invalid */
const ModeChoice &mc = m_aModeChoices[m_Choice];
CString why;
if( !mc.IsPlayable( &why ) )
{
SCREENMAN->PlayInvalidSound();
if( why != "" )
SCREENMAN->SystemMessage( why );
return;
}
if( !Screen::JoinInput( DeviceI, type, GameI, MenuI, StyleI ) )
return;
if( !m_Out.IsTransitioning() )
StartTransitioning( SM_GoToNextScreen );
}
}
// detect codes
if( CodeDetector::EnteredCode(GameI.controller,CodeDetector::CODE_NEXT_THEME) ||
CodeDetector::EnteredCode(GameI.controller,CodeDetector::CODE_NEXT_THEME2) )
{
THEME->NextTheme();
ApplyGraphicOptions(); // update window title and icon
SCREENMAN->SystemMessage( "Theme: "+THEME->GetCurThemeName() );
SCREENMAN->SetNewScreen( "ScreenTitleMenu" );
TEXTUREMAN->DoDelayedDelete();
}
if( CodeDetector::EnteredCode(GameI.controller,CodeDetector::CODE_NEXT_ANNOUNCER) ||
CodeDetector::EnteredCode(GameI.controller,CodeDetector::CODE_NEXT_ANNOUNCER2) )
{
ANNOUNCER->NextAnnouncer();
CString sName = ANNOUNCER->GetCurAnnouncerName();
if( sName=="" ) sName = "(none)";
SCREENMAN->SystemMessage( "Announcer: "+sName );
SCREENMAN->SetNewScreen( "ScreenTitleMenu" );
}
if( CodeDetector::EnteredCode(GameI.controller,CodeDetector::CODE_NEXT_GAME) ||
CodeDetector::EnteredCode(GameI.controller,CodeDetector::CODE_NEXT_GAME2) )
{
vector<const Game*> vGames;
GAMEMAN->GetEnabledGames( vGames );
ASSERT( !vGames.empty() );
vector<const Game*>::iterator iter = find(vGames.begin(),vGames.end(),GAMESTATE->m_pCurGame);
ASSERT( iter != vGames.end() );
iter++; // move to the next game
// wrap
if( iter == vGames.end() )
iter = vGames.begin();
GAMESTATE->m_pCurGame = *iter;
/* Reload the theme if it's changed, but don't back to the initial screen. */
ResetGame( false );
SCREENMAN->SystemMessage( CString("Game: ") + GAMESTATE->GetCurrentGame()->m_szName );
SCREENMAN->SetNewScreen( "ScreenTitleMenu" );
}
ScreenSelect::Input( DeviceI, type, GameI, MenuI, StyleI );
}
void ScreenTitleMenu::Update( float fDelta )
{
// time out on this screen and go to the attract sequence
if( !IsTransitioning() && TimeToDemonstration.PeekDeltaTime() >= SECONDS_BEFORE_ATTRACT)
{
// don't time out on this screen is coin mode is pay.
// If we're here, then there's a credit in the machine.
if( PREFSMAN->GetCoinMode() == COIN_PAY )
; // do nothing
else
{
this->PostScreenMessage( SM_GoToAttractLoop, 0 );
TimeToDemonstration.GetDeltaTime();
}
}
Screen::Update(fDelta);
}
void ScreenTitleMenu::HandleScreenMessage( const ScreenMessage SM )
{
switch( SM )
{
case SM_PlayComment:
SOUND->PlayOnceFromAnnouncer( "title menu attract" );
this->PostScreenMessage( SM_PlayComment, SECONDS_BETWEEN_COMMENTS );
break;
case SM_GoToNextScreen:
/* XXX: Bad hack: we only want to set default options if we're actually
* going into the game. We don't want to set it if we're going into the
* editor menu, since that never resets options (so it'll maintain changes
* when entering and exiting the editor), and the editor probably shouldn't
* use default options. */
if( m_Choice == 0 )
{
// apply default options
FOREACH_PlayerNumber( p )
GAMESTATE->m_PlayerOptions[p].FromString( PREFSMAN->m_sDefaultModifiers );
GAMESTATE->m_SongOptions.FromString( PREFSMAN->m_sDefaultModifiers );
}
m_aModeChoices[m_Choice].ApplyToAllPlayers();
break;
case SM_GoToAttractLoop:
SCREENMAN->SetNewScreen( INITIAL_SCREEN );
break;
}
}
void ScreenTitleMenu::LoseFocus( int iChoiceIndex )
{
m_textChoice[iChoiceIndex].SetEffectNone();
m_textChoice[iChoiceIndex].StopTweening();
m_textChoice[iChoiceIndex].BeginTweening( 0.3f );
m_textChoice[iChoiceIndex].SetZoom( ZOOM_NOT_SELECTED );
}
void ScreenTitleMenu::GainFocus( int iChoiceIndex )
{
m_textChoice[iChoiceIndex].StopTweening();
m_textChoice[iChoiceIndex].BeginTweening( 0.3f );
m_textChoice[iChoiceIndex].SetZoom( ZOOM_SELECTED );
RageColor color1, color2;
color1 = COLOR_SELECTED;
color2 = color1 * 0.5f;
color2.a = 1;
m_textChoice[iChoiceIndex].SetEffectDiffuseShift( 0.5f, color1, color2 );
}
/*
* (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.
*/