Advertisement
xepher95

ScreenSelectMusic.cpp

Mar 9th, 2013
74
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 61.64 KB | None | 0 0
  1. #include "global.h"
  2. #include "ScreenSelectMusic.h"
  3. #include "ScreenManager.h"
  4. #include "PrefsManager.h"
  5. #include "SongManager.h"
  6. #include "GameManager.h"
  7. #include "GameSoundManager.h"
  8. #include "GameConstantsAndTypes.h"
  9. #include "RageLog.h"
  10. #include "InputMapper.h"
  11. #include "GameState.h"
  12. #include "CodeDetector.h"
  13. #include "ThemeManager.h"
  14. #include "Steps.h"
  15. #include "ActorUtil.h"
  16. #include "RageTextureManager.h"
  17. #include "Course.h"
  18. #include "ProfileManager.h"
  19. #include "Profile.h"
  20. #include "MenuTimer.h"
  21. #include "StatsManager.h"
  22. #include "StepsUtil.h"
  23. #include "Foreach.h"
  24. #include "Style.h"
  25. #include "PlayerState.h"
  26. #include "CommonMetrics.h"
  27. #include "BannerCache.h"
  28. //#include "BackgroundCache.h"
  29. #include "Song.h"
  30. #include "InputEventPlus.h"
  31. #include "RageInput.h"
  32. #include "OptionsList.h"
  33.  
  34. static const char *SelectionStateNames[] = {
  35.     "SelectingSong",
  36.     "SelectingSteps",
  37.     "SelectingConfirm",
  38.     "Finalized"
  39. };
  40. XToString( SelectionState );
  41.  
  42. /** @brief The maximum number of digits for the ScoreDisplay. */
  43. const int NUM_SCORE_DIGITS = 9;
  44.  
  45. #define SHOW_OPTIONS_MESSAGE_SECONDS        THEME->GetMetricF( m_sName, "ShowOptionsMessageSeconds" )
  46.  
  47. AutoScreenMessage( SM_AllowOptionsMenuRepeat );
  48. AutoScreenMessage( SM_SongChanged );
  49. AutoScreenMessage( SM_SortOrderChanging );
  50. AutoScreenMessage( SM_SortOrderChanged );
  51. AutoScreenMessage( SM_BackFromPlayerOptions );
  52.  
  53. static RString g_sCDTitlePath;
  54. static bool g_bWantFallbackCdTitle;
  55. static bool g_bCDTitleWaiting = false;
  56. static RString g_sBannerPath;
  57. static bool g_bBannerWaiting = false;
  58. static bool g_bSampleMusicWaiting = false;
  59. static RageTimer g_StartedLoadingAt(RageZeroTimer);
  60. static RageTimer g_ScreenStartedLoadingAt(RageZeroTimer);
  61. RageTimer g_CanOpenOptionsList(RageZeroTimer);
  62.  
  63. REGISTER_SCREEN_CLASS( ScreenSelectMusic );
  64. void ScreenSelectMusic::Init()
  65. {
  66.     g_ScreenStartedLoadingAt.Touch();
  67.     if( PREFSMAN->m_sTestInitialScreen.Get() == m_sName )
  68.     {
  69.         GAMESTATE->m_PlayMode.Set( PLAY_MODE_REGULAR );
  70.         GAMESTATE->SetCurrentStyle( GAMEMAN->GameAndStringToStyle(GAMEMAN->GetDefaultGame(),"versus") );
  71.         GAMESTATE->JoinPlayer( PLAYER_1 );
  72.         GAMESTATE->SetMasterPlayerNumber(PLAYER_1);
  73.     }
  74.  
  75.     IDLE_COMMENT_SECONDS.Load( m_sName, "IdleCommentSeconds" );
  76.     SAMPLE_MUSIC_DELAY_INIT.Load( m_sName, "SampleMusicDelayInit" );
  77.     SAMPLE_MUSIC_DELAY.Load( m_sName, "SampleMusicDelay" );
  78.     SAMPLE_MUSIC_LOOPS.Load( m_sName, "SampleMusicLoops" );
  79.     SAMPLE_MUSIC_PREVIEW_MODE.Load( m_sName, "SampleMusicPreviewMode" );
  80.     SAMPLE_MUSIC_FALLBACK_FADE_IN_SECONDS.Load( m_sName, "SampleMusicFallbackFadeInSeconds" );
  81.     DO_ROULETTE_ON_MENU_TIMER.Load( m_sName, "DoRouletteOnMenuTimer" );
  82.     ROULETTE_TIMER_SECONDS.Load( m_sName, "RouletteTimerSeconds" );
  83.     ALIGN_MUSIC_BEATS.Load( m_sName, "AlignMusicBeat" );
  84.     CODES.Load( m_sName, "Codes" );
  85.     MUSIC_WHEEL_TYPE.Load( m_sName, "MusicWheelType" );
  86.     SELECT_MENU_AVAILABLE.Load( m_sName, "SelectMenuAvailable" );
  87.     MODE_MENU_AVAILABLE.Load( m_sName, "ModeMenuAvailable" );
  88.     USE_OPTIONS_LIST.Load( m_sName, "UseOptionsList" );
  89.     USE_PLAYER_SELECT_MENU.Load( m_sName, "UsePlayerSelectMenu" );
  90.     SELECT_MENU_NAME.Load( m_sName, "SelectMenuScreenName" );
  91.     OPTIONS_LIST_TIMEOUT.Load( m_sName, "OptionsListTimeout" );
  92.     SELECT_MENU_CHANGES_DIFFICULTY.Load( m_sName, "SelectMenuChangesDifficulty" );
  93.     TWO_PART_SELECTION.Load( m_sName, "TwoPartSelection" );
  94.     TWO_PART_CONFIRMS_ONLY.Load( m_sName, "TwoPartConfirmsOnly" );
  95.     TWO_PART_TIMER_SECONDS.Load( m_sName, "TwoPartTimerSeconds" );
  96.     WRAP_CHANGE_STEPS.Load( m_sName, "WrapChangeSteps" );
  97.     NULL_SCORE_STRING.Load( m_sName, "NullScoreString" );
  98.     PLAY_SOUND_ON_ENTERING_OPTIONS_MENU.Load( m_sName, "PlaySoundOnEnteringOptionsMenu" );
  99.     // To allow changing steps with gamebuttons -DaisuMaster
  100.     CHANGE_STEPS_WITH_GAME_BUTTONS.Load( m_sName, "ChangeStepsWithGameButtons" );
  101.     CHANGE_GROUPS_WITH_GAME_BUTTONS.Load( m_sName, "ChangeGroupsWithGameButtons" );
  102.  
  103.     m_GameButtonPreviousSong = INPUTMAPPER->GetInputScheme()->ButtonNameToIndex( THEME->GetMetric(m_sName,"PreviousSongButton") );
  104.     m_GameButtonNextSong = INPUTMAPPER->GetInputScheme()->ButtonNameToIndex( THEME->GetMetric(m_sName,"NextSongButton") );
  105.  
  106.     // Ask for those only if changing steps with gamebuttons is allowed -DaisuMaster
  107.     if( CHANGE_STEPS_WITH_GAME_BUTTONS )
  108.     {
  109.         m_GameButtonPreviousDifficulty = INPUTMAPPER->GetInputScheme()->ButtonNameToIndex( THEME->GetMetric(m_sName,"PreviousDifficultyButton") );
  110.         m_GameButtonNextDifficulty = INPUTMAPPER->GetInputScheme()->ButtonNameToIndex( THEME->GetMetric(m_sName,"NextDifficultyButton") );
  111.     }
  112.     // same here but for groups -DaisuMaster
  113.     if( CHANGE_GROUPS_WITH_GAME_BUTTONS )
  114.     {
  115.         m_GameButtonPreviousGroup = INPUTMAPPER->GetInputScheme()->ButtonNameToIndex( THEME->GetMetric(m_sName,"PreviousGroupButton") );
  116.         m_GameButtonNextGroup = INPUTMAPPER->GetInputScheme()->ButtonNameToIndex( THEME->GetMetric(m_sName,"NextGroupButton") );
  117.     }
  118.  
  119.     FOREACH_ENUM( PlayerNumber, p )
  120.     {
  121.         m_bSelectIsDown[p] = false; // used by UpdateSelectButton
  122.         m_bAcceptSelectRelease[p] = false;
  123.     }
  124.  
  125.     ScreenWithMenuElements::Init();
  126.  
  127.     this->SubscribeToMessage( Message_PlayerJoined );
  128.  
  129.     // Cache these values
  130.     // Marking for change -- Midiman (why? -aj)
  131.     m_sSectionMusicPath =       THEME->GetPathS(m_sName,"section music");
  132.     m_sSortMusicPath =          THEME->GetPathS(m_sName,"sort music");
  133.     m_sRouletteMusicPath =      THEME->GetPathS(m_sName,"roulette music");
  134.     m_sRandomMusicPath =        THEME->GetPathS(m_sName,"random music");
  135.     m_sCourseMusicPath =        THEME->GetPathS(m_sName,"course music");
  136.     m_sLoopMusicPath =          THEME->GetPathS(m_sName,"loop music");
  137.     m_sFallbackCDTitlePath =    THEME->GetPathG(m_sName,"fallback cdtitle");
  138.  
  139.     m_TexturePreload.Load( m_sFallbackCDTitlePath );
  140.  
  141.     // load banners
  142.     if( PREFSMAN->m_BannerCache != BNCACHE_OFF )
  143.     {
  144.         m_TexturePreload.Load( Banner::SongBannerTexture(THEME->GetPathG("Banner","all music")) );
  145.         m_TexturePreload.Load( Banner::SongBannerTexture(THEME->GetPathG("Common","fallback banner")) );
  146.         m_TexturePreload.Load( Banner::SongBannerTexture(THEME->GetPathG("Banner","roulette")) );
  147.         m_TexturePreload.Load( Banner::SongBannerTexture(THEME->GetPathG("Banner","random")) );
  148.         m_TexturePreload.Load( Banner::SongBannerTexture(THEME->GetPathG("Banner","mode")) );
  149.     }
  150.     // load backgrounds
  151.     /*
  152.     if( PREFSMAN->m_BackgroundCache != BGCACHE_OFF )
  153.     {
  154.         m_TexturePreload.Load( Sprite::SongBGTexture(THEME->GetPathG("SongBackgroundItem","AllMusic")) );
  155.         m_TexturePreload.Load( Sprite::SongBGTexture(THEME->GetPathG("Common","fallback banner")) );
  156.         m_TexturePreload.Load( Sprite::SongBGTexture(THEME->GetPathG("SongBackgroundItem","roulette")) );
  157.         m_TexturePreload.Load( Sprite::SongBGTexture(THEME->GetPathG("SongBackgroundItem","random")) );
  158.         m_TexturePreload.Load( Sprite::SongBGTexture(THEME->GetPathG("SongBackgroundItem","Mode")) );
  159.         m_TexturePreload.Load( Sprite::SongBGTexture(THEME->GetPathG("SongBackgroundItem","group fallback")) );
  160.         m_TexturePreload.Load( Sprite::SongBGTexture(THEME->GetPathG("SongBackgroundItem","course fallback")) );
  161.     }
  162.     */
  163.  
  164.     // Load low-res banners and backgrounds if needed.
  165.     BANNERCACHE->Demand();
  166.     //BACKGROUNDCACHE->Demand();
  167.  
  168.     m_MusicWheel.SetName( "MusicWheel" );
  169.     m_MusicWheel.Load( MUSIC_WHEEL_TYPE );
  170.     LOAD_ALL_COMMANDS_AND_SET_XY( m_MusicWheel );
  171.     this->AddChild( &m_MusicWheel );
  172.  
  173.     if( USE_OPTIONS_LIST )
  174.     {
  175.         FOREACH_PlayerNumber(p)
  176.         {
  177.             m_OptionsList[p].SetName( "OptionsList" + PlayerNumberToString(p) );
  178.             m_OptionsList[p].Load( "OptionsList", p );
  179.             m_OptionsList[p].SetDrawOrder( 100 );
  180.             ActorUtil::LoadAllCommands( m_OptionsList[p], m_sName );
  181.             this->AddChild( &m_OptionsList[p] );
  182.         }
  183.         m_OptionsList[PLAYER_1].Link( &m_OptionsList[PLAYER_2] );
  184.         m_OptionsList[PLAYER_2].Link( &m_OptionsList[PLAYER_1] );
  185.     }
  186.  
  187.     // this is loaded SetSong and TweenToSong
  188.     m_Banner.SetName( "Banner" );
  189.     LOAD_ALL_COMMANDS_AND_SET_XY( m_Banner );
  190.     this->AddChild( &m_Banner );
  191.  
  192.     /*m_sprCDTitleFront.SetName( "CDTitle" );
  193.     m_sprCDTitleFront.Load( THEME->GetPathG(m_sName,"fallback cdtitle") );
  194.     LOAD_ALL_COMMANDS_AND_SET_XY( m_sprCDTitleFront );
  195.     COMMAND( m_sprCDTitleFront, "Front" );
  196.     this->AddChild( &m_sprCDTitleFront );
  197.  
  198.     m_sprCDTitleBack.SetName( "CDTitle" );
  199.     m_sprCDTitleBack.Load( THEME->GetPathG(m_sName,"fallback cdtitle") );
  200.     LOAD_ALL_COMMANDS_AND_SET_XY( m_sprCDTitleBack );
  201.     COMMAND( m_sprCDTitleBack, "Back" );
  202.     this->AddChild( &m_sprCDTitleBack );*/
  203.  
  204.     FOREACH_ENUM( PlayerNumber, p )
  205.     {
  206.         m_sprHighScoreFrame[p].Load( THEME->GetPathG(m_sName,ssprintf("ScoreFrame P%d",p+1)) );
  207.         m_sprHighScoreFrame[p]->SetName( ssprintf("ScoreFrameP%d",p+1) );
  208.         LOAD_ALL_COMMANDS_AND_SET_XY( m_sprHighScoreFrame[p] );
  209.         this->AddChild( m_sprHighScoreFrame[p] );
  210.  
  211.         m_textHighScore[p].SetName( ssprintf("ScoreP%d",p+1) );
  212.         m_textHighScore[p].LoadFromFont( THEME->GetPathF(m_sName,"score") );
  213.         LOAD_ALL_COMMANDS_AND_SET_XY( m_textHighScore[p] );
  214.         this->AddChild( &m_textHighScore[p] );
  215.     }
  216.  
  217.     RageSoundLoadParams SoundParams;
  218.     SoundParams.m_bSupportPan = true;
  219.  
  220.     m_soundStart.Load( THEME->GetPathS(m_sName,"start") );
  221.     m_soundDifficultyEasier.Load( THEME->GetPathS(m_sName,"difficulty easier"), false, &SoundParams );
  222.     m_soundDifficultyHarder.Load( THEME->GetPathS(m_sName,"difficulty harder"), false, &SoundParams );
  223.     m_soundOptionsChange.Load( THEME->GetPathS(m_sName,"options") );
  224.     m_soundLocked.Load( THEME->GetPathS(m_sName,"locked") );
  225.  
  226.     this->SortByDrawOrder();
  227. }
  228.  
  229. void ScreenSelectMusic::BeginScreen()
  230. {
  231.     g_ScreenStartedLoadingAt.Touch();
  232.     m_timerIdleComment.GetDeltaTime();
  233.  
  234.     if( CommonMetrics::AUTO_SET_STYLE )
  235.     {
  236.         vector<StepsType> vst;
  237.         GAMEMAN->GetStepsTypesForGame( GAMESTATE->m_pCurGame, vst );
  238.         const Style *pStyle = GAMEMAN->GetFirstCompatibleStyle( GAMESTATE->m_pCurGame, GAMESTATE->GetNumSidesJoined(), vst[0] );
  239.         GAMESTATE->SetCurrentStyle( pStyle );
  240.     }
  241.  
  242.     if( GAMESTATE->GetCurrentStyle() == NULL )
  243.         RageException::Throw( "The Style has not been set.  A theme must set the Style before loading ScreenSelectMusic." );
  244.  
  245.     if( GAMESTATE->m_PlayMode == PlayMode_Invalid )
  246.     {
  247.         // Instead of crashing here, let's just set the PlayMode to regular
  248.         GAMESTATE->m_PlayMode.Set( PLAY_MODE_REGULAR );
  249.         LOG->Trace( "PlayMode not set, setting as regular." );
  250.     }
  251.     FOREACH_ENUM( PlayerNumber, pn )
  252.     {
  253.         if( GAMESTATE->IsHumanPlayer(pn) )
  254.             continue;
  255.         m_sprHighScoreFrame[pn]->SetVisible( false );
  256.         m_textHighScore[pn].SetVisible( false );
  257.     }
  258.  
  259.     OPTIONS_MENU_AVAILABLE.Load( m_sName, "OptionsMenuAvailable" );
  260.     PlayCommand( "Mods" );
  261.     m_MusicWheel.BeginScreen();
  262.  
  263.     m_SelectionState = SelectionState_SelectingSong;
  264.     ZERO( m_bStepsChosen );
  265.     m_bGoToOptions = false;
  266.     m_bAllowOptionsMenu = m_bAllowOptionsMenuRepeat = false;
  267.     ZERO( m_iSelection );
  268.  
  269.     if( USE_OPTIONS_LIST )
  270.         FOREACH_PlayerNumber( pn )
  271.             m_OptionsList[pn].Reset();
  272.  
  273.     AfterMusicChange();
  274.  
  275.     SOUND->PlayOnceFromAnnouncer( "select music intro" );
  276.  
  277.     ScreenWithMenuElements::BeginScreen();
  278. }
  279.  
  280. ScreenSelectMusic::~ScreenSelectMusic()
  281. {
  282.     LOG->Trace( "ScreenSelectMusic::~ScreenSelectMusic()" );
  283.     BANNERCACHE->Undemand();
  284.     //BACKGROUNDCACHE->Undemand();
  285. }
  286.  
  287. // If bForce is true, the next request will be started even if it might cause a skip.
  288. void ScreenSelectMusic::CheckBackgroundRequests( bool bForce )
  289. {
  290.     if( g_bCDTitleWaiting )
  291.     {
  292.         // The CDTitle is normally very small, so we don't bother waiting to display it.
  293.         RString sPath;
  294.         if( !m_BackgroundLoader.IsCacheFileFinished(g_sCDTitlePath, sPath) )
  295.             return;
  296.  
  297.         g_bCDTitleWaiting = false;
  298.  
  299.         RString sCDTitlePath = sPath;
  300.  
  301.         if( sCDTitlePath.empty() || !IsAFile(sCDTitlePath) )
  302.             sCDTitlePath = g_bWantFallbackCdTitle? m_sFallbackCDTitlePath:RString("");
  303.  
  304.         if( !sCDTitlePath.empty() )
  305.         {
  306.             TEXTUREMAN->DisableOddDimensionWarning();
  307.             m_sprCDTitleFront.Load( sCDTitlePath );
  308.             m_sprCDTitleBack.Load( sCDTitlePath );
  309.             TEXTUREMAN->EnableOddDimensionWarning();
  310.         }
  311.  
  312.         m_BackgroundLoader.FinishedWithCachedFile( g_sCDTitlePath );
  313.     }
  314.  
  315.     /* Loading the rest can cause small skips, so don't do it until the wheel settles.
  316.      * Do load if we're transitioning out, though, so we don't miss starting the music
  317.      * for the options screen if a song is selected quickly.  Also, don't do this
  318.      * if the wheel is locked, since we're just bouncing around after selecting
  319.      * TYPE_RANDOM, and it'll take a while before the wheel will settle. */
  320.     if( !m_MusicWheel.IsSettled() && !m_MusicWheel.WheelIsLocked() && !bForce )
  321.         return;
  322.  
  323.     if( g_bBannerWaiting )
  324.     {
  325.         if( m_Banner.GetTweenTimeLeft() > 0 )
  326.             return;
  327.  
  328.         RString sPath;
  329.         bool bFreeCache = false;
  330.         if( TEXTUREMAN->IsTextureRegistered( Sprite::SongBannerTexture(g_sBannerPath) ) )
  331.         {
  332.             /* If the file is already loaded into a texture, it's finished,
  333.              * and we only do this to honor the HighQualTime value. */
  334.             sPath = g_sBannerPath;
  335.         }
  336.         else
  337.         {
  338.             if( !m_BackgroundLoader.IsCacheFileFinished( g_sBannerPath, sPath ) )
  339.                 return;
  340.             bFreeCache = true;
  341.         }
  342.  
  343.         g_bBannerWaiting = false;
  344.         m_Banner.Load( sPath, true );
  345.  
  346.         if( bFreeCache )
  347.             m_BackgroundLoader.FinishedWithCachedFile( g_sBannerPath );
  348.     }
  349.  
  350.     // Nothing else is going.  Start the music, if we haven't yet.
  351.     if( g_bSampleMusicWaiting )
  352.     {
  353.         if(g_ScreenStartedLoadingAt.Ago() < SAMPLE_MUSIC_DELAY_INIT)
  354.             return;
  355.  
  356.         // Don't start the music sample when moving fast.
  357.         if( g_StartedLoadingAt.Ago() < SAMPLE_MUSIC_DELAY && !bForce )
  358.             return;
  359.  
  360.         g_bSampleMusicWaiting = false;
  361.  
  362.         GameSoundManager::PlayMusicParams PlayParams;
  363.         PlayParams.sFile = m_sSampleMusicToPlay;
  364.         PlayParams.pTiming = m_pSampleMusicTimingData;
  365.         PlayParams.bForceLoop = SAMPLE_MUSIC_LOOPS;
  366.         PlayParams.fStartSecond = m_fSampleStartSeconds;
  367.         PlayParams.fLengthSeconds = m_fSampleLengthSeconds;
  368.         PlayParams.fFadeOutLengthSeconds = 1.5f;
  369.         PlayParams.bAlignBeat = ALIGN_MUSIC_BEATS;
  370.         PlayParams.bApplyMusicRate = true;
  371.  
  372.         GameSoundManager::PlayMusicParams FallbackMusic;
  373.         FallbackMusic.sFile = m_sLoopMusicPath;
  374.         FallbackMusic.fFadeInLengthSeconds = SAMPLE_MUSIC_FALLBACK_FADE_IN_SECONDS;
  375.         FallbackMusic.bAlignBeat = ALIGN_MUSIC_BEATS;
  376.  
  377.         SOUND->PlayMusic( PlayParams, FallbackMusic );
  378.     }
  379. }
  380.  
  381. void ScreenSelectMusic::Update( float fDeltaTime )
  382. {
  383.     if( !IsTransitioning() )
  384.     {
  385.         if( IDLE_COMMENT_SECONDS > 0  &&  m_timerIdleComment.PeekDeltaTime() >= IDLE_COMMENT_SECONDS )
  386.         {
  387.             SOUND->PlayOnceFromAnnouncer( m_sName+" IdleComment" );
  388.             m_timerIdleComment.GetDeltaTime();
  389.         }
  390.     }
  391.  
  392.     ScreenWithMenuElements::Update( fDeltaTime );
  393.  
  394.     CheckBackgroundRequests( false );
  395. }
  396. bool ScreenSelectMusic::Input( const InputEventPlus &input )
  397. {
  398.     // HACK: This screen eats mouse inputs if we don't check for them first.
  399.     bool mouse_evt = false;
  400.     for (int i = MOUSE_LEFT; i <= MOUSE_WHEELDOWN; i++)
  401.     {
  402.         if (input.DeviceI == DeviceInput( DEVICE_MOUSE, (DeviceButton)i ))
  403.             mouse_evt = true;
  404.     }
  405.     if (mouse_evt) 
  406.     {
  407.         return ScreenWithMenuElements::Input(input);
  408.     }
  409. //  LOG->Trace( "ScreenSelectMusic::Input()" );
  410.  
  411.     // reset announcer timer
  412.     m_timerIdleComment.GetDeltaTime();
  413.  
  414.     // debugging?
  415.     // I just like being able to see untransliterated titles occasionally.
  416.     if( input.DeviceI.device == DEVICE_KEYBOARD && input.DeviceI.button == KEY_F9 )
  417.     {
  418.         if( input.type != IET_FIRST_PRESS )
  419.             return false;
  420.         PREFSMAN->m_bShowNativeLanguage.Set( !PREFSMAN->m_bShowNativeLanguage );
  421.         MESSAGEMAN->Broadcast( "DisplayLanguageChanged" );
  422.         m_MusicWheel.RebuildWheelItems();
  423.         return true;
  424.     }
  425.  
  426.     if( !IsTransitioning() && m_SelectionState != SelectionState_Finalized )
  427.     {
  428.         bool bHoldingCtrl =
  429.         INPUTFILTER->IsBeingPressed(DeviceInput(DEVICE_KEYBOARD, KEY_LCTRL)) ||
  430.         INPUTFILTER->IsBeingPressed(DeviceInput(DEVICE_KEYBOARD, KEY_RCTRL));
  431.  
  432.         wchar_t c = INPUTMAN->DeviceInputToChar(input.DeviceI,false);
  433.         MakeUpper( &c, 1 );
  434.  
  435.         if( bHoldingCtrl && ( c >= 'A' ) && ( c <= 'Z' ) )
  436.         {
  437.             // Only allow changing the sort order if the wheel is not locked
  438.             // and we're not in course mode. -aj
  439.             if( !m_MusicWheel.WheelIsLocked() && !GAMESTATE->IsCourseMode() )
  440.             {
  441.                 SortOrder so = GAMESTATE->m_SortOrder;
  442.                 // When in Artist sort, this means first letter of the artist.
  443.                 // Otherwise, if not in Title sort already, switch to Title sort.
  444.                 if ( so != SORT_ARTIST )
  445.                     so = SORT_TITLE;
  446.  
  447.                 GAMESTATE->m_PreferredSortOrder = so;
  448.                 GAMESTATE->m_SortOrder.Set( so );
  449.                 // Odd, changing the sort order requires us to call SetOpenSection more than once
  450.                 m_MusicWheel.ChangeSort( so );
  451.                 m_MusicWheel.SetOpenSection( ssprintf("%c", c ) );
  452.  
  453.                 m_MusicWheel.SelectSection( ssprintf("%c", c ) );
  454.                 m_MusicWheel.ChangeSort( so );
  455.                 m_MusicWheel.SetOpenSection( ssprintf("%c", c ) );
  456.                 AfterMusicChange();
  457.                 return true;
  458.             }
  459.         }
  460.     }
  461.  
  462.     if( !input.GameI.IsValid() )
  463.         return false; // don't care
  464.  
  465.     // Handle late joining
  466.     if( m_SelectionState != SelectionState_Finalized  &&  input.MenuI == GAME_BUTTON_START  &&  input.type == IET_FIRST_PRESS  &&  GAMESTATE->JoinInput(input.pn) )
  467.         return true; // don't handle this press again below
  468.  
  469.     if( !GAMESTATE->IsHumanPlayer(input.pn) )
  470.         return false;
  471.  
  472.     // Check for "Press START again for options" button press
  473.     if( m_SelectionState == SelectionState_Finalized  &&
  474.         input.MenuI == GAME_BUTTON_START  &&
  475.         input.type != IET_RELEASE  &&
  476.         OPTIONS_MENU_AVAILABLE.GetValue() )
  477.     {
  478.         if( m_bGoToOptions )
  479.             return false; // got it already
  480.         if( !m_bAllowOptionsMenu )
  481.             return false; // not allowed
  482.  
  483.         if( !m_bAllowOptionsMenuRepeat && input.type == IET_REPEAT )
  484.         {
  485.             return false; // not allowed yet
  486.         }
  487.  
  488.         m_bGoToOptions = true;
  489.         if( PLAY_SOUND_ON_ENTERING_OPTIONS_MENU )
  490.             m_soundStart.Play();
  491.         this->PlayCommand( "ShowEnteringOptions" );
  492.  
  493.         // Re-queue SM_BeginFadingOut, since ShowEnteringOptions may have
  494.         // short-circuited animations.
  495.         this->ClearMessageQueue( SM_BeginFadingOut );
  496.         this->PostScreenMessage( SM_BeginFadingOut, this->GetTweenTimeLeft() );
  497.  
  498.         return true;
  499.     }
  500.  
  501.     if( IsTransitioning() )
  502.         return false; // ignore
  503.  
  504.     // Handle unselect steps
  505.     // xxx: select button could conflict with OptionsList here -aj
  506.     if( m_SelectionState == SelectionState_SelectingSteps && m_bStepsChosen[input.pn]
  507.         && input.MenuI == GAME_BUTTON_SELECT && input.type == IET_FIRST_PRESS )
  508.     {
  509.         Message msg("StepsUnchosen");
  510.         msg.SetParam( "Player", input.pn );
  511.         MESSAGEMAN->Broadcast( msg );
  512.         m_bStepsChosen[input.pn] = false;
  513.         return true;
  514.     }
  515.  
  516.     if( m_SelectionState == SelectionState_Finalized  ||
  517.         m_bStepsChosen[input.pn] )
  518.         return false; // ignore
  519.  
  520.     if( USE_PLAYER_SELECT_MENU )
  521.     {
  522.         if( input.type == IET_RELEASE  &&  input.MenuI == GAME_BUTTON_SELECT )
  523.         {
  524.             SCREENMAN->AddNewScreenToTop( SELECT_MENU_NAME, SM_BackFromPlayerOptions );
  525.         }
  526.     }
  527.  
  528.     // handle OptionsList input
  529.     if( USE_OPTIONS_LIST )
  530.     {
  531.         PlayerNumber pn = input.pn;
  532.         if( pn != PLAYER_INVALID )
  533.         {
  534.             if( m_OptionsList[pn].IsOpened() )
  535.             {
  536.                 return m_OptionsList[pn].Input( input );
  537.             }
  538.             else
  539.             {
  540.                 if( input.type == IET_RELEASE  &&  input.MenuI == GAME_BUTTON_SELECT && m_bAcceptSelectRelease[pn] )
  541.                     m_OptionsList[pn].Open();
  542.             }
  543.         }
  544.     }
  545.  
  546.     if( input.MenuI == GAME_BUTTON_SELECT && input.type != IET_REPEAT )
  547.         m_bAcceptSelectRelease[input.pn] = (input.type == IET_FIRST_PRESS);
  548.  
  549.     if( SELECT_MENU_AVAILABLE && input.MenuI == GAME_BUTTON_SELECT && input.type != IET_REPEAT )
  550.         UpdateSelectButton( input.pn, input.type == IET_FIRST_PRESS );
  551.  
  552.     if( SELECT_MENU_AVAILABLE  &&  m_bSelectIsDown[input.pn] )
  553.     {
  554.         if( input.type == IET_FIRST_PRESS && SELECT_MENU_CHANGES_DIFFICULTY )
  555.         {
  556.             switch( input.MenuI )
  557.             {
  558.                 case GAME_BUTTON_LEFT:
  559.                     ChangeSteps( input.pn, -1 );
  560.                     m_bAcceptSelectRelease[input.pn] = false;
  561.                     break;
  562.                 case GAME_BUTTON_RIGHT:
  563.                     ChangeSteps( input.pn, +1 );
  564.                     m_bAcceptSelectRelease[input.pn] = false;
  565.                     break;
  566.                 case GAME_BUTTON_START:
  567.                     m_bAcceptSelectRelease[input.pn] = false;
  568.                     if( MODE_MENU_AVAILABLE )
  569.                         m_MusicWheel.NextSort();
  570.                     else
  571.                         m_soundLocked.Play();
  572.                     break;
  573.                 default: break;
  574.             }
  575.         }
  576.         else if( input.type == IET_FIRST_PRESS && input.MenuI != GAME_BUTTON_SELECT )
  577.         {
  578.             Message msg("SelectMenuInput");
  579.             msg.SetParam( "Player", input.pn );
  580.             msg.SetParam( "Button", GameButtonToString(INPUTMAPPER->GetInputScheme(), input.MenuI) );
  581.             MESSAGEMAN->Broadcast( msg );
  582.             m_bAcceptSelectRelease[input.pn] = false;
  583.         }
  584.         if( input.type == IET_FIRST_PRESS )
  585.             g_CanOpenOptionsList.Touch();
  586.         if( g_CanOpenOptionsList.Ago() > OPTIONS_LIST_TIMEOUT )
  587.             m_bAcceptSelectRelease[input.pn] = false;
  588.         return true;
  589.     }
  590.  
  591.     if( m_SelectionState == SelectionState_SelectingSong  &&
  592.         (input.MenuI == m_GameButtonNextSong || input.MenuI == m_GameButtonPreviousSong || input.MenuI == GAME_BUTTON_SELECT) )
  593.     {
  594.         {
  595.             // If we're rouletting, hands off.
  596.             if( m_MusicWheel.IsRouletting() )
  597.                 return false;
  598.  
  599.             bool bLeftIsDown = false;
  600.             bool bRightIsDown = false;
  601.  
  602.             FOREACH_HumanPlayer( p )
  603.             {
  604.                 if( m_OptionsList[p].IsOpened() )
  605.                     continue;
  606.                 if( SELECT_MENU_AVAILABLE && INPUTMAPPER->IsBeingPressed(GAME_BUTTON_SELECT, p) )
  607.                     continue;
  608.  
  609.                 bLeftIsDown |= INPUTMAPPER->IsBeingPressed( m_GameButtonPreviousSong, p );
  610.                 bRightIsDown |= INPUTMAPPER->IsBeingPressed( m_GameButtonNextSong, p );
  611.             }
  612.  
  613.             bool bBothDown = bLeftIsDown && bRightIsDown;
  614.             bool bNeitherDown = !bLeftIsDown && !bRightIsDown;
  615.  
  616.             if( bNeitherDown )
  617.             {
  618.                 // Both buttons released.
  619.                 m_MusicWheel.Move( 0 );
  620.             }
  621.             else if( bBothDown )
  622.             {
  623.                 m_MusicWheel.Move( 0 );
  624.                 if( input.type == IET_FIRST_PRESS )
  625.                 {
  626.                     if( input.MenuI == m_GameButtonPreviousSong )
  627.                         m_MusicWheel.ChangeMusicUnlessLocked( -1 );
  628.                     else if( input.MenuI == m_GameButtonNextSong )
  629.                         m_MusicWheel.ChangeMusicUnlessLocked( +1 );
  630.                 }
  631.             }
  632.             else if( bLeftIsDown )
  633.             {
  634.                 if( input.type != IET_RELEASE )
  635.                 {
  636.                     MESSAGEMAN->Broadcast( "PreviousSong" );
  637.                     m_MusicWheel.Move( -1 );
  638.                 }
  639.             }
  640.             else if( bRightIsDown )
  641.             {
  642.                 if( input.type != IET_RELEASE )
  643.                 {
  644.                     MESSAGEMAN->Broadcast( "NextSong" );
  645.                     m_MusicWheel.Move( +1 );
  646.                 }
  647.             }
  648.             else
  649.             {
  650.                 FAIL_M("Logic bug: L/R keys in an impossible state?");
  651.             }
  652.  
  653.             // Reset the repeat timer when the button is released.
  654.             // This fixes jumping when you release Left and Right after entering the sort
  655.             // code at the same if L & R aren't released at the exact same time.
  656.             if( input.type == IET_RELEASE )
  657.             {
  658.                 INPUTMAPPER->ResetKeyRepeat( m_GameButtonPreviousSong, input.pn );
  659.                 INPUTMAPPER->ResetKeyRepeat( m_GameButtonNextSong, input.pn );
  660.             }
  661.         }
  662.     }
  663.  
  664.     // To allow changing steps with gamebuttons, NOT WITH THE GODDAMN CODEDETECTOR
  665.     // yeah, wanted this since a while ago... -DaisuMaster
  666.     if( CHANGE_STEPS_WITH_GAME_BUTTONS )
  667.     {
  668.         // Avoid any event not being first press
  669.         if( input.type != IET_FIRST_PRESS )
  670.             return false;
  671.  
  672.         if( m_SelectionState == SelectionState_SelectingSong )
  673.         {
  674.             if (input.MenuI == m_GameButtonPreviousDifficulty )
  675.             {
  676.                 if( GAMESTATE->IsAnExtraStageAndSelectionLocked() )
  677.                     m_soundLocked.Play();
  678.                 else
  679.                     ChangeSteps( input.pn, -1 );
  680.             }
  681.             else if( input.MenuI == m_GameButtonNextDifficulty )
  682.             {
  683.                 if( GAMESTATE->IsAnExtraStageAndSelectionLocked() )
  684.                     m_soundLocked.Play();
  685.                 else
  686.                     ChangeSteps( input.pn, +1 );
  687.             }
  688.         }
  689.     }
  690.  
  691.     // Actually I don't like to just copy and paste code because it may go
  692.     // wrong if something goes overlooked -DaisuMaster
  693.     if( CHANGE_GROUPS_WITH_GAME_BUTTONS )
  694.     {
  695.         if( input.type != IET_FIRST_PRESS)
  696.             return false;
  697.  
  698.         if( m_SelectionState == SelectionState_SelectingSong )
  699.         {
  700.             if(input.MenuI == m_GameButtonPreviousGroup )
  701.             {
  702.                 if( GAMESTATE->IsAnExtraStageAndSelectionLocked() )
  703.                     m_soundLocked.Play();
  704.                 else
  705.                 {
  706.                     RString sNewGroup = m_MusicWheel.JumpToPrevGroup();
  707.                     m_MusicWheel.SelectSection(sNewGroup);
  708.                     m_MusicWheel.SetOpenSection(sNewGroup);
  709.                     MESSAGEMAN->Broadcast("PreviousGroup");
  710.                     AfterMusicChange();
  711.                 }
  712.             }
  713.             else if(input.MenuI == m_GameButtonNextGroup )
  714.             {
  715.                 if( GAMESTATE->IsAnExtraStageAndSelectionLocked() )
  716.                     m_soundLocked.Play();
  717.                 else
  718.                 {
  719.                     RString sNewGroup = m_MusicWheel.JumpToNextGroup();
  720.                     m_MusicWheel.SelectSection(sNewGroup);
  721.                     m_MusicWheel.SetOpenSection(sNewGroup);
  722.                     MESSAGEMAN->Broadcast("NextGroup");
  723.                     AfterMusicChange();
  724.                 }
  725.             }
  726.         }
  727.     }
  728.  
  729.     // two part confirms only means we can actually change songs here,
  730.     // so we need some hackery. -aj
  731.     if( TWO_PART_CONFIRMS_ONLY )
  732.     {
  733.         if( m_SelectionState == SelectionState_SelectingSteps )
  734.         {
  735.             if( input.MenuI == m_GameButtonPreviousSong )
  736.             {
  737.                 if( GAMESTATE->IsAnExtraStageAndSelectionLocked() )
  738.                     m_soundLocked.Play();
  739.                 else
  740.                 {
  741.                     m_SelectionState = SelectionState_SelectingSong;
  742.                     MESSAGEMAN->Broadcast("TwoPartConfirmCanceled");
  743.                     MESSAGEMAN->Broadcast("PreviousSong");
  744.                     m_MusicWheel.ChangeMusicUnlessLocked( -1 );
  745.                 }
  746.             }
  747.             else if( input.MenuI == m_GameButtonNextSong )
  748.             {
  749.                 if( GAMESTATE->IsAnExtraStageAndSelectionLocked() )
  750.                     m_soundLocked.Play();
  751.                 else
  752.                 {
  753.                     m_SelectionState = SelectionState_SelectingSong;
  754.                     MESSAGEMAN->Broadcast("TwoPartConfirmCanceled");
  755.                     MESSAGEMAN->Broadcast("NextSong");
  756.                     m_MusicWheel.ChangeMusicUnlessLocked( +1 );
  757.                 }
  758.             }
  759.             // added an entry for difficulty change with gamebuttons -DaisuMaster
  760.             else if( input.MenuI == m_GameButtonPreviousDifficulty )
  761.             {
  762.                 if( GAMESTATE->IsAnExtraStageAndSelectionLocked() )
  763.                     m_soundLocked.Play();
  764.                 else
  765.                 {
  766.                     m_SelectionState = SelectionState_SelectingSong;
  767.                     MESSAGEMAN->Broadcast("TwoPartConfirmCanceled");
  768.                     ChangeSteps( input.pn, -1);
  769.                 }
  770.             }
  771.             else if( input.MenuI == m_GameButtonNextDifficulty )
  772.             {
  773.                 if( GAMESTATE->IsAnExtraStageAndSelectionLocked() )
  774.                     m_soundLocked.Play();
  775.                 else
  776.                 {
  777.                     m_SelectionState = SelectionState_SelectingSong;
  778.                     MESSAGEMAN->Broadcast("TwoPartConfirmCanceled");
  779.                     ChangeSteps( input.pn, +1);
  780.                 }
  781.             }
  782.             // added also for groupchanges
  783.             else if(input.MenuI == m_GameButtonPreviousGroup )
  784.             {
  785.                 if( GAMESTATE->IsAnExtraStageAndSelectionLocked() )
  786.                     m_soundLocked.Play();
  787.                 else
  788.                 {
  789.                     RString sNewGroup = m_MusicWheel.JumpToPrevGroup();
  790.                     m_MusicWheel.SelectSection(sNewGroup);
  791.                     m_MusicWheel.SetOpenSection(sNewGroup);
  792.                     MESSAGEMAN->Broadcast("TwoPartConfirmCanceled");
  793.                     MESSAGEMAN->Broadcast("PreviousGroup");
  794.                     AfterMusicChange();
  795.                 }
  796.             }
  797.             else if(input.MenuI == m_GameButtonNextGroup )
  798.             {
  799.                 if( GAMESTATE->IsAnExtraStageAndSelectionLocked() )
  800.                     m_soundLocked.Play();
  801.                 else
  802.                 {
  803.                     RString sNewGroup = m_MusicWheel.JumpToNextGroup();
  804.                     m_MusicWheel.SelectSection(sNewGroup);
  805.                     m_MusicWheel.SetOpenSection(sNewGroup);
  806.                     MESSAGEMAN->Broadcast("TwoPartConfirmCanceled");
  807.                     MESSAGEMAN->Broadcast("NextGroup");
  808.                     AfterMusicChange();
  809.                 }
  810.             }
  811.         }
  812.     }
  813.     else
  814.     {
  815.         if( m_SelectionState == SelectionState_SelectingSteps && input.type == IET_FIRST_PRESS && !m_bStepsChosen[input.pn] )
  816.         {
  817.             if( input.MenuI == m_GameButtonNextSong || input.MenuI == m_GameButtonPreviousSong )
  818.             {
  819.                 if( input.MenuI == m_GameButtonPreviousSong )
  820.                 {
  821.                     if( GAMESTATE->IsAnExtraStageAndSelectionLocked() )
  822.                         m_soundLocked.Play();
  823.                     else
  824.                         ChangeSteps( input.pn, -1 );
  825.                 }
  826.                 else if( input.MenuI == m_GameButtonNextSong )
  827.                 {
  828.                     if( GAMESTATE->IsAnExtraStageAndSelectionLocked() )
  829.                         m_soundLocked.Play();
  830.                     else
  831.                         ChangeSteps( input.pn, +1 );
  832.                 }
  833.             }
  834.             else if( input.MenuI == GAME_BUTTON_MENUUP || input.MenuI == GAME_BUTTON_MENUDOWN ) // && TWO_PART_DESELECTS_WITH_MENUUPDOWN
  835.             {
  836.                 if( GAMESTATE->IsAnExtraStageAndSelectionLocked() )
  837.                     m_soundLocked.Play();
  838.                 else
  839.                 {
  840.                     // XXX: should this be called "TwoPartCancelled"?
  841.                     float fSeconds = m_MenuTimer->GetSeconds();
  842.                     if( fSeconds > 10 ) {
  843.                         Message msg("SongUnchosen");
  844.                         msg.SetParam( "Player", input.pn );
  845.                         MESSAGEMAN->Broadcast( msg );
  846.                         // unset all steps
  847.                         FOREACH_ENUM( PlayerNumber , p )
  848.                             m_bStepsChosen[p] = false;
  849.                         m_SelectionState = SelectionState_SelectingSong;
  850.                     }
  851.                 }
  852.             }
  853.         }
  854.     }
  855.  
  856.     if( input.type == IET_FIRST_PRESS && DetectCodes(input) )
  857.         return true;
  858.  
  859.     return ScreenWithMenuElements::Input( input );
  860. }
  861.  
  862. bool ScreenSelectMusic::DetectCodes( const InputEventPlus &input )
  863. {
  864.     if( CodeDetector::EnteredPrevSteps(input.GameI.controller) && !CHANGE_STEPS_WITH_GAME_BUTTONS )
  865.     {
  866.         if( GAMESTATE->IsAnExtraStageAndSelectionLocked() )
  867.             m_soundLocked.Play();
  868.         else
  869.             ChangeSteps( input.pn, -1 );
  870.     }
  871.     else if( CodeDetector::EnteredNextSteps(input.GameI.controller) && !CHANGE_STEPS_WITH_GAME_BUTTONS )
  872.     {
  873.         if( GAMESTATE->IsAnExtraStageAndSelectionLocked() )
  874.             m_soundLocked.Play();
  875.         else
  876.             ChangeSteps( input.pn, +1 );
  877.     }
  878.     else if( CodeDetector::EnteredModeMenu(input.GameI.controller) )
  879.     {
  880.         if( MODE_MENU_AVAILABLE )
  881.             m_MusicWheel.ChangeSort( SORT_MODE_MENU );
  882.         else
  883.             m_soundLocked.Play();
  884.     }
  885.     else if( CodeDetector::EnteredNextSort(input.GameI.controller) )
  886.     {
  887.         if( GAMESTATE->IsAnExtraStageAndSelectionLocked() )
  888.             m_soundLocked.Play();
  889.         else
  890.             m_MusicWheel.NextSort();
  891.     }
  892.     else if( !GAMESTATE->IsAnExtraStageAndSelectionLocked() && CodeDetector::DetectAndAdjustMusicOptions(input.GameI.controller) )
  893.     {
  894.         m_soundOptionsChange.Play();
  895.  
  896.         Message msg( "PlayerOptionsChanged" );
  897.         msg.SetParam( "PlayerNumber", input.pn );
  898.         MESSAGEMAN->Broadcast( msg );
  899.  
  900.         MESSAGEMAN->Broadcast( "SongOptionsChanged" );
  901.     }
  902.     else if( CodeDetector::EnteredNextGroup(input.GameI.controller) && !CHANGE_GROUPS_WITH_GAME_BUTTONS )
  903.     {
  904.         if( GAMESTATE->IsAnExtraStageAndSelectionLocked() )
  905.             m_soundLocked.Play();
  906.         else
  907.         {
  908.             RString sNewGroup = m_MusicWheel.JumpToNextGroup();
  909.             m_MusicWheel.SelectSection(sNewGroup);
  910.             m_MusicWheel.SetOpenSection(sNewGroup);
  911.             MESSAGEMAN->Broadcast("NextGroup");
  912.             AfterMusicChange();
  913.         }
  914.     }
  915.     else if( CodeDetector::EnteredPrevGroup(input.GameI.controller) && !CHANGE_GROUPS_WITH_GAME_BUTTONS )
  916.     {
  917.         if( GAMESTATE->IsAnExtraStageAndSelectionLocked() )
  918.             m_soundLocked.Play();
  919.         else
  920.         {
  921.             RString sNewGroup = m_MusicWheel.JumpToPrevGroup();
  922.             m_MusicWheel.SelectSection(sNewGroup);
  923.             m_MusicWheel.SetOpenSection(sNewGroup);
  924.             MESSAGEMAN->Broadcast("PreviousGroup");
  925.             AfterMusicChange();
  926.         }
  927.     }
  928.     else if( CodeDetector::EnteredCloseFolder(input.GameI.controller) )
  929.     {
  930.         if( GAMESTATE->IsAnExtraStageAndSelectionLocked() )
  931.             m_soundLocked.Play();
  932.         else
  933.         {
  934.             RString sCurSection = m_MusicWheel.GetSelectedSection();
  935.             m_MusicWheel.SelectSection(sCurSection);
  936.             m_MusicWheel.SetOpenSection("");
  937.             AfterMusicChange();
  938.         }
  939.     }
  940.     else
  941.     {
  942.         return false;
  943.     }
  944.     return true;
  945. }
  946.  
  947. void ScreenSelectMusic::UpdateSelectButton( PlayerNumber pn, bool bSelectIsDown )
  948. {
  949.     if( !SELECT_MENU_AVAILABLE  ||  !CanChangeSong() )
  950.         bSelectIsDown = false;
  951.  
  952.     if( m_bSelectIsDown[pn] != bSelectIsDown )
  953.     {
  954.         m_bSelectIsDown[pn] = bSelectIsDown;
  955.         Message msg( bSelectIsDown ? "SelectMenuOpened" : "SelectMenuClosed" );
  956.         msg.SetParam( "Player", pn );
  957.         MESSAGEMAN->Broadcast( msg );
  958.     }
  959. }
  960.  
  961. void ScreenSelectMusic::ChangeSteps( PlayerNumber pn, int dir )
  962. {
  963.     LOG->Trace( "ScreenSelectMusic::ChangeSteps( %d, %d )", pn, dir );
  964.  
  965.     ASSERT( GAMESTATE->IsHumanPlayer(pn) );
  966.  
  967.     if( GAMESTATE->m_pCurSong )
  968.     {
  969.         m_iSelection[pn] += dir;
  970.         if( WRAP_CHANGE_STEPS )
  971.         {
  972.             wrap( m_iSelection[pn], m_vpSteps.size() );
  973.         }
  974.         else
  975.         {
  976.             if( CLAMP(m_iSelection[pn],0,m_vpSteps.size()-1) )
  977.                 return;
  978.         }
  979.  
  980.         // the user explicity switched difficulties. Update the preferred Difficulty and StepsType
  981.         Steps *pSteps = m_vpSteps[ m_iSelection[pn] ];
  982.         GAMESTATE->ChangePreferredDifficultyAndStepsType( pn, pSteps->GetDifficulty(), pSteps->m_StepsType );
  983.     }
  984.     else if( GAMESTATE->m_pCurCourse )
  985.     {
  986.         m_iSelection[pn] += dir;
  987.         if( WRAP_CHANGE_STEPS )
  988.         {
  989.             wrap( m_iSelection[pn], m_vpTrails.size() );
  990.         }
  991.         else
  992.         {
  993.             if( CLAMP(m_iSelection[pn],0,m_vpTrails.size()-1) )
  994.                 return;
  995.         }
  996.  
  997.         // the user explicity switched difficulties. Update the preferred Difficulty and StepsType
  998.         Trail *pTrail = m_vpTrails[ m_iSelection[pn] ];
  999.         GAMESTATE->ChangePreferredCourseDifficultyAndStepsType( pn, pTrail->m_CourseDifficulty, pTrail->m_StepsType );
  1000.     }
  1001.     else
  1002.     {
  1003.         // If we're showing multiple StepsTypes in the list, don't allow
  1004.         // changing the difficulty/StepsType when a non-Song, non-Course is
  1005.         // selected. Changing the preferred Difficulty and StepsType by
  1006.         // direction is complicated when multiple StepsTypes are being shown,
  1007.         // so we don't support it.
  1008.         if( CommonMetrics::AUTO_SET_STYLE )
  1009.             return;
  1010.         if( !GAMESTATE->ChangePreferredDifficulty( pn, dir ) )
  1011.             return;
  1012.     }
  1013.  
  1014.     vector<PlayerNumber> vpns;
  1015.     FOREACH_HumanPlayer( p )
  1016.     {
  1017.         if( pn == p || GAMESTATE->DifficultiesLocked() )
  1018.         {
  1019.             m_iSelection[p] = m_iSelection[pn];
  1020.             vpns.push_back( p );
  1021.         }
  1022.     }
  1023.     AfterStepsOrTrailChange( vpns );
  1024.  
  1025.     float fBalance = GameSoundManager::GetPlayerBalance( pn );
  1026.     if( dir < 0 )
  1027.     {
  1028.         m_soundDifficultyEasier.SetProperty( "Pan", fBalance );
  1029.         m_soundDifficultyEasier.PlayCopy();
  1030.     }
  1031.     else
  1032.     {
  1033.         m_soundDifficultyHarder.SetProperty( "Pan", fBalance );
  1034.         m_soundDifficultyHarder.PlayCopy();
  1035.     }
  1036.  
  1037.     Message msg( "ChangeSteps" );
  1038.     msg.SetParam( "Player", pn );
  1039.     msg.SetParam( "Direction", dir );
  1040.     MESSAGEMAN->Broadcast( msg );
  1041. }
  1042.  
  1043.  
  1044. void ScreenSelectMusic::HandleMessage( const Message &msg )
  1045. {
  1046.     if( m_bRunning && msg == Message_PlayerJoined )
  1047.     {
  1048.         PlayerNumber master_pn = GAMESTATE->GetMasterPlayerNumber();
  1049.         // The current steps may no longer be playable. If one player has double
  1050.         // steps selected, they are no longer playable now that P2 has joined.
  1051.  
  1052.         // TODO: Invalidate the CurSteps only if they are no longer playable.
  1053.         // That way, after music change will clamp to the nearest in the StepsDisplayList.
  1054.         GAMESTATE->m_pCurSteps[master_pn].SetWithoutBroadcast( NULL );
  1055.         FOREACH_ENUM( PlayerNumber, p )
  1056.             GAMESTATE->m_pCurSteps[p].SetWithoutBroadcast( NULL );
  1057.  
  1058.         /* If a course is selected, it may no longer be playable.
  1059.          * Let MusicWheel know about the late join. */
  1060.         m_MusicWheel.PlayerJoined();
  1061.  
  1062.         AfterMusicChange();
  1063.  
  1064.         int iSel = 0;
  1065.         PlayerNumber pn;
  1066.         bool b = msg.GetParam( "Player", pn );
  1067.         ASSERT( b );
  1068.  
  1069.         // load player profiles
  1070.         if( GAMESTATE->HaveProfileToLoad() )
  1071.         {
  1072.             GAMESTATE->LoadProfiles( true ); // I guess you could always load edits here...
  1073.             SCREENMAN->ZeroNextUpdate(); // be kind, don't skip frames if you can avoid it
  1074.         }
  1075.  
  1076.         m_iSelection[pn] = iSel;
  1077.         if( GAMESTATE->IsCourseMode() )
  1078.         {
  1079.             Trail* pTrail = m_vpTrails.empty()? NULL: m_vpTrails[m_iSelection[pn]];
  1080.             GAMESTATE->m_pCurTrail[pn].Set( pTrail );
  1081.         }
  1082.         else
  1083.         {
  1084.             Steps* pSteps = m_vpSteps.empty()? NULL: m_vpSteps[m_iSelection[pn]];
  1085.  
  1086.             // handle changing rave difficulty on join
  1087.             if(GAMESTATE->m_PlayMode == PLAY_MODE_RAVE)
  1088.                 pSteps = m_vpSteps[m_iSelection[master_pn]];
  1089.  
  1090.             GAMESTATE->m_pCurSteps[pn].Set( pSteps );
  1091.         }
  1092.     }
  1093.  
  1094.     ScreenWithMenuElements::HandleMessage( msg );
  1095. }
  1096.  
  1097. void ScreenSelectMusic::HandleScreenMessage( const ScreenMessage SM )
  1098. {
  1099.     if( SM == SM_AllowOptionsMenuRepeat )
  1100.     {
  1101.         m_bAllowOptionsMenuRepeat = true;
  1102.     }
  1103.     else if( SM == SM_MenuTimer )
  1104.     {
  1105.         if( m_MusicWheel.IsRouletting() )
  1106.         {
  1107.             MenuStart( InputEventPlus() );
  1108.             m_MenuTimer->SetSeconds( ROULETTE_TIMER_SECONDS );
  1109.             m_MenuTimer->Start();
  1110.         }
  1111.         else if( DO_ROULETTE_ON_MENU_TIMER  &&  m_MusicWheel.GetSelectedSong() == NULL  &&  m_MusicWheel.GetSelectedCourse() == NULL )
  1112.         {
  1113.             m_MusicWheel.StartRoulette();
  1114.             m_MenuTimer->SetSeconds( ROULETTE_TIMER_SECONDS );
  1115.             m_MenuTimer->Start();
  1116.         }
  1117.         else
  1118.         {
  1119.             // Finish sort changing so that the wheel can respond immediately to
  1120.             // our request to choose random.
  1121.             m_MusicWheel.FinishChangingSorts();
  1122.             if( m_MusicWheel.GetSelectedSong() == NULL && m_MusicWheel.GetSelectedCourse() == NULL )
  1123.                 m_MusicWheel.StartRandom();
  1124.  
  1125.             MenuStart( InputEventPlus() );
  1126.         }
  1127.         return;
  1128.     }
  1129.     else if( SM == SM_GoToPrevScreen )
  1130.     {
  1131.         /* We may have stray SM_SongChanged messages from the music wheel.
  1132.          * We can't handle them anymore, since the title menu (and attract
  1133.          * screens) reset the game state, so just discard them. */
  1134.         ClearMessageQueue();
  1135.     }
  1136.     else if( SM == SM_BeginFadingOut )
  1137.     {
  1138.         m_bAllowOptionsMenu = false;
  1139.         if( OPTIONS_MENU_AVAILABLE && !m_bGoToOptions )
  1140.             this->PlayCommand( "HidePressStartForOptions" );
  1141.  
  1142.         this->PostScreenMessage( SM_GoToNextScreen, this->GetTweenTimeLeft() );
  1143.     }
  1144.     else if( SM == SM_GoToNextScreen )
  1145.     {
  1146.         if( !m_bGoToOptions )
  1147.             SOUND->StopMusic();
  1148.     }
  1149.     else if( SM == SM_SongChanged )
  1150.     {
  1151.         AfterMusicChange();
  1152.     }
  1153.     else if( SM == SM_SortOrderChanging ) // happens immediately
  1154.     {
  1155.         this->PlayCommand( "SortChange" );
  1156.     }
  1157.     else if( SM == SM_GainFocus )
  1158.     {
  1159.         CodeDetector::RefreshCacheItems( CODES );
  1160.     }
  1161.     else if( SM == SM_LoseFocus )
  1162.     {
  1163.         CodeDetector::RefreshCacheItems(); // reset for other screens
  1164.     }
  1165.  
  1166.     ScreenWithMenuElements::HandleScreenMessage( SM );
  1167. }
  1168.  
  1169. bool ScreenSelectMusic::MenuStart( const InputEventPlus &input )
  1170. {
  1171.     if( input.type != IET_FIRST_PRESS )
  1172.         return false;
  1173.  
  1174.     /* If select is being pressed at the same time, this is probably an attempt
  1175.      * to change the sort, not to pick a song or difficulty. If it gets here,
  1176.      * the actual select press was probably hit during a tween and ignored.
  1177.      * Ignore it. */
  1178.     if( input.pn != PLAYER_INVALID && INPUTMAPPER->IsBeingPressed(GAME_BUTTON_SELECT, input.pn) )
  1179.         return false;
  1180.  
  1181.     // Honor locked input for start presses.
  1182.     if( m_fLockInputSecs > 0 )
  1183.         return false;
  1184.  
  1185.     switch( m_SelectionState )
  1186.     {
  1187.     DEFAULT_FAIL( m_SelectionState );
  1188.    
  1189.     case SelectionState_SelectingSong:
  1190.         // If false, we don't have a selection just yet.
  1191.         if( !m_MusicWheel.Select() )
  1192.             return false;
  1193.  
  1194.         // a song was selected
  1195.         if( m_MusicWheel.GetSelectedSong() != NULL )
  1196.         {
  1197.             if(TWO_PART_CONFIRMS_ONLY && SAMPLE_MUSIC_PREVIEW_MODE == SampleMusicPreviewMode_StartToPreview)
  1198.             {
  1199.                 // start playing the preview music.
  1200.                 g_bSampleMusicWaiting = true;
  1201.                 CheckBackgroundRequests( true );
  1202.             }
  1203.  
  1204.             const bool bIsNew = PROFILEMAN->IsSongNew( m_MusicWheel.GetSelectedSong() );
  1205.             bool bIsHard = false;
  1206.             FOREACH_HumanPlayer( p )
  1207.             {
  1208.                 if( GAMESTATE->m_pCurSteps[p]  &&  GAMESTATE->m_pCurSteps[p]->GetMeter() >= 10 )
  1209.                     bIsHard = true;
  1210.             }
  1211.  
  1212.             // See if this song is a repeat.
  1213.             // If we're in event mode, only check the last five songs.
  1214.             bool bIsRepeat = false;
  1215.             int i = 0;
  1216.             if( GAMESTATE->IsEventMode() )
  1217.                 i = max( 0, int(STATSMAN->m_vPlayedStageStats.size())-5 );
  1218.             for( ; i < (int)STATSMAN->m_vPlayedStageStats.size(); ++i )
  1219.                 if( STATSMAN->m_vPlayedStageStats[i].m_vpPlayedSongs.back() == m_MusicWheel.GetSelectedSong() )
  1220.                     bIsRepeat = true;
  1221.  
  1222.             // Don't complain about repeats if the user didn't get to pick.
  1223.             if( GAMESTATE->IsAnExtraStageAndSelectionLocked() )
  1224.                 bIsRepeat = false;
  1225.  
  1226.             if( bIsRepeat )
  1227.                 SOUND->PlayOnceFromAnnouncer( "select music comment repeat" );
  1228.             else if( bIsNew )
  1229.                 SOUND->PlayOnceFromAnnouncer( "select music comment new" );
  1230.             else if( bIsHard )
  1231.                 SOUND->PlayOnceFromAnnouncer( "select music comment hard" );
  1232.             else
  1233.                 SOUND->PlayOnceFromAnnouncer( "select music comment general" );
  1234.  
  1235.             /* If we're in event mode, we may have just played a course (putting
  1236.              * us in course mode). Make sure we're in a single song mode. */
  1237.             if( GAMESTATE->IsCourseMode() )
  1238.                 GAMESTATE->m_PlayMode.Set( PLAY_MODE_REGULAR );
  1239.         }
  1240.         else if( m_MusicWheel.GetSelectedCourse() != NULL )
  1241.         {
  1242.             SOUND->PlayOnceFromAnnouncer( "select course comment general" );
  1243.  
  1244.             Course *pCourse = m_MusicWheel.GetSelectedCourse();
  1245.             ASSERT( pCourse != NULL );
  1246.             GAMESTATE->m_PlayMode.Set( pCourse->GetPlayMode() );
  1247.  
  1248.             // apply #LIVES
  1249.             if( pCourse->m_iLives != -1 )
  1250.             {
  1251.                 SO_GROUP_ASSIGN( GAMESTATE->m_SongOptions, ModsLevel_Stage, m_LifeType, SongOptions::LIFE_BATTERY );
  1252.                 SO_GROUP_ASSIGN( GAMESTATE->m_SongOptions, ModsLevel_Stage, m_iBatteryLives, pCourse->m_iLives );
  1253.             }
  1254.             if( pCourse->GetCourseType() == COURSE_TYPE_SURVIVAL)
  1255.                 SO_GROUP_ASSIGN( GAMESTATE->m_SongOptions, ModsLevel_Stage, m_LifeType, SongOptions::LIFE_TIME );
  1256.         }
  1257.         else
  1258.         {
  1259.             // We haven't made a selection yet.
  1260.             return false;
  1261.         }
  1262.         // I believe this is for those who like pump pro. -aj
  1263.         MESSAGEMAN->Broadcast("SongChosen");
  1264.  
  1265.         break;
  1266.  
  1267.     case SelectionState_SelectingSteps:
  1268.         {
  1269.             PlayerNumber pn = input.pn;
  1270.             bool bInitiatedByMenuTimer = pn == PLAYER_INVALID;
  1271.             bool bAllOtherHumanPlayersDone = true;
  1272.             FOREACH_HumanPlayer( p )
  1273.             {
  1274.                 if( p == pn )
  1275.                     continue;
  1276.                 bAllOtherHumanPlayersDone &= m_bStepsChosen[p];
  1277.             }
  1278.  
  1279.             bool bAllPlayersDoneSelectingSteps = bInitiatedByMenuTimer || bAllOtherHumanPlayersDone;
  1280.             if(TWO_PART_CONFIRMS_ONLY)
  1281.                 bAllPlayersDoneSelectingSteps = true;
  1282.  
  1283.             /* TRICKY: if we have a Routine chart selected, we need to ensure
  1284.              * the following:
  1285.              * 1. Both players must select the same Routine steps.
  1286.              * 2. If the other player picks non-Routine steps, this player
  1287.              *    cannot pick Routine.
  1288.              * 3. If the other player picked Routine steps, and we pick
  1289.              *    non-Routine steps, the other player's steps must be unselected.
  1290.              * 4. If time runs out, and both players don't have the same Routine
  1291.              *    chart selected, we need to bump the player with a Routine
  1292.              *    chart selection to a playable chart.
  1293.              *    (Right now, we bump them to Beginner... Can we come up with
  1294.              *    something better?)
  1295.              */
  1296.  
  1297.             if( !GAMESTATE->IsCourseMode() && GAMESTATE->GetNumSidesJoined() == 2 )
  1298.             {
  1299.                 bool bSelectedRoutineSteps[NUM_PLAYERS], bAnySelectedRoutine = false;
  1300.                 bool bSelectedSameSteps = GAMESTATE->m_pCurSteps[PLAYER_1] == GAMESTATE->m_pCurSteps[PLAYER_2];
  1301.  
  1302.                 FOREACH_HumanPlayer( p )
  1303.                 {
  1304.                     const Steps *pSteps = GAMESTATE->m_pCurSteps[p];
  1305.                     const StepsTypeInfo &sti = GAMEMAN->GetStepsTypeInfo( pSteps->m_StepsType );
  1306.  
  1307.                     bSelectedRoutineSteps[p] = sti.m_StepsTypeCategory == StepsTypeCategory_Routine;
  1308.                     bAnySelectedRoutine |= bSelectedRoutineSteps[p];
  1309.                 }
  1310.  
  1311.                 if( bAnySelectedRoutine )
  1312.                 {
  1313.                     /* Timer ran out. If we haven't agreed on steps, move players with
  1314.                      * Routine steps down to Beginner. I'll admit that's annoying,
  1315.                      * but at least they won't lose more stages. */
  1316.                     if( bInitiatedByMenuTimer && !bSelectedSameSteps )
  1317.                     {
  1318.                         /* Since m_vpSteps is sorted by Difficulty, the first
  1319.                          * entry should be the easiest. */
  1320.                         ASSERT( m_vpSteps.size() != 0 );
  1321.                         Steps *pSteps = m_vpSteps[0];
  1322.  
  1323.                         FOREACH_PlayerNumber( p )
  1324.                         {
  1325.                             if( bSelectedRoutineSteps[p] )
  1326.                                 GAMESTATE->m_pCurSteps[p].Set( pSteps );
  1327.                         }
  1328.  
  1329.                         break;
  1330.                     }
  1331.  
  1332.                     // If the steps don't match up, we need to check some more conditions...
  1333.                     if( !bSelectedSameSteps )
  1334.                     {
  1335.                         const PlayerNumber other = OPPOSITE_PLAYER[pn];
  1336.  
  1337.                         if( m_bStepsChosen[other] )
  1338.                         {
  1339.                             /* Unready the other player if they selected Routine
  1340.                              * steps, but we didn't. */
  1341.                             if( bSelectedRoutineSteps[other] )
  1342.                             {
  1343.                                 m_bStepsChosen[other] = false;
  1344.                                 bAllPlayersDoneSelectingSteps = false;  // if the timer ran out, we handled it earlier
  1345.  
  1346.                                 // HACK: send an event to Input to tell it to unready.
  1347.                                 InputEventPlus event;
  1348.                                 event.MenuI = GAME_BUTTON_SELECT;
  1349.                                 event.pn = other;
  1350.  
  1351.                                 this->Input( event );
  1352.                             }
  1353.                             else if( bSelectedRoutineSteps[pn] )
  1354.                             {
  1355.                                 /* They selected non-Routine steps, so we can't
  1356.                                  * select Routine steps. */
  1357.                                 return false;
  1358.                             }
  1359.                         }
  1360.                     }
  1361.                 }
  1362.             }
  1363.  
  1364.             if( !bAllPlayersDoneSelectingSteps )
  1365.             {
  1366.                 m_bStepsChosen[pn] = true;
  1367.                 m_soundStart.Play();
  1368.  
  1369.                 // impldiff: Pump it Up Pro uses "StepsSelected". -aj
  1370.                 Message msg("StepsChosen");
  1371.                 msg.SetParam( "Player", pn );
  1372.                 MESSAGEMAN->Broadcast( msg );
  1373.                 return true;
  1374.             }
  1375.         }
  1376.         break;
  1377.     }
  1378.  
  1379.     FOREACH_ENUM( PlayerNumber, p )
  1380.     {
  1381.         if( !TWO_PART_SELECTION || m_SelectionState == SelectionState_SelectingSteps )
  1382.         {
  1383.             if( m_OptionsList[p].IsOpened() )
  1384.                 m_OptionsList[p].Close();
  1385.         }
  1386.         UpdateSelectButton( p, false );
  1387.     }
  1388.  
  1389.     m_SelectionState = GetNextSelectionState();
  1390.     Message msg( "Start" + SelectionStateToString(m_SelectionState) );
  1391.     MESSAGEMAN->Broadcast( msg );
  1392.  
  1393.     m_soundStart.Play();
  1394.  
  1395.     // If the MenuTimer has forced us to move on && TWO_PART_CONFIRMS_ONLY,
  1396.     // set Selection State to finalized and move on.
  1397.     if(TWO_PART_CONFIRMS_ONLY)
  1398.     {
  1399.         if(m_MenuTimer->GetSeconds() < 1)
  1400.         {
  1401.             m_SelectionState = SelectionState_Finalized;
  1402.         }
  1403.     }
  1404.  
  1405.     if( m_SelectionState == SelectionState_Finalized )
  1406.     {
  1407.         m_MenuTimer->Stop();
  1408.  
  1409.         FOREACH_HumanPlayer( p )
  1410.         {
  1411.             if( !m_bStepsChosen[p] )
  1412.             {
  1413.                 m_bStepsChosen[p] = true;
  1414.                 // Don't play start sound. We play it again below on finalized
  1415.                 //m_soundStart.Play();
  1416.  
  1417.                 Message lMsg("StepsChosen");
  1418.                 lMsg.SetParam( "Player", p );
  1419.                 MESSAGEMAN->Broadcast( lMsg );
  1420.             }
  1421.         }
  1422.  
  1423.         if( CommonMetrics::AUTO_SET_STYLE )
  1424.         {
  1425.             // Now that Steps have been chosen, set a Style that can play them.
  1426.             const Style *pStyle = NULL;
  1427.             if( GAMESTATE->IsCourseMode() )
  1428.                 pStyle = GAMESTATE->m_pCurCourse->GetCourseStyle( GAMESTATE->m_pCurGame, GAMESTATE->GetNumSidesJoined() );
  1429.             if( pStyle == NULL )
  1430.             {
  1431.                 StepsType stCurrent;
  1432.                 PlayerNumber pn = GAMESTATE->GetMasterPlayerNumber();
  1433.                 if( GAMESTATE->IsCourseMode() )
  1434.                 {
  1435.                     ASSERT( GAMESTATE->m_pCurTrail[pn] != NULL );
  1436.                     stCurrent = GAMESTATE->m_pCurTrail[pn]->m_StepsType;
  1437.                 }
  1438.                 else
  1439.                 {
  1440.                     ASSERT( GAMESTATE->m_pCurSteps[pn] != NULL );
  1441.                     stCurrent = GAMESTATE->m_pCurSteps[pn]->m_StepsType;
  1442.                 }
  1443.                 vector<StepsType> vst;
  1444.                 pStyle = GAMEMAN->GetFirstCompatibleStyle( GAMESTATE->m_pCurGame, GAMESTATE->GetNumSidesJoined(), stCurrent );
  1445.             }
  1446.             GAMESTATE->SetCurrentStyle( pStyle );
  1447.         }
  1448.  
  1449.         /* If we're currently waiting on song assets, abort all except the music
  1450.          * and start the music, so if we make a choice quickly before background
  1451.          * requests come through, the music will still start. */
  1452.         g_bCDTitleWaiting = g_bBannerWaiting = false;
  1453.         m_BackgroundLoader.Abort();
  1454.         CheckBackgroundRequests( true );
  1455.  
  1456.         if( OPTIONS_MENU_AVAILABLE )
  1457.         {
  1458.             // show "hold START for options"
  1459.             this->PlayCommand( "ShowPressStartForOptions" );
  1460.  
  1461.             m_bAllowOptionsMenu = true;
  1462.  
  1463.             /* Don't accept a held START for a little while, so it's not
  1464.              * hit accidentally.  Accept an initial START right away, though,
  1465.              * so we don't ignore deliberate fast presses (which would be
  1466.              * annoying). */
  1467.             this->PostScreenMessage( SM_AllowOptionsMenuRepeat, 0.5f );
  1468.  
  1469.             StartTransitioningScreen( SM_None );
  1470.             float fTime = max( SHOW_OPTIONS_MESSAGE_SECONDS, this->GetTweenTimeLeft() );
  1471.             this->PostScreenMessage( SM_BeginFadingOut, fTime );
  1472.         }
  1473.         else
  1474.         {
  1475.             StartTransitioningScreen( SM_BeginFadingOut );
  1476.         }
  1477.     }
  1478.     else // !finalized.  Set the timer for selecting difficulty and mods.
  1479.     {
  1480.         float fSeconds = m_MenuTimer->GetSeconds();
  1481.         if( fSeconds < 10 )
  1482.         {
  1483.             m_MenuTimer->SetSeconds( TWO_PART_TIMER_SECONDS ); // was 13 -aj
  1484.             m_MenuTimer->Start();
  1485.         }
  1486.     }
  1487.     return true;
  1488. }
  1489.  
  1490.  
  1491. bool ScreenSelectMusic::MenuBack( const InputEventPlus & /* input */ )
  1492. {
  1493.     // Handle unselect song (ffff)
  1494.     // todo: this isn't right at all. -aj
  1495.     /*
  1496.     if( m_SelectionState == SelectionState_SelectingSteps &&
  1497.         !m_bStepsChosen[input.pn] && input.MenuI == GAME_BUTTON_BACK &&
  1498.         input.type == IET_FIRST_PRESS )
  1499.     {
  1500.         // if a player has chosen their steps already, don't unchoose song.
  1501.         FOREACH_HumanPlayer( p )
  1502.             if( m_bStepsChosen[p] ) return;
  1503.  
  1504.         // and if we get here...
  1505.         Message msg("SongUnchosen");
  1506.         msg.SetParam( "Player", input.pn );
  1507.         MESSAGEMAN->Broadcast( msg );
  1508.         m_SelectionState = SelectionState_SelectingSong;
  1509.         return true;
  1510.     }
  1511.     */
  1512.  
  1513.     m_BackgroundLoader.Abort();
  1514.  
  1515.     Cancel( SM_GoToPrevScreen );
  1516.     return true;
  1517. }
  1518.  
  1519. void ScreenSelectMusic::AfterStepsOrTrailChange( const vector<PlayerNumber> &vpns )
  1520. {
  1521.     if(TWO_PART_CONFIRMS_ONLY && m_SelectionState == SelectionState_SelectingSteps)
  1522.     {
  1523.         // if TWO_PART_CONFIRMS_ONLY, changing difficulties unsets the song. -aj
  1524.         m_SelectionState = SelectionState_SelectingSong;
  1525.         MESSAGEMAN->Broadcast("TwoPartConfirmCanceled");
  1526.     }
  1527.  
  1528.     FOREACH_CONST( PlayerNumber, vpns, p )
  1529.     {
  1530.         PlayerNumber pn = *p;
  1531.         ASSERT( GAMESTATE->IsHumanPlayer(pn) );
  1532.  
  1533.         if( GAMESTATE->m_pCurSong )
  1534.         {
  1535.             CLAMP( m_iSelection[pn], 0, m_vpSteps.size()-1 );
  1536.  
  1537.             Song* pSong = GAMESTATE->m_pCurSong;
  1538.             Steps* pSteps = m_vpSteps.empty()? NULL: m_vpSteps[m_iSelection[pn]];
  1539.  
  1540.             GAMESTATE->m_pCurSteps[pn].Set( pSteps );
  1541.             GAMESTATE->m_pCurTrail[pn].Set( NULL );
  1542.  
  1543.             int iScore = 0;
  1544.             if( pSteps )
  1545.             {
  1546.                 const Profile *pProfile = PROFILEMAN->IsPersistentProfile(pn) ? PROFILEMAN->GetProfile(pn) : PROFILEMAN->GetMachineProfile();
  1547.                 iScore = pProfile->GetStepsHighScoreList(pSong,pSteps).GetTopScore().GetScore();
  1548.             }
  1549.  
  1550.             m_textHighScore[pn].SetText( ssprintf("%*i", NUM_SCORE_DIGITS, iScore) );
  1551.         }
  1552.         else if( GAMESTATE->m_pCurCourse )
  1553.         {
  1554.             CLAMP( m_iSelection[pn], 0, m_vpTrails.size()-1 );
  1555.  
  1556.             Course* pCourse = GAMESTATE->m_pCurCourse;
  1557.             Trail* pTrail = m_vpTrails.empty()? NULL: m_vpTrails[m_iSelection[pn]];
  1558.  
  1559.             GAMESTATE->m_pCurSteps[pn].Set( NULL );
  1560.             GAMESTATE->m_pCurTrail[pn].Set( pTrail );
  1561.  
  1562.             int iScore = 0;
  1563.             if( pTrail )
  1564.             {
  1565.                 const Profile *pProfile = PROFILEMAN->IsPersistentProfile(pn) ? PROFILEMAN->GetProfile(pn) : PROFILEMAN->GetMachineProfile();
  1566.                 iScore = pProfile->GetCourseHighScoreList(pCourse,pTrail).GetTopScore().GetScore();
  1567.             }
  1568.  
  1569.             m_textHighScore[pn].SetText( ssprintf("%*i", NUM_SCORE_DIGITS, iScore) );
  1570.         }
  1571.         else
  1572.         {
  1573.             // The numbers shouldn't stay if the current selection is NULL.
  1574.             m_textHighScore[pn].SetText( NULL_SCORE_STRING );
  1575.         }
  1576.     }
  1577. }
  1578.  
  1579. void ScreenSelectMusic::SwitchToPreferredDifficulty()
  1580. {
  1581.     if( !GAMESTATE->m_pCurCourse )
  1582.     {
  1583.         FOREACH_HumanPlayer( pn )
  1584.         {
  1585.             // Find the closest match to the user's preferred difficulty and StepsType.
  1586.             int iCurDifference = -1;
  1587.             int &iSelection = m_iSelection[pn];
  1588.             FOREACH_CONST( Steps*, m_vpSteps, s )
  1589.             {
  1590.                 int i = s - m_vpSteps.begin();
  1591.  
  1592.                 // If the current steps are listed, use them.
  1593.                 if( GAMESTATE->m_pCurSteps[pn] == *s )
  1594.                 {
  1595.                     iSelection = i;
  1596.                     break;
  1597.                 }
  1598.  
  1599.                 if( GAMESTATE->m_PreferredDifficulty[pn] != Difficulty_Invalid  )
  1600.                 {
  1601.                     int iDifficultyDifference = abs( (*s)->GetDifficulty() - GAMESTATE->m_PreferredDifficulty[pn] );
  1602.                     int iStepsTypeDifference = 0;
  1603.                     if( GAMESTATE->m_PreferredStepsType != StepsType_Invalid )
  1604.                         iStepsTypeDifference = abs( (*s)->m_StepsType - GAMESTATE->m_PreferredStepsType );
  1605.                     int iTotalDifference = iStepsTypeDifference * NUM_Difficulty + iDifficultyDifference;
  1606.  
  1607.                     if( iCurDifference == -1 || iTotalDifference < iCurDifference )
  1608.                     {
  1609.                         iSelection = i;
  1610.                         iCurDifference = iTotalDifference;
  1611.                     }
  1612.                 }
  1613.             }
  1614.  
  1615.             CLAMP( iSelection, 0, m_vpSteps.size()-1 );
  1616.         }
  1617.     }
  1618.     else
  1619.     {
  1620.         FOREACH_HumanPlayer( pn )
  1621.         {
  1622.             // Find the closest match to the user's preferred difficulty.
  1623.             int iCurDifference = -1;
  1624.             int &iSelection = m_iSelection[pn];
  1625.             FOREACH_CONST( Trail*, m_vpTrails, t )
  1626.             {
  1627.                 int i = t - m_vpTrails.begin();
  1628.  
  1629.                 // If the current trail is listed, use it.
  1630.                 if( GAMESTATE->m_pCurTrail[pn] == m_vpTrails[i] )
  1631.                 {
  1632.                     iSelection = i;
  1633.                     break;
  1634.                 }
  1635.  
  1636.                 if( GAMESTATE->m_PreferredCourseDifficulty[pn] != Difficulty_Invalid  &&  GAMESTATE->m_PreferredStepsType != StepsType_Invalid  )
  1637.                 {
  1638.                     int iDifficultyDifference = abs( (*t)->m_CourseDifficulty - GAMESTATE->m_PreferredCourseDifficulty[pn] );
  1639.                     int iStepsTypeDifference = abs( (*t)->m_StepsType - GAMESTATE->m_PreferredStepsType );
  1640.                     int iTotalDifference = iStepsTypeDifference * NUM_CourseDifficulty + iDifficultyDifference;
  1641.  
  1642.                     if( iCurDifference == -1 || iTotalDifference < iCurDifference )
  1643.                     {
  1644.                         iSelection = i;
  1645.                         iCurDifference = iTotalDifference;
  1646.                     }
  1647.                 }
  1648.             }
  1649.  
  1650.             CLAMP( iSelection, 0, m_vpTrails.size()-1 );
  1651.         }
  1652.     }
  1653.  
  1654.     if( GAMESTATE->DifficultiesLocked() )
  1655.     {
  1656.         FOREACH_HumanPlayer( p )
  1657.             m_iSelection[p] = m_iSelection[GAMESTATE->GetMasterPlayerNumber()];
  1658.     }
  1659. }
  1660.  
  1661. void ScreenSelectMusic::AfterMusicChange()
  1662. {
  1663.     if( !m_MusicWheel.IsRouletting() )
  1664.         m_MenuTimer->Stall();
  1665.  
  1666.     Song* pSong = m_MusicWheel.GetSelectedSong();
  1667.     GAMESTATE->m_pCurSong.Set( pSong );
  1668.     if( pSong )
  1669.         GAMESTATE->m_pPreferredSong = pSong;
  1670.  
  1671.     Course* pCourse = m_MusicWheel.GetSelectedCourse();
  1672.     GAMESTATE->m_pCurCourse.Set( pCourse );
  1673.     if( pCourse )
  1674.         GAMESTATE->m_pPreferredCourse = pCourse;
  1675.  
  1676.     m_vpSteps.clear();
  1677.     m_vpTrails.clear();
  1678.  
  1679.     m_Banner.SetMovingFast( !!m_MusicWheel.IsMoving() );
  1680.  
  1681.     vector<RString> m_Artists, m_AltArtists;
  1682.  
  1683.     if( SAMPLE_MUSIC_PREVIEW_MODE != SampleMusicPreviewMode_LastSong )
  1684.     {
  1685.         m_sSampleMusicToPlay = "";
  1686.     }
  1687.     m_pSampleMusicTimingData = NULL;
  1688.     g_sCDTitlePath = "";
  1689.     g_sBannerPath = "";
  1690.     g_bWantFallbackCdTitle = false;
  1691.     bool bWantBanner = true;
  1692.  
  1693.     static SortOrder s_lastSortOrder = SortOrder_Invalid;
  1694.     if( GAMESTATE->m_SortOrder != s_lastSortOrder )
  1695.     {
  1696.         // Reload to let Lua metrics have a chance to change the help text.
  1697.         s_lastSortOrder = GAMESTATE->m_SortOrder;
  1698.     }
  1699.  
  1700.     WheelItemDataType wtype = m_MusicWheel.GetSelectedType();
  1701.     SampleMusicPreviewMode pmode;
  1702.     switch( wtype )
  1703.     {
  1704.     case WheelItemDataType_Section:
  1705.     case WheelItemDataType_Sort:
  1706.     case WheelItemDataType_Roulette:
  1707.     case WheelItemDataType_Random:
  1708.     case WheelItemDataType_Custom:
  1709.         FOREACH_PlayerNumber( p )
  1710.             m_iSelection[p] = -1;
  1711.  
  1712.         g_sCDTitlePath = ""; // none
  1713.  
  1714.         if( SAMPLE_MUSIC_PREVIEW_MODE == SampleMusicPreviewMode_LastSong )
  1715.         {
  1716.             // HACK: Make random music work in LastSong mode. -aj
  1717.             if( m_sSampleMusicToPlay == m_sRandomMusicPath )
  1718.             {
  1719.                 m_fSampleStartSeconds = 0;
  1720.                 m_fSampleLengthSeconds = -1;
  1721.             }
  1722.         }
  1723.         else
  1724.         {
  1725.             m_fSampleStartSeconds = 0;
  1726.             m_fSampleLengthSeconds = -1;
  1727.         }
  1728.  
  1729.         switch( wtype )
  1730.         {
  1731.             case WheelItemDataType_Section:
  1732.                 // reduce scope
  1733.                 {
  1734.                     SortOrder curSort = GAMESTATE->m_SortOrder;
  1735.                     if( curSort == SORT_GROUP)
  1736.                     {
  1737.                         g_sBannerPath = SONGMAN->GetSongGroupBannerPath( m_MusicWheel.GetSelectedSection() );
  1738.                     }
  1739.                     else
  1740.                     {
  1741.                         bWantBanner = false; // we load it ourself
  1742.                         m_Banner.LoadFromSortOrder(curSort);
  1743.                     }
  1744.  
  1745.                     if( SAMPLE_MUSIC_PREVIEW_MODE != SampleMusicPreviewMode_LastSong )
  1746.                         m_sSampleMusicToPlay = m_sSectionMusicPath;
  1747.                 }
  1748.                 break;
  1749.             case WheelItemDataType_Sort:
  1750.                 bWantBanner = false; // we load it ourself
  1751.                 m_Banner.LoadMode();
  1752.                 if( SAMPLE_MUSIC_PREVIEW_MODE != SampleMusicPreviewMode_LastSong )
  1753.                     m_sSampleMusicToPlay = m_sSortMusicPath;
  1754.                 break;
  1755.             case WheelItemDataType_Roulette:
  1756.                 bWantBanner = false; // we load it ourself
  1757.                 m_Banner.LoadRoulette();
  1758.                 if( SAMPLE_MUSIC_PREVIEW_MODE != SampleMusicPreviewMode_LastSong )
  1759.                     m_sSampleMusicToPlay = m_sRouletteMusicPath;
  1760.                 break;
  1761.             case WheelItemDataType_Random:
  1762.                 bWantBanner = false; // we load it ourself
  1763.                 m_Banner.LoadRandom();
  1764.                 //if( SAMPLE_MUSIC_PREVIEW_MODE != SampleMusicPreviewMode_LastSong )
  1765.                 m_sSampleMusicToPlay = m_sRandomMusicPath;
  1766.                 break;
  1767.             case WheelItemDataType_Custom:
  1768.                 {
  1769.                     bWantBanner = false; // we load it ourself
  1770.                     RString sBannerName = GetMusicWheel()->GetCurWheelItemData( GetMusicWheel()->GetCurrentIndex() )->m_pAction->m_sName.c_str();
  1771.                     m_Banner.LoadCustom(sBannerName);
  1772.                     if( SAMPLE_MUSIC_PREVIEW_MODE != SampleMusicPreviewMode_LastSong )
  1773.                         m_sSampleMusicToPlay = m_sSectionMusicPath;
  1774.                 }
  1775.                 break;
  1776.             default:
  1777.                 FAIL_M(ssprintf("Invalid WheelItemDataType: %i", wtype));
  1778.         }
  1779.         // override this if the sample music mode wants to.
  1780.         /*
  1781.         if(SAMPLE_MUSIC_PREVIEW_MODE == SampleMusicPreviewMode_LastSong)
  1782.         {
  1783.             m_sSampleMusicToPlay = pSong->GetMusicPath();
  1784.             m_pSampleMusicTimingData = &pSong->m_SongTiming;
  1785.             m_fSampleStartSeconds = pSong->m_fMusicSampleStartSeconds;
  1786.             m_fSampleLengthSeconds = pSong->m_fMusicSampleLengthSeconds;
  1787.         }
  1788.         */
  1789.         break;
  1790.     case WheelItemDataType_Song:
  1791.     case WheelItemDataType_Portal:
  1792.         // check SampleMusicPreviewMode here.
  1793.         pmode = SAMPLE_MUSIC_PREVIEW_MODE;
  1794.         switch( pmode )
  1795.         {
  1796.             case SampleMusicPreviewMode_ScreenMusic:
  1797.                 // play the screen music
  1798.                 m_sSampleMusicToPlay = m_sLoopMusicPath;
  1799.                 m_fSampleStartSeconds = 0;
  1800.                 m_fSampleLengthSeconds = -1;
  1801.                 break;
  1802.             case SampleMusicPreviewMode_StartToPreview:
  1803.                 // we want to load the sample music, but we don't want to
  1804.                 // actually play it. fall through. -aj
  1805.             case SampleMusicPreviewMode_Normal:
  1806.             case SampleMusicPreviewMode_LastSong: // fall through
  1807.                 // play the sample music
  1808.                 m_sSampleMusicToPlay = pSong->GetMusicPath();
  1809.                 m_pSampleMusicTimingData = &pSong->m_SongTiming;
  1810.                 m_fSampleStartSeconds = pSong->m_fMusicSampleStartSeconds;
  1811.                 m_fSampleLengthSeconds = pSong->m_fMusicSampleLengthSeconds;
  1812.                 break;
  1813.             default:
  1814.                 FAIL_M(ssprintf("Invalid preview mode: %i", pmode));
  1815.         }
  1816.  
  1817.         SongUtil::GetPlayableSteps( pSong, m_vpSteps );
  1818.  
  1819.         if ( PREFSMAN->m_bShowBanners )
  1820.             g_sBannerPath = pSong->GetBannerPath();
  1821.  
  1822.         g_sCDTitlePath = pSong->GetCDTitlePath();
  1823.         g_bWantFallbackCdTitle = true;
  1824.  
  1825.         SwitchToPreferredDifficulty();
  1826.         break;
  1827.  
  1828.     case WheelItemDataType_Course:
  1829.     {
  1830.         const Course *lCourse = m_MusicWheel.GetSelectedCourse();
  1831.         const Style *pStyle = NULL;
  1832.         if( CommonMetrics::AUTO_SET_STYLE )
  1833.             pStyle = pCourse->GetCourseStyle( GAMESTATE->m_pCurGame, GAMESTATE->GetNumSidesJoined() );
  1834.         if( pStyle == NULL )
  1835.             pStyle = GAMESTATE->GetCurrentStyle();
  1836.         lCourse->GetTrails( m_vpTrails, pStyle->m_StepsType );
  1837.  
  1838.         m_sSampleMusicToPlay = m_sCourseMusicPath;
  1839.         m_fSampleStartSeconds = 0;
  1840.         m_fSampleLengthSeconds = -1;
  1841.  
  1842.         g_sBannerPath = lCourse->GetBannerPath();
  1843.         if( g_sBannerPath.empty() )
  1844.             m_Banner.LoadFallback();
  1845.  
  1846.         SwitchToPreferredDifficulty();
  1847.         break;
  1848.     }
  1849.     default:
  1850.         FAIL_M(ssprintf("Invalid WheelItemDataType: %i", wtype));
  1851.     }
  1852.  
  1853.     m_sprCDTitleFront.UnloadTexture();
  1854.     m_sprCDTitleBack.UnloadTexture();
  1855.  
  1856.     // Cancel any previous, incomplete requests for song assets,
  1857.     // since we need new ones.
  1858.     m_BackgroundLoader.Abort();
  1859.  
  1860.     g_bCDTitleWaiting = false;
  1861.     if( !g_sCDTitlePath.empty() || g_bWantFallbackCdTitle )
  1862.     {
  1863.         LOG->Trace( "cache \"%s\"", g_sCDTitlePath.c_str());
  1864.         m_BackgroundLoader.CacheFile( g_sCDTitlePath ); // empty OK
  1865.         g_bCDTitleWaiting = true;
  1866.     }
  1867.  
  1868.     g_bBannerWaiting = false;
  1869.     if( bWantBanner )
  1870.     {
  1871.         LOG->Trace("LoadFromCachedBanner(%s)",g_sBannerPath .c_str());
  1872.         if( m_Banner.LoadFromCachedBanner( g_sBannerPath ) )
  1873.         {
  1874.             /* If the high-res banner is already loaded, just delay before
  1875.              * loading it, so the low-res one has time to fade in. */
  1876.             if( !TEXTUREMAN->IsTextureRegistered( Sprite::SongBannerTexture(g_sBannerPath) ) )
  1877.                 m_BackgroundLoader.CacheFile( g_sBannerPath );
  1878.  
  1879.             g_bBannerWaiting = true;
  1880.         }
  1881.     }
  1882.  
  1883.     // Don't stop music if it's already playing the right file.
  1884.     g_bSampleMusicWaiting = false;
  1885.     if( !m_MusicWheel.IsRouletting() && SOUND->GetMusicPath() != m_sSampleMusicToPlay )
  1886.     {
  1887.         SOUND->StopMusic();
  1888.         // some SampleMusicPreviewModes don't want the sample music immediately.
  1889.         if( SAMPLE_MUSIC_PREVIEW_MODE != SampleMusicPreviewMode_StartToPreview )
  1890.         {
  1891.             if( !m_sSampleMusicToPlay.empty() )
  1892.                 g_bSampleMusicWaiting = true;
  1893.         }
  1894.     }
  1895.  
  1896.     g_StartedLoadingAt.Touch();
  1897.  
  1898.     vector<PlayerNumber> vpns;
  1899.     FOREACH_HumanPlayer( p )
  1900.         vpns.push_back( p );
  1901.  
  1902.     AfterStepsOrTrailChange( vpns );
  1903. }
  1904.  
  1905. void ScreenSelectMusic::OpenOptionsList(PlayerNumber pn)
  1906. {
  1907.     if( pn != PLAYER_INVALID )
  1908.     {
  1909.         m_MusicWheel.Move( 0 );
  1910.         m_OptionsList[pn].Open();
  1911.     }
  1912. }
  1913.  
  1914. // lua start
  1915. #include "LuaBinding.h"
  1916.  
  1917. /** @brief Allow Lua to have access to the ScreenSelectMusic. */
  1918. class LunaScreenSelectMusic: public Luna<ScreenSelectMusic>
  1919. {
  1920. public:
  1921.     static int GetGoToOptions( T* p, lua_State *L ) { lua_pushboolean( L, p->GetGoToOptions() ); return 1; }
  1922.     static int GetMusicWheel( T* p, lua_State *L ) {
  1923.         p->GetMusicWheel()->PushSelf(L);
  1924.         return 1;
  1925.     }
  1926.     static int OpenOptionsList( T* p, lua_State *L ) { PlayerNumber pn = Enum::Check<PlayerNumber>(L, 1);  p->OpenOptionsList(pn); return 0; }
  1927.  
  1928.     LunaScreenSelectMusic()
  1929.     {
  1930.         ADD_METHOD( GetGoToOptions );
  1931.         ADD_METHOD( GetMusicWheel );
  1932.         ADD_METHOD( OpenOptionsList );
  1933.     }
  1934. };
  1935.  
  1936. LUA_REGISTER_DERIVED_CLASS( ScreenSelectMusic, ScreenWithMenuElements )
  1937. // lua end
  1938.  
  1939. /*
  1940.  * (c) 2001-2004 Chris Danford
  1941.  * All rights reserved.
  1942.  *
  1943.  * Permission is hereby granted, free of charge, to any person obtaining a
  1944.  * copy of this software and associated documentation files (the
  1945.  * "Software"), to deal in the Software without restriction, including
  1946.  * without limitation the rights to use, copy, modify, merge, publish,
  1947.  * distribute, and/or sell copies of the Software, and to permit persons to
  1948.  * whom the Software is furnished to do so, provided that the above
  1949.  * copyright notice(s) and this permission notice appear in all copies of
  1950.  * the Software and that both the above copyright notice(s) and this
  1951.  * permission notice appear in supporting documentation.
  1952.  *
  1953.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  1954.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  1955.  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
  1956.  * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
  1957.  * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
  1958.  * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
  1959.  * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  1960.  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  1961.  * PERFORMANCE OF THIS SOFTWARE.
  1962.  */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement