2003-02-16 04:01:45 +00:00
#include "global.h"
2002-01-16 10:01:32 +00:00
/*
-----------------------------------------------------------------------------
2003-02-10 05:30:12 +00:00
Class: MusicWheelItem
2002-01-16 10:01:32 +00:00
2002-05-01 19:14:55 +00:00
Desc: See header.
2002-01-16 10:01:32 +00:00
2003-02-03 04:50:37 +00:00
Copyright (c) 2001-2003 by the person(s) listed below. All rights reserved.
2002-05-01 19:14:55 +00:00
Chris Danford
2003-02-03 04:50:37 +00:00
Chris Gomez
2003-02-10 05:30:12 +00:00
Glenn Maynard
2002-01-16 10:01:32 +00:00
-----------------------------------------------------------------------------
*/
#include "MusicWheel.h"
#include "RageUtil.h"
2002-02-28 19:40:40 +00:00
#include "SongManager.h"
2002-03-19 07:09:49 +00:00
#include "GameManager.h"
2002-07-23 01:41:40 +00:00
#include "PrefsManager.h"
2002-05-19 01:59:48 +00:00
#include "ScreenManager.h" // for sending SM_PlayMusicSample
2002-05-01 19:14:55 +00:00
#include "RageLog.h"
#include "GameConstantsAndTypes.h"
2002-07-23 01:41:40 +00:00
#include "GameState.h"
2003-07-04 18:03:20 +00:00
#include "RageMath.h"
2002-11-11 04:53:31 +00:00
#include <math.h>
#include "ThemeManager.h"
2003-04-03 21:29:14 +00:00
#include "song.h"
2003-03-31 23:06:15 +00:00
#include "Course.h"
2003-04-02 04:41:49 +00:00
#include "RageDisplay.h"
2003-04-19 18:51:13 +00:00
#include "RageTextureManager.h"
2003-04-19 22:22:31 +00:00
#include "Banner.h"
2003-06-27 08:06:22 +00:00
#include "Notes.h"
2003-07-07 22:21:31 +00:00
#include "UnlockSystem.h"
2003-07-20 08:54:31 +00:00
#include "ModeChoice.h"
2002-01-20 08:59:38 +00:00
2002-09-03 06:33:08 +00:00
2002-08-13 23:26:46 +00:00
#define FADE_SECONDS THEME->GetMetricF("MusicWheel","FadeSeconds")
#define SWITCH_SECONDS THEME->GetMetricF("MusicWheel","SwitchSeconds")
#define ROULETTE_SWITCH_SECONDS THEME->GetMetricF("MusicWheel","RouletteSwitchSeconds")
#define ROULETTE_SLOW_DOWN_SWITCHES THEME->GetMetricI("MusicWheel","RouletteSlowDownSwitches")
#define LOCKED_INITIAL_VELOCITY THEME->GetMetricF("MusicWheel","LockedInitialVelocity")
#define SCROLL_BAR_X THEME->GetMetricF("MusicWheel","ScrollBarX")
2002-08-26 05:53:48 +00:00
#define SCROLL_BAR_HEIGHT THEME->GetMetricI("MusicWheel","ScrollBarHeight")
2003-03-26 19:15:38 +00:00
CachedThemeMetricF ITEM_CURVE_X ( "MusicWheel" , "ItemCurveX" );
CachedThemeMetricF ITEM_SPACING_Y ( "MusicWheel" , "ItemSpacingY" );
2002-09-03 06:33:08 +00:00
#define NUM_SECTION_COLORS THEME->GetMetricI("MusicWheel","NumSectionColors")
#define SECTION_COLORS( i ) THEME->GetMetricC("MusicWheel",ssprintf("SectionColor%d",i+1))
2003-02-10 05:30:12 +00:00
#define DEFAULT_SCROLL_DIRECTION THEME->GetMetricI("Notes","DefaultScrollDirection")
2003-02-12 20:55:51 +00:00
#define SONG_REAL_EXTRA_COLOR THEME->GetMetricC("MusicWheel","SongRealExtraColor")
2003-03-13 23:58:30 +00:00
#define SHOW_ROULETTE THEME->GetMetricB("MusicWheel","ShowRoulette")
#define SHOW_RANDOM THEME->GetMetricB("MusicWheel","ShowRandom")
2003-04-02 04:41:49 +00:00
CachedThemeMetricB USE_3D ( "MusicWheel" , "Use3D" );
2003-06-30 00:34:18 +00:00
CachedThemeMetricI NUM_WHEEL_ITEMS_METRIC ( "MusicWheel" , "NumWheelItems" );
#define NUM_WHEEL_ITEMS min( MAX_WHEEL_ITEMS, (int) NUM_WHEEL_ITEMS_METRIC )
2003-07-20 08:54:31 +00:00
#define MENU_NAMES THEME->GetMetric ("MusicWheel","MenuNames")
#define MENU_ACTIONS THEME->GetMetric ("MusicWheel","MenuActions")
2002-09-03 06:33:08 +00:00
2003-07-20 08:54:31 +00:00
2003-01-21 07:04:53 +00:00
const int MAX_WHEEL_SOUND_SPEED = 15 ;
2002-01-16 10:01:32 +00:00
2003-02-17 20:38:57 +00:00
2003-06-30 07:09:13 +00:00
static const SongSortOrder SortOrder [] =
{
SORT_GROUP ,
SORT_TITLE ,
SORT_BPM ,
SORT_MOST_PLAYED ,
SORT_ARTIST ,
SORT_INVALID
};
2003-05-17 23:04:14 +00:00
2002-01-16 10:01:32 +00:00
MusicWheel :: MusicWheel ()
{
2002-07-31 19:40:40 +00:00
LOG -> Trace ( "MusicWheel::MusicWheel()" );
2003-01-27 07:25:29 +00:00
if ( GAMESTATE -> m_pCurSong != NULL )
2003-04-25 00:27:30 +00:00
LOG -> Trace ( "Current Song: %s" , GAMESTATE -> m_pCurSong -> GetSongDir (). c_str () );
2003-01-27 07:25:29 +00:00
else
LOG -> Trace ( "Current Song: NULL" );
2002-09-03 06:33:08 +00:00
2003-01-01 17:20:36 +00:00
if ( DEFAULT_SCROLL_DIRECTION && GAMESTATE -> m_pCurSong == NULL ) /* check the song is null... incase they have just come back from a song and changed their PlayerOptions */
{
for ( int i = 0 ; i < NUM_PLAYERS ; i ++ )
2003-02-26 23:26:57 +00:00
GAMESTATE -> m_PlayerOptions [ i ]. m_fReverseScroll = 1 ;
2003-01-01 17:20:36 +00:00
}
2002-09-03 06:33:08 +00:00
// update theme metric cache
2003-03-26 19:15:38 +00:00
ITEM_CURVE_X . Refresh ();
ITEM_SPACING_Y . Refresh ();
2003-04-02 04:41:49 +00:00
USE_3D . Refresh ();
2003-06-30 00:34:18 +00:00
NUM_WHEEL_ITEMS_METRIC . Refresh ();
2002-09-03 06:33:08 +00:00
2002-05-28 20:01:22 +00:00
// for debugging
2003-01-30 07:18:33 +00:00
if ( GAMESTATE -> m_CurStyle == STYLE_INVALID )
2002-07-23 01:41:40 +00:00
GAMESTATE -> m_CurStyle = STYLE_DANCE_SINGLE ;
2002-05-28 20:01:22 +00:00
2003-04-12 17:39:27 +00:00
m_sprSelectionOverlay . Load ( THEME -> GetPathToG ( "MusicWheel highlight" ) );
2002-01-16 10:01:32 +00:00
m_sprSelectionOverlay . SetXY ( 0 , 0 );
2002-10-28 05:30:45 +00:00
m_sprSelectionOverlay . SetDiffuse ( RageColor ( 1 , 1 , 1 , 1 ) );
2003-02-18 23:15:38 +00:00
m_sprSelectionOverlay . SetEffectGlowShift ( 1.0f , RageColor ( 1 , 1 , 1 , 0.4f ), RageColor ( 1 , 1 , 1 , 1 ) );
2002-09-02 21:59:58 +00:00
AddChild ( & m_sprSelectionOverlay );
2002-01-16 10:01:32 +00:00
2002-08-13 23:26:46 +00:00
m_ScrollBar . SetX ( SCROLL_BAR_X );
2002-08-26 05:53:48 +00:00
m_ScrollBar . SetBarHeight ( SCROLL_BAR_HEIGHT );
2002-09-02 21:59:58 +00:00
this -> AddChild ( & m_ScrollBar );
2002-05-01 19:14:55 +00:00
2003-01-21 02:45:35 +00:00
/* We play a lot of this one, so precache it. */
2003-04-12 17:39:27 +00:00
m_soundChangeMusic . Load ( THEME -> GetPathToS ( "MusicWheel change" ), true );
m_soundChangeSort . Load ( THEME -> GetPathToS ( "MusicWheel sort" ) );
m_soundExpand . Load ( THEME -> GetPathToS ( "MusicWheel expand" ) );
m_soundStart . Load ( THEME -> GetPathToS ( "Common start" ) );
m_soundLocked . Load ( THEME -> GetPathToS ( "MusicWheel locked" ) );
2002-01-16 10:01:32 +00:00
m_iSelection = 0 ;
2003-06-16 17:28:58 +00:00
m_LastSongSortOrder = SORT_INVALID ;
2002-01-16 10:01:32 +00:00
2002-06-24 22:04:31 +00:00
m_WheelState = STATE_SELECTING_MUSIC ;
m_fTimeLeftInState = 0 ;
2002-01-20 08:59:38 +00:00
m_fPositionOffsetFromSelection = 0 ;
2002-01-16 10:01:32 +00:00
2002-06-24 22:04:31 +00:00
m_iSwitchesLeftInSpinDown = 0 ;
2003-02-25 21:10:07 +00:00
m_Moving = 0 ;
2003-02-01 05:39:48 +00:00
if ( GAMESTATE -> IsExtraStage () || GAMESTATE -> IsExtraStage2 () )
2002-07-31 04:06:34 +00:00
{
2002-08-01 13:42:56 +00:00
// make the preferred group the group of the last song played.
2003-02-25 00:33:42 +00:00
if ( GAMESTATE -> m_sPreferredGroup == GROUP_ALL_MUSIC && ! PREFSMAN -> m_bPickExtraStage )
2003-04-23 07:29:03 +00:00
{
ASSERT ( GAMESTATE -> m_pCurSong );
2002-08-01 13:42:56 +00:00
GAMESTATE -> m_sPreferredGroup = GAMESTATE -> m_pCurSong -> m_sGroupName ;
2003-04-23 07:29:03 +00:00
}
2002-08-01 13:42:56 +00:00
Song * pSong ;
Notes * pNotes ;
PlayerOptions po ;
SongOptions so ;
SONGMAN -> GetExtraStageInfo (
GAMESTATE -> IsExtraStage2 (),
GAMESTATE -> m_sPreferredGroup ,
2002-09-06 08:56:28 +00:00
GAMESTATE -> GetCurrentStyleDef (),
2002-08-01 13:42:56 +00:00
pSong ,
pNotes ,
po ,
so );
GAMESTATE -> m_pCurSong = pSong ;
for ( int p = 0 ; p < NUM_PLAYERS ; p ++ )
2002-07-31 04:06:34 +00:00
{
2003-04-10 05:46:31 +00:00
if ( GAMESTATE -> IsHumanPlayer ( p ) )
2002-07-31 04:06:34 +00:00
{
2002-08-01 13:42:56 +00:00
GAMESTATE -> m_pCurNotes [ p ] = pNotes ;
GAMESTATE -> m_PlayerOptions [ p ] = po ;
2003-07-07 19:19:16 +00:00
GAMESTATE -> m_PreferredDifficulty [ p ] = pNotes -> GetDifficulty ();
2002-07-31 04:06:34 +00:00
}
}
2002-08-01 13:42:56 +00:00
GAMESTATE -> m_SongOptions = so ;
2002-07-31 04:06:34 +00:00
}
2003-06-30 07:09:13 +00:00
if ( GAMESTATE -> m_SongSortOrder == SORT_INVALID )
{
2003-07-20 08:54:31 +00:00
switch ( GAMESTATE -> m_PlayMode )
{
case PLAY_MODE_ONI : GAMESTATE -> m_SongSortOrder = SORT_ONI_COURSES ; break ;
case PLAY_MODE_NONSTOP : GAMESTATE -> m_SongSortOrder = SORT_NONSTOP_COURSES ; break ;
case PLAY_MODE_ENDLESS : GAMESTATE -> m_SongSortOrder = SORT_ENDLESS_COURSES ; break ;
default : GAMESTATE -> m_SongSortOrder = SortOrder [ 0 ]; break ;
}
2003-06-30 07:09:13 +00:00
}
2003-05-17 23:04:14 +00:00
2003-07-21 21:47:50 +00:00
/* Update for SORT_MOST_PLAYED. */
SONGMAN -> UpdateBest ();
2002-08-30 21:51:40 +00:00
/* Build all of the wheel item data. Do tihs after selecting
* the extra stage, so it knows to always display it. */
for ( int so = 0 ; so < NUM_SORT_ORDERS ; so ++ )
BuildWheelItemDatas ( m_WheelItemDatas [ so ], SongSortOrder ( so ) );
2002-08-01 13:42:56 +00:00
// If there is no currently selected song, select one.
if ( GAMESTATE -> m_pCurSong == NULL )
2002-02-24 01:43:11 +00:00
{
2003-01-27 07:25:29 +00:00
//Select the first selectable song based on the sort order...
vector < WheelItemData > & wiWheelItems = m_WheelItemDatas [ GAMESTATE -> m_SongSortOrder ];
for ( unsigned i = 0 ; i < wiWheelItems . size (); i ++ )
2002-08-01 13:42:56 +00:00
{
2003-01-27 07:25:29 +00:00
if ( wiWheelItems [ i ]. m_pSong != NULL )
{
GAMESTATE -> m_pCurSong = wiWheelItems [ i ]. m_pSong ;
break ;
}
}
if ( GAMESTATE -> m_pCurSong == NULL )
2003-07-20 20:53:11 +00:00
LOG -> Trace ( "MusicWheel::MusicWheel() - No selectable songs found in WheelData" );
2002-02-24 01:43:11 +00:00
}
2002-08-01 05:11:11 +00:00
// Select the the previously selected song (if any)
2003-01-02 02:59:25 +00:00
bool selected = SelectSong ( GAMESTATE -> m_pCurSong );
2002-08-01 05:11:11 +00:00
// Select the the previously selected course (if any)
2003-01-02 02:59:25 +00:00
if ( ! selected ) selected = SelectCourse ( GAMESTATE -> m_pCurCourse );
if ( ! selected ) SetOpenGroup ( "" );
2002-08-01 05:11:11 +00:00
2002-02-09 18:53:47 +00:00
// rebuild the WheelItems that appear on screen
2003-03-31 23:06:15 +00:00
RebuildMusicWheelItems ();
2002-01-16 10:01:32 +00:00
}
2002-02-06 05:13:39 +00:00
MusicWheel ::~ MusicWheel ()
{
2002-08-13 23:26:46 +00:00
}
2003-01-02 02:59:25 +00:00
bool MusicWheel :: SelectSong ( const Song * p )
2002-08-13 23:26:46 +00:00
{
2003-01-02 02:59:25 +00:00
if ( p == NULL )
return false ;
unsigned i ;
vector < WheelItemData > & from = m_WheelItemDatas [ GAMESTATE -> m_SongSortOrder ];
for ( i = 0 ; i < from . size (); i ++ )
{
if ( from [ i ]. m_pSong == p )
{
// make its group the currently expanded group
SetOpenGroup ( from [ i ]. m_sSectionName );
break ;
}
}
if ( i == from . size ())
return false ;
for ( i = 0 ; i < m_CurWheelItemData . size (); i ++ )
{
if ( m_CurWheelItemData [ i ] -> m_pSong == p )
m_iSelection = i ; // select it
}
return true ;
2002-02-06 05:13:39 +00:00
}
2003-01-02 02:59:25 +00:00
bool MusicWheel :: SelectCourse ( const Course * p )
{
if ( p == NULL )
return false ;
unsigned i ;
vector < WheelItemData > & from = m_WheelItemDatas [ GAMESTATE -> m_SongSortOrder ];
for ( i = 0 ; i < from . size (); i ++ )
{
if ( from [ i ]. m_pCourse == p )
{
// make its group the currently expanded group
SetOpenGroup ( from [ i ]. m_sSectionName );
break ;
}
}
if ( i == from . size ())
return false ;
for ( i = 0 ; i < m_CurWheelItemData . size (); i ++ )
{
if ( m_CurWheelItemData [ i ] -> m_pCourse == p )
m_iSelection = i ; // select it
}
return true ;
}
2003-06-16 17:28:58 +00:00
bool MusicWheel :: SelectSort ( SongSortOrder so )
{
if ( so == SORT_INVALID )
return false ;
unsigned i ;
vector < WheelItemData > & from = m_WheelItemDatas [ GAMESTATE -> m_SongSortOrder ];
for ( i = 0 ; i < from . size (); i ++ )
{
2003-07-20 08:54:31 +00:00
if ( from [ i ]. m_SongSortOrder != so )
continue ;
if ( ! from [ i ]. m_Action . DescribesCurrentMode () )
continue ;
// make its group the currently expanded group
SetOpenGroup ( from [ i ]. m_sSectionName );
break ;
2003-06-16 17:28:58 +00:00
}
if ( i == from . size ())
return false ;
for ( i = 0 ; i < m_CurWheelItemData . size (); i ++ )
{
2003-07-20 08:54:31 +00:00
if ( m_CurWheelItemData [ i ] -> m_SongSortOrder != so )
continue ;
if ( ! m_CurWheelItemData [ i ] -> m_Action . DescribesCurrentMode () )
continue ;
m_iSelection = i ; // select it
break ;
2003-06-16 17:28:58 +00:00
}
return true ;
}
2003-04-19 18:51:13 +00:00
void MusicWheel :: GetSongList ( vector < Song *> & arraySongs , SongSortOrder so , CString sPreferredGroup )
2003-01-03 03:24:00 +00:00
{
2003-02-03 05:53:59 +00:00
vector < Song *> apAllSongs ;
2003-05-17 23:04:14 +00:00
// if( so==SORT_PREFERRED && GAMESTATE->m_sPreferredGroup!=GROUP_ALL_MUSIC)
// SONGMAN->GetSongs( apAllSongs, GAMESTATE->m_sPreferredGroup, GAMESTATE->GetNumStagesLeft() );
// else
// SONGMAN->GetSongs( apAllSongs, GAMESTATE->GetNumStagesLeft() );
SONGMAN -> GetSongs ( apAllSongs , GAMESTATE -> m_sPreferredGroup , GAMESTATE -> GetNumStagesLeft () );
2003-02-03 05:53:59 +00:00
2003-01-03 03:24:00 +00:00
// copy only songs that have at least one Notes for the current GameMode
2003-02-03 05:53:59 +00:00
for ( unsigned i = 0 ; i < apAllSongs . size (); i ++ )
2003-01-03 03:24:00 +00:00
{
2003-02-03 05:53:59 +00:00
Song * pSong = apAllSongs [ i ];
2003-01-03 03:24:00 +00:00
/* If we're on an extra stage, and this song is selected, ignore
* #SELECTABLE. */
if ( pSong != GAMESTATE -> m_pCurSong ||
( ! GAMESTATE -> IsExtraStage () && ! GAMESTATE -> IsExtraStage2 ()) ) {
/* Hide songs that asked to be hidden via #SELECTABLE. */
2003-04-19 18:51:13 +00:00
if ( so != SORT_ROULETTE && ! pSong -> NormallyDisplayed () )
2003-01-03 03:24:00 +00:00
continue ;
2003-07-09 11:38:50 +00:00
if ( so == SORT_ROULETTE && ! ( pSong -> RouletteDisplayed ()
|| GAMESTATE -> m_pUnlockingSys -> SongIsRoulette ( pSong )) )
2003-07-07 10:22:53 +00:00
continue ;
2003-01-03 03:24:00 +00:00
}
2003-07-18 08:04:47 +00:00
// If we're using unlocks, check it here to prevent from being shown
if ( so != SORT_ROULETTE && GAMESTATE -> m_pUnlockingSys -> SongIsLocked ( pSong ) )
continue ;
2003-01-03 05:56:28 +00:00
vector < Notes *> arraySteps ;
2003-03-27 01:56:21 +00:00
pSong -> GetNotes ( arraySteps , GAMESTATE -> GetCurrentStyleDef () -> m_NotesType , DIFFICULTY_INVALID , - 1 , - 1 , "" , PREFSMAN -> m_bAutogenMissingTypes );
2003-01-03 03:24:00 +00:00
if ( ! arraySteps . empty () )
arraySongs . push_back ( pSong );
}
}
2003-06-19 06:24:41 +00:00
extern map < const Song * , CString > song_sort_val ;
bool CompareSongPointersBySortVal ( const Song * pSong1 , const Song * pSong2 );
void MusicWheel :: SortSongPointerArrayBySectionName ( vector < Song *> & arraySongPointers , SongSortOrder so )
{
for ( unsigned i = 0 ; i < arraySongPointers . size (); ++ i )
{
CString val = MusicWheel :: GetSectionNameFromSongAndSort ( arraySongPointers [ i ], so );
/* Make sure NUM comes first and OTHER comes last. */
if ( val == "NUM" ) val = "0" ;
else if ( val == "OTHER" ) val = "2" ;
else val = "1" + val ;
song_sort_val [ arraySongPointers [ i ]] = val ;
}
stable_sort ( arraySongPointers . begin (), arraySongPointers . end (), CompareSongPointersBySortVal );
song_sort_val . clear ();
}
2003-02-11 23:52:18 +00:00
2003-01-03 03:24:00 +00:00
void MusicWheel :: BuildWheelItemDatas ( vector < WheelItemData > & arrayWheelItemDatas , SongSortOrder so )
2002-01-16 10:01:32 +00:00
{
2002-10-31 02:46:42 +00:00
unsigned i ;
2002-02-09 04:30:27 +00:00
2003-07-20 05:13:45 +00:00
switch ( so )
2002-02-09 18:53:47 +00:00
{
2003-07-20 08:54:31 +00:00
case SORT_MENU :
{
2003-07-20 05:13:45 +00:00
arrayWheelItemDatas . clear (); // clear out the previous wheel items
2003-07-20 08:54:31 +00:00
CString sNames = MENU_NAMES , sActions = MENU_ACTIONS ;
vector < CString > Names , Actions ;
split ( sNames , "," , Names );
split ( sActions , "," , Actions );
if ( Names . size () != Actions . size () )
RageException :: Throw ( "MusicWheel::MenuNames and MusicWheel::MenuActions must have the same number of components" );
for ( i = 0 ; i < Names . size (); ++ i )
2002-06-14 22:25:22 +00:00
{
2003-07-20 08:54:31 +00:00
/* Look for sort names. */
vector < CString > parts ;
split ( Actions [ i ], "-" , parts );
SongSortOrder so = SORT_INVALID ;
for ( unsigned j = 0 ; so == SORT_INVALID && j < parts . size (); ++ j )
so = StringToSongSortOrder ( parts [ j ] );
if ( so == SORT_INVALID )
so = SORT_GROUP ;
2003-07-20 05:13:45 +00:00
RageColor c = RageColor ( 1 , 1 , 0 , 1 );
2003-07-20 08:54:31 +00:00
WheelItemData wid ( TYPE_SORT , NULL , "" , NULL , c , so );
wid . m_sLabel = Names [ i ];
wid . m_Action . FromString ( Actions [ i ], true );
2003-07-20 09:15:46 +00:00
switch ( so )
{
case SORT_ALL_COURSES :
case SORT_NONSTOP_COURSES :
case SORT_ONI_COURSES :
case SORT_ENDLESS_COURSES :
/* Don't display course modes after the first stage. */
if ( ! PREFSMAN -> m_bEventMode && GAMESTATE -> m_iCurrentStageIndex )
continue ;
}
2003-07-20 08:54:31 +00:00
arrayWheelItemDatas . push_back ( wid );
}
2003-07-20 05:13:45 +00:00
break ;
2003-07-20 08:54:31 +00:00
}
2003-07-20 05:13:45 +00:00
case SORT_PREFERRED :
case SORT_ROULETTE :
case SORT_GROUP :
case SORT_TITLE :
case SORT_BPM :
case SORT_MOST_PLAYED :
case SORT_GRADE :
case SORT_ARTIST :
case SORT_EASY_METER :
case SORT_MEDIUM_METER :
case SORT_HARD_METER :
{
///////////////////////////////////
// Make an array of Song*, then sort them
///////////////////////////////////
vector < Song *> arraySongs ;
GetSongList ( arraySongs , so , GAMESTATE -> m_sPreferredGroup );
2003-06-16 17:28:58 +00:00
2003-07-20 05:13:45 +00:00
bool bUseSections = true ;
2002-02-09 18:53:47 +00:00
2003-07-20 05:13:45 +00:00
// sort the songs
switch ( so )
{
case SORT_PREFERRED :
case SORT_ROULETTE :
SortSongPointerArrayByGroupAndDifficulty ( arraySongs );
bUseSections = false ;
break ;
case SORT_GROUP :
SortSongPointerArrayByGroupAndTitle ( arraySongs );
bUseSections = GAMESTATE -> m_sPreferredGroup == GROUP_ALL_MUSIC ;
break ;
case SORT_TITLE :
SortSongPointerArrayByTitle ( arraySongs );
break ;
case SORT_BPM :
SortSongPointerArrayByBPM ( arraySongs );
break ;
case SORT_MOST_PLAYED :
2003-07-21 21:47:50 +00:00
arraySongs = SONGMAN -> GetBestSongs ();
2003-07-20 05:13:45 +00:00
if ( arraySongs . size () > 30 )
arraySongs . erase ( arraySongs . begin () + 30 , arraySongs . end ());
bUseSections = false ;
break ;
case SORT_GRADE :
SortSongPointerArrayByGrade ( arraySongs );
break ;
case SORT_ARTIST :
SortSongPointerArrayByArtist ( arraySongs );
break ;
case SORT_EASY_METER :
SortSongPointerArrayByMeter ( arraySongs , DIFFICULTY_EASY );
break ;
case SORT_MEDIUM_METER :
SortSongPointerArrayByMeter ( arraySongs , DIFFICULTY_MEDIUM );
break ;
case SORT_HARD_METER :
SortSongPointerArrayByMeter ( arraySongs , DIFFICULTY_HARD );
break ;
default :
ASSERT ( 0 ); // unhandled SortOrder
}
2002-06-14 22:25:22 +00:00
2003-07-20 05:13:45 +00:00
///////////////////////////////////
// Build an array of WheelItemDatas from the sorted list of Song*'s
///////////////////////////////////
arrayWheelItemDatas . clear (); // clear out the previous wheel items
2002-06-14 22:25:22 +00:00
2003-07-20 05:13:45 +00:00
if ( PREFSMAN -> m_MusicWheelUsesSections == PrefsManager :: NEVER || ( so != SORT_TITLE && PREFSMAN -> m_MusicWheelUsesSections == PrefsManager :: ABC_ONLY ))
bUseSections = false ;
2002-06-30 23:19:33 +00:00
2003-07-20 05:13:45 +00:00
if ( bUseSections )
{
// Sorting twice isn't necessary. Instead, modify the compatator functions
// in Song.cpp to have the desired effect. -Chris
/* Keeping groups together with the sorts is tricky and brittle; we
* keep getting OTHER split up without this. However, it puts the
* Grade and BPM sorts in the wrong order, and they're already correct,
* so don't re-sort for them. */
2003-06-16 20:23:07 +00:00
// /* We're using sections, so use the section name as the top-level
// * sort. */
2003-07-20 05:13:45 +00:00
if ( so != SORT_GRADE && so != SORT_BPM )
SortSongPointerArrayBySectionName ( arraySongs , so );
2003-02-11 23:52:18 +00:00
2003-07-20 05:13:45 +00:00
// make WheelItemDatas with sections
CString sLastSection = "" ;
RageColor colorSection ;
for ( unsigned i = 0 ; i < arraySongs . size (); i ++ )
2002-06-14 22:25:22 +00:00
{
2003-07-20 05:13:45 +00:00
Song * pSong = arraySongs [ i ];
CString sThisSection = GetSectionNameFromSongAndSort ( pSong , so );
int iSectionColorIndex = 0 ;
if ( sThisSection != sLastSection ) // new section, make a section item
2002-06-14 22:25:22 +00:00
{
2003-07-20 05:13:45 +00:00
colorSection = ( so == SORT_GROUP ) ? SONGMAN -> GetGroupColor ( pSong -> m_sGroupName ) : SECTION_COLORS ( iSectionColorIndex );
iSectionColorIndex = ( iSectionColorIndex + 1 ) % NUM_SECTION_COLORS ;
arrayWheelItemDatas . push_back ( WheelItemData ( TYPE_SECTION , NULL , sThisSection , NULL , colorSection , SORT_INVALID ) );
sLastSection = sThisSection ;
2003-02-25 00:33:42 +00:00
}
2003-07-20 05:13:45 +00:00
arrayWheelItemDatas . push_back ( WheelItemData ( TYPE_SONG , pSong , sThisSection , NULL , SONGMAN -> GetSongColor ( pSong ), SORT_INVALID ) );
2003-02-25 00:33:42 +00:00
}
}
2003-07-20 05:13:45 +00:00
else
2002-07-29 03:06:55 +00:00
{
2003-07-20 05:13:45 +00:00
for ( unsigned i = 0 ; i < arraySongs . size (); i ++ )
2002-08-01 20:30:40 +00:00
{
2003-07-20 05:13:45 +00:00
Song * pSong = arraySongs [ i ];
arrayWheelItemDatas . push_back ( WheelItemData ( TYPE_SONG , pSong , "" , NULL , SONGMAN -> GetSongColor ( pSong ), SORT_INVALID ) );
2002-07-29 03:06:55 +00:00
}
}
2003-07-20 05:13:45 +00:00
if ( so != SORT_ROULETTE && SHOW_ROULETTE )
arrayWheelItemDatas . push_back ( WheelItemData ( TYPE_ROULETTE , NULL , "" , NULL , RageColor ( 1 , 0 , 0 , 1 ), SORT_INVALID ) );
if ( so != SORT_ROULETTE && SHOW_RANDOM )
arrayWheelItemDatas . push_back ( WheelItemData ( TYPE_RANDOM , NULL , "" , NULL , RageColor ( 1 , 0 , 0 , 1 ), SORT_INVALID ) );
// HACK: Add extra stage item if it isn't already present on the music wheel
if ( GAMESTATE -> IsExtraStage () || GAMESTATE -> IsExtraStage2 () )
{
Song * pSong ;
Notes * pNotes ;
PlayerOptions po ;
SongOptions so ;
SONGMAN -> GetExtraStageInfo ( GAMESTATE -> IsExtraStage2 (), GAMESTATE -> m_pCurSong -> m_sGroupName , GAMESTATE -> GetCurrentStyleDef (), pSong , pNotes , po , so );
bool bFoundExtraSong = false ;
for ( unsigned i = 0 ; i < arrayWheelItemDatas . size (); i ++ )
{
if ( arrayWheelItemDatas [ i ]. m_pSong == pSong )
{
/* Change the song color. */
arrayWheelItemDatas [ i ]. m_color = SONG_REAL_EXTRA_COLOR ;
bFoundExtraSong = true ;
break ;
}
}
if ( ! bFoundExtraSong )
arrayWheelItemDatas . push_back ( WheelItemData ( TYPE_SONG , pSong , "" , NULL , SONG_REAL_EXTRA_COLOR , SORT_INVALID ) );
}
2002-07-29 03:06:55 +00:00
break ;
2003-07-20 05:13:45 +00:00
}
2003-07-20 08:54:31 +00:00
case SORT_ALL_COURSES :
case SORT_NONSTOP_COURSES :
case SORT_ONI_COURSES :
case SORT_ENDLESS_COURSES :
2003-07-20 05:13:45 +00:00
{
vector < Course *> apCourses ;
2003-07-20 08:54:31 +00:00
switch ( so )
2003-07-20 05:13:45 +00:00
{
2003-07-20 08:54:31 +00:00
case SORT_NONSTOP_COURSES : SONGMAN -> GetNonstopCourses ( apCourses , PREFSMAN -> m_bAutogenGroupCourses ); break ;
case SORT_ONI_COURSES : SONGMAN -> GetOniCourses ( apCourses , PREFSMAN -> m_bAutogenGroupCourses ); break ;
case SORT_ENDLESS_COURSES : SONGMAN -> GetEndlessCourses ( apCourses , PREFSMAN -> m_bAutogenGroupCourses ); break ;
case SORT_ALL_COURSES : SONGMAN -> GetAllCourses ( apCourses , PREFSMAN -> m_bAutogenGroupCourses ); break ;
default : ASSERT ( 0 ); break ;
2003-07-20 05:13:45 +00:00
}
2003-07-27 14:10:47 +00:00
// default sort order; other songs may alter this
2003-07-20 05:13:45 +00:00
SortCoursePointerArrayByDifficulty ( apCourses );
2003-07-27 18:39:34 +00:00
if ( PREFSMAN -> m_iCourseSortOrder != PrefsManager :: COURSE_SORT_SONGS )
2003-07-27 14:10:47 +00:00
{
for ( i = 0 ; i < apCourses . size (); i ++ )
apCourses [ i ] -> UpdateCourseStats ();
2003-07-27 18:39:34 +00:00
if ( PREFSMAN -> m_iCourseSortOrder == PrefsManager :: COURSE_SORT_METER )
2003-07-27 14:10:47 +00:00
SortCoursePointerArrayByAvgDifficulty ( apCourses );
2003-07-27 18:39:34 +00:00
if ( PREFSMAN -> m_iCourseSortOrder == PrefsManager :: COURSE_SORT_METER_SUM )
2003-07-27 14:10:47 +00:00
SortCoursePointerArrayByTotalDifficulty ( apCourses );
2003-07-27 18:39:34 +00:00
if ( PREFSMAN -> m_iCourseSortOrder == PrefsManager :: COURSE_SORT_RANK )
2003-07-27 14:10:47 +00:00
SortCoursePointerArrayByRanking ( apCourses );
}
2003-07-20 08:54:31 +00:00
if ( so == SORT_ALL_COURSES )
SortCoursePointerArrayByType ( apCourses );
arrayWheelItemDatas . clear (); // clear out the previous wheel items
CString sLastSection = "" ;
int iSectionColorIndex = 0 ;
2003-07-20 05:13:45 +00:00
for ( unsigned c = 0 ; c < apCourses . size (); c ++ ) // foreach course
{
Course * pCourse = apCourses [ c ];
// if unlocks are on, make sure it is unlocked
if ( GAMESTATE -> m_pUnlockingSys -> CourseIsLocked ( pCourse ) )
continue ;
2003-07-20 08:54:31 +00:00
CString sThisSection = "" ;
if ( so == SORT_ALL_COURSES )
switch ( pCourse -> GetPlayMode () )
{
case PLAY_MODE_ONI : sThisSection = "Oni" ; break ;
case PLAY_MODE_NONSTOP : sThisSection = "Nonstop" ; break ;
case PLAY_MODE_ENDLESS : sThisSection = "Endless" ; break ;
}
2003-07-20 05:13:45 +00:00
// check that this course has at least one song playable in the current style
2003-07-20 08:54:31 +00:00
if ( ! pCourse -> IsPlayableIn ( GAMESTATE -> GetCurrentStyleDef () -> m_NotesType ) )
continue ;
if ( sThisSection != sLastSection ) // new section, make a section item
{
RageColor c = SECTION_COLORS ( iSectionColorIndex );
iSectionColorIndex = ( iSectionColorIndex + 1 ) % NUM_SECTION_COLORS ;
arrayWheelItemDatas . push_back ( WheelItemData ( TYPE_SECTION , NULL , sThisSection , NULL , c , SORT_INVALID ) );
sLastSection = sThisSection ;
}
arrayWheelItemDatas . push_back ( WheelItemData ( TYPE_COURSE , NULL , sThisSection , pCourse , pCourse -> GetColor (), SORT_INVALID ) );
2003-07-20 05:13:45 +00:00
}
break ;
}
2002-01-16 10:01:32 +00:00
}
2003-02-10 05:30:12 +00:00
// init music status icons
2002-10-31 02:46:42 +00:00
for ( i = 0 ; i < arrayWheelItemDatas . size (); i ++ )
2002-02-10 06:25:12 +00:00
{
Song * pSong = arrayWheelItemDatas [ i ]. m_pSong ;
2002-08-20 21:00:56 +00:00
if ( pSong == NULL )
continue ;
2002-09-06 10:13:46 +00:00
WheelItemData & WID = arrayWheelItemDatas [ i ];
2003-02-10 05:30:12 +00:00
WID . m_Flags . bHasBeginnerOr1Meter = pSong -> IsEasy ( NOTES_TYPE_DANCE_SINGLE );
WID . m_Flags . bEdits = pSong -> HasEdits ( NOTES_TYPE_DANCE_SINGLE );
WID . m_Flags . iStagesForSong = SongManager :: GetNumStagesForSong ( pSong );
2002-02-10 06:25:12 +00:00
}
2002-01-16 10:01:32 +00:00
2003-02-10 05:30:12 +00:00
// init crowns
2002-02-06 05:13:39 +00:00
if ( so == SORT_MOST_PLAYED )
2002-01-16 10:01:32 +00:00
{
// init crown icons
2002-10-31 02:46:42 +00:00
for ( i = 0 ; i < min ( 3u , arrayWheelItemDatas . size ()); i ++ )
2002-01-16 10:01:32 +00:00
{
2002-08-20 21:00:56 +00:00
WheelItemData & WID = arrayWheelItemDatas [ i ];
2003-02-10 05:30:12 +00:00
WID . m_Flags . iPlayersBestNumber = i + 1 ;
2002-01-16 10:01:32 +00:00
}
}
2002-10-31 02:46:42 +00:00
if ( arrayWheelItemDatas . empty () )
2002-01-16 10:01:32 +00:00
{
2003-06-16 17:28:58 +00:00
arrayWheelItemDatas . push_back ( WheelItemData ( TYPE_SECTION , NULL , "- EMPTY -" , NULL , RageColor ( 1 , 0 , 0 , 1 ), SORT_INVALID ) );
2002-05-19 01:59:48 +00:00
}
2002-01-16 10:01:32 +00:00
}
2003-04-02 04:41:49 +00:00
void MusicWheel :: GetItemPosition ( float fPosOffsetsFromMiddle , float & fX_out , float & fY_out , float & fZ_out , float & fRotationX_out )
2002-01-16 10:01:32 +00:00
{
2003-04-02 04:41:49 +00:00
if ( USE_3D )
{
2003-07-10 03:38:21 +00:00
fRotationX_out = SCALE ( fPosOffsetsFromMiddle , - 7 , + 7 , - PI / 2.f , + PI / 2.f );
2002-01-16 10:01:32 +00:00
2003-07-05 05:34:16 +00:00
// printf( "fRotationX_out = %f\n", fRotationX_out );
2003-04-02 04:41:49 +00:00
float radius = 200 ;
fX_out = 0 ;
2003-07-10 03:38:21 +00:00
fY_out = radius * sinf ( fRotationX_out );
fZ_out = - 100 + radius * cosf ( fRotationX_out );
2003-04-23 05:54:56 +00:00
fRotationX_out *= 180.f / PI ; // to degrees
2003-04-02 04:41:49 +00:00
}
else
{
fX_out = ( 1 - cosf ( fPosOffsetsFromMiddle / PI )) * ITEM_CURVE_X ;
fY_out = fPosOffsetsFromMiddle * ITEM_SPACING_Y ;
fZ_out = 0 ;
fRotationX_out = 0 ;
fX_out = roundf ( fX_out );
fY_out = roundf ( fY_out );
fZ_out = roundf ( fZ_out );
}
2002-01-16 10:01:32 +00:00
}
2003-03-31 23:06:15 +00:00
void MusicWheel :: RebuildMusicWheelItems ()
2002-01-16 10:01:32 +00:00
{
2002-02-09 04:30:27 +00:00
// rewind to first index that will be displayed;
2002-01-16 10:01:32 +00:00
int iIndex = m_iSelection ;
2003-01-02 02:59:25 +00:00
if ( m_iSelection > int ( m_CurWheelItemData . size () - 1 ) )
2002-02-10 06:25:12 +00:00
m_iSelection = 0 ;
2002-11-16 08:55:46 +00:00
2003-03-26 19:15:38 +00:00
iIndex -= NUM_WHEEL_ITEMS / 2 ;
2003-03-14 22:55:06 +00:00
ASSERT ( m_CurWheelItemData . size ());
2003-01-02 02:59:25 +00:00
while ( iIndex < 0 )
iIndex += m_CurWheelItemData . size ();
2002-01-16 10:01:32 +00:00
// iIndex is now the index of the lowest WheelItem to draw
2003-03-26 19:15:38 +00:00
for ( int i = 0 ; i < NUM_WHEEL_ITEMS ; i ++ )
2002-01-16 10:01:32 +00:00
{
2003-01-02 02:59:25 +00:00
WheelItemData * data = m_CurWheelItemData [ iIndex ];
2003-03-31 23:06:15 +00:00
MusicWheelItem & display = m_MusicWheelItems [ i ];
2002-01-16 10:01:32 +00:00
2003-01-02 02:59:25 +00:00
display . LoadFromWheelItemData ( data );
2002-02-09 04:30:27 +00:00
// increment iIndex
2003-01-02 02:59:25 +00:00
iIndex ++ ;
if ( iIndex > int ( m_CurWheelItemData . size () - 1 ) )
iIndex = 0 ;
2002-02-09 04:30:27 +00:00
}
}
2002-04-28 20:42:32 +00:00
void MusicWheel :: NotesChanged ( PlayerNumber pn ) // update grade graphics and top score
{
2003-03-26 19:15:38 +00:00
for ( int i = 0 ; i < NUM_WHEEL_ITEMS ; i ++ )
2002-04-28 20:42:32 +00:00
{
2003-03-31 23:06:15 +00:00
MusicWheelItem & display = m_MusicWheelItems [ i ];
2002-04-28 20:42:32 +00:00
display . RefreshGrades ();
}
}
2002-02-09 04:30:27 +00:00
2002-05-19 01:59:48 +00:00
void MusicWheel :: DrawPrimitives ()
2002-02-09 04:30:27 +00:00
{
2003-04-02 04:41:49 +00:00
if ( USE_3D )
{
2003-04-23 05:54:56 +00:00
// DISPLAY->PushMatrix();
// DISPLAY->EnterPerspective(45, false);
2003-04-02 04:41:49 +00:00
// construct view and project matrix
2003-04-23 05:54:56 +00:00
// RageVector3 Up( 0.0f, 1.0f, 0.0f );
// RageVector3 Eye( CENTER_X, CENTER_Y, 550 );
// RageVector3 At( CENTER_X, CENTER_Y, 0 );
2003-04-02 04:41:49 +00:00
2003-04-23 05:54:56 +00:00
// DISPLAY->LookAt(Eye, At, Up);
2003-04-02 04:41:49 +00:00
}
2003-04-23 05:54:56 +00:00
// draw outside->inside
int i ;
for ( i = 0 ; i < NUM_WHEEL_ITEMS / 2 ; i ++ )
DrawItem ( i );
for ( i = NUM_WHEEL_ITEMS - 1 ; i >= NUM_WHEEL_ITEMS / 2 ; i -- )
DrawItem ( i );
2002-02-09 04:30:27 +00:00
2002-01-16 10:01:32 +00:00
2002-05-19 01:59:48 +00:00
ActorFrame :: DrawPrimitives ();
2003-04-02 04:41:49 +00:00
if ( USE_3D )
{
2003-04-23 05:54:56 +00:00
// DISPLAY->ExitPerspective();
// DISPLAY->PopMatrix();
2003-04-02 04:41:49 +00:00
}
2002-01-16 10:01:32 +00:00
}
2003-04-23 05:54:56 +00:00
void MusicWheel :: DrawItem ( int i )
{
MusicWheelItem & display = m_MusicWheelItems [ i ];
switch ( m_WheelState )
{
case STATE_SELECTING_MUSIC :
case STATE_ROULETTE_SPINNING :
case STATE_ROULETTE_SLOWING_DOWN :
case STATE_RANDOM_SPINNING :
case STATE_LOCKED :
{
float fThisBannerPositionOffsetFromSelection = i - NUM_WHEEL_ITEMS / 2 + m_fPositionOffsetFromSelection ;
float fX , fY , fZ , fRotationX ;
GetItemPosition ( fThisBannerPositionOffsetFromSelection , fX , fY , fZ , fRotationX );
// if( fY < -SCREEN_HEIGHT/2 || fY > SCREEN_HEIGHT/2 )
// continue; // skip
display . SetXY ( fX , fY );
display . SetZ ( fZ );
display . SetRotationX ( fRotationX );
}
break ;
}
if ( m_WheelState == STATE_LOCKED && i != NUM_WHEEL_ITEMS / 2 )
display . m_fPercentGray = 0.5f ;
else
display . m_fPercentGray = 0 ;
display . Draw ();
}
2003-01-02 02:59:25 +00:00
void MusicWheel :: UpdateScrollbar ()
{
int total_num_items = m_CurWheelItemData . size ();
float item_at = m_iSelection - m_fPositionOffsetFromSelection ;
2003-04-20 02:02:58 +00:00
if ( NUM_WHEEL_ITEMS >= total_num_items ) {
2003-01-02 02:59:25 +00:00
m_ScrollBar . SetPercentage ( 0 , 1 );
} else {
2003-03-26 19:15:38 +00:00
float size = float ( NUM_WHEEL_ITEMS ) / total_num_items ;
2003-01-02 02:59:25 +00:00
float center = item_at / total_num_items ;
size *= 0.5f ;
m_ScrollBar . SetPercentage ( center - size , center + size );
}
}
2002-01-16 10:01:32 +00:00
void MusicWheel :: Update ( float fDeltaTime )
{
ActorFrame :: Update ( fDeltaTime );
2002-10-31 02:46:42 +00:00
unsigned i ;
2003-03-26 21:32:48 +00:00
for ( i = 0 ; i < unsigned ( NUM_WHEEL_ITEMS ); i ++ )
2002-01-16 10:01:32 +00:00
{
2003-03-31 23:06:15 +00:00
MusicWheelItem & display = m_MusicWheelItems [ i ];
2002-02-09 04:30:27 +00:00
display . Update ( fDeltaTime );
2002-01-16 10:01:32 +00:00
}
2003-01-02 02:59:25 +00:00
UpdateScrollbar ();
2002-01-16 10:01:32 +00:00
2003-01-02 02:59:25 +00:00
if ( m_Moving )
2002-06-14 22:25:22 +00:00
{
2003-01-02 02:59:25 +00:00
m_TimeBeforeMovingBegins -= fDeltaTime ;
m_TimeBeforeMovingBegins = max ( m_TimeBeforeMovingBegins , 0 );
2002-06-24 22:04:31 +00:00
}
2002-01-16 10:01:32 +00:00
// update wheel state
m_fTimeLeftInState -= fDeltaTime ;
if ( m_fTimeLeftInState <= 0 ) // time to go to a new state
{
switch ( m_WheelState )
{
2002-01-18 21:19:05 +00:00
case STATE_FLYING_OFF_BEFORE_NEXT_SORT :
2002-01-16 10:01:32 +00:00
{
2003-01-02 02:59:25 +00:00
Song * pPrevSelectedSong = m_CurWheelItemData [ m_iSelection ] -> m_pSong ;
2003-02-03 04:50:37 +00:00
2003-03-25 21:17:29 +00:00
SCREENMAN -> PostMessageToTopScreen ( SM_SortOrderChanged , 0 );
2003-06-16 17:28:58 +00:00
2003-01-02 02:59:25 +00:00
SetOpenGroup ( GetSectionNameFromSongAndSort ( pPrevSelectedSong , GAMESTATE -> m_SongSortOrder ));
2002-06-14 22:25:22 +00:00
m_iSelection = 0 ;
2002-02-24 01:43:11 +00:00
2003-06-16 17:28:58 +00:00
switch ( GAMESTATE -> m_SongSortOrder )
2002-02-24 01:43:11 +00:00
{
2003-06-16 17:28:58 +00:00
case SORT_PREFERRED :
case SORT_GROUP :
case SORT_TITLE :
case SORT_BPM :
2003-06-16 20:23:07 +00:00
case SORT_GRADE :
case SORT_ARTIST :
2003-06-16 17:28:58 +00:00
case SORT_MOST_PLAYED :
case SORT_ROULETTE :
2003-06-27 08:06:22 +00:00
case SORT_EASY_METER :
case SORT_MEDIUM_METER :
case SORT_HARD_METER :
2003-07-20 08:54:31 +00:00
case SORT_ALL_COURSES :
case SORT_NONSTOP_COURSES :
case SORT_ONI_COURSES :
case SORT_ENDLESS_COURSES :
2003-06-16 17:28:58 +00:00
// Look for the last selected song or course
if ( GAMESTATE -> m_pCurCourse )
SelectCourse ( GAMESTATE -> m_pCurCourse );
if ( GAMESTATE -> m_pCurSong )
SelectSong ( GAMESTATE -> m_pCurSong );
break ;
2003-07-20 08:54:31 +00:00
case SORT_MENU :
2003-06-16 17:28:58 +00:00
SelectSort ( m_LastSongSortOrder );
break ;
default :
ASSERT ( 0 );
2002-08-28 22:42:40 +00:00
}
2003-06-27 08:06:22 +00:00
// Change difficulty for sorts by meter
switch ( GAMESTATE -> m_SongSortOrder )
{
case SORT_EASY_METER :
{
for ( int p = 0 ; p < NUM_PLAYERS ; p ++ )
if ( GAMESTATE -> IsPlayerEnabled ( p ) )
GAMESTATE -> m_PreferredDifficulty [ p ] = DIFFICULTY_EASY ;
}
break ;
case SORT_MEDIUM_METER :
{
for ( int p = 0 ; p < NUM_PLAYERS ; p ++ )
if ( GAMESTATE -> IsPlayerEnabled ( p ) )
GAMESTATE -> m_PreferredDifficulty [ p ] = DIFFICULTY_MEDIUM ;
}
break ;
case SORT_HARD_METER :
{
for ( int p = 0 ; p < NUM_PLAYERS ; p ++ )
if ( GAMESTATE -> IsPlayerEnabled ( p ) )
GAMESTATE -> m_PreferredDifficulty [ p ] = DIFFICULTY_HARD ;
}
break ;
}
2003-03-25 21:17:29 +00:00
SCREENMAN -> PostMessageToTopScreen ( SM_SongChanged , 0 );
2003-03-31 23:06:15 +00:00
RebuildMusicWheelItems ();
2003-01-02 02:59:25 +00:00
TweenOnScreen ( true );
2003-01-03 03:24:00 +00:00
m_WheelState = STATE_FLYING_ON_AFTER_NEXT_SORT ;
2002-01-16 10:01:32 +00:00
}
break ;
2003-01-03 03:24:00 +00:00
2002-01-18 21:19:05 +00:00
case STATE_FLYING_ON_AFTER_NEXT_SORT :
2002-06-24 22:04:31 +00:00
m_WheelState = STATE_SELECTING_MUSIC ; // now, wait for input
2002-01-16 10:01:32 +00:00
break ;
2003-01-03 03:24:00 +00:00
2002-01-18 21:19:05 +00:00
case STATE_TWEENING_ON_SCREEN :
m_fTimeLeftInState = 0 ;
2003-02-01 05:39:48 +00:00
if ( ( GAMESTATE -> IsExtraStage () && ! PREFSMAN -> m_bPickExtraStage ) || GAMESTATE -> IsExtraStage2 () )
2002-07-31 04:06:34 +00:00
{
2003-07-20 20:10:54 +00:00
m_WheelState = STATE_LOCKED ;
m_soundStart . Play ();
m_fLockedWheelVelocity = 0 ;
2002-07-31 04:06:34 +00:00
}
else
{
m_WheelState = STATE_SELECTING_MUSIC ;
}
2002-01-18 21:19:05 +00:00
break ;
case STATE_TWEENING_OFF_SCREEN :
m_WheelState = STATE_WAITING_OFF_SCREEN ;
m_fTimeLeftInState = 0 ;
break ;
2002-06-24 22:04:31 +00:00
case STATE_SELECTING_MUSIC :
2002-01-16 10:01:32 +00:00
m_fTimeLeftInState = 0 ;
break ;
2002-06-24 22:04:31 +00:00
case STATE_ROULETTE_SPINNING :
2003-01-03 03:24:00 +00:00
case STATE_RANDOM_SPINNING :
2002-06-24 22:04:31 +00:00
break ;
case STATE_WAITING_OFF_SCREEN :
break ;
case STATE_LOCKED :
break ;
2002-06-14 22:25:22 +00:00
case STATE_ROULETTE_SLOWING_DOWN :
2002-06-24 22:04:31 +00:00
if ( m_iSwitchesLeftInSpinDown == 0 )
{
m_WheelState = STATE_LOCKED ;
m_fTimeLeftInState = 0 ;
m_soundStart . Play ();
m_fLockedWheelVelocity = 0 ;
2003-01-02 02:59:25 +00:00
/* Send this again so the screen starts sample music. */
2003-03-25 21:17:29 +00:00
SCREENMAN -> PostMessageToTopScreen ( SM_SongChanged , 0 );
2002-06-24 22:04:31 +00:00
}
else
{
m_iSwitchesLeftInSpinDown -- ;
2002-09-10 02:37:17 +00:00
const float SwitchTimes [] = { 0.5f , 1.3f , 0.8f , 0.4f , 0.2f };
ASSERT ( m_iSwitchesLeftInSpinDown >= 0 && m_iSwitchesLeftInSpinDown <= 4 );
m_fTimeLeftInState = SwitchTimes [ m_iSwitchesLeftInSpinDown ];
2002-07-31 19:40:40 +00:00
LOG -> Trace ( "m_iSwitchesLeftInSpinDown id %d, m_fTimeLeftInState is %f" , m_iSwitchesLeftInSpinDown , m_fTimeLeftInState );
2002-06-24 22:04:31 +00:00
if ( m_iSwitchesLeftInSpinDown < 2 )
2003-01-21 07:04:53 +00:00
ChangeMusic ( randomf ( 0 , 1 ) >= 0.5f ? 1 :- 1 );
2002-06-24 22:04:31 +00:00
else
2003-01-21 07:04:53 +00:00
ChangeMusic ( 1 );
2002-06-24 22:04:31 +00:00
}
break ;
default :
ASSERT ( 0 ); // all state changes should be handled explitily
2002-06-14 22:25:22 +00:00
break ;
2002-01-16 10:01:32 +00:00
}
}
2002-06-24 22:04:31 +00:00
if ( m_WheelState == STATE_LOCKED )
{
2003-01-03 03:24:00 +00:00
/* Do this in at most .1 sec chunks, so we don't get weird if we
* stop for some reason (and so it behaves the same when being
* single stepped). */
float tm = fDeltaTime ;
while ( tm > 0 )
2002-06-24 22:04:31 +00:00
{
2003-01-03 03:24:00 +00:00
float t = min ( tm , 0.1f );
tm -= t ;
m_fPositionOffsetFromSelection = clamp ( m_fPositionOffsetFromSelection , - 0.3f , + 0.3f );
float fSpringForce = - m_fPositionOffsetFromSelection * LOCKED_INITIAL_VELOCITY ;
m_fLockedWheelVelocity += fSpringForce ;
float fDrag = - m_fLockedWheelVelocity * t * 4 ;
m_fLockedWheelVelocity += fDrag ;
m_fPositionOffsetFromSelection += m_fLockedWheelVelocity * t ;
if ( fabsf ( m_fPositionOffsetFromSelection ) < 0.01f && fabsf ( m_fLockedWheelVelocity ) < 0.01f )
{
m_fPositionOffsetFromSelection = 0 ;
m_fLockedWheelVelocity = 0 ;
}
2002-06-24 22:04:31 +00:00
}
}
2003-01-21 07:04:53 +00:00
else if ( IsMoving () )
{
/* We're automatically moving. Move linearly, and don't clamp
* to the selection. */
float fSpinSpeed = m_SpinSpeed * m_Moving ;
m_fPositionOffsetFromSelection -= fSpinSpeed * fDeltaTime ;
/* Make sure that we don't go further than 1 away, in case the
* speed is very high or we miss a lot of frames. */
m_fPositionOffsetFromSelection = clamp ( m_fPositionOffsetFromSelection , - 1.0f , 1.0f );
/* If it passed the selection, move again. */
if (( m_Moving == - 1 && m_fPositionOffsetFromSelection >= 0 ) ||
( m_Moving == 1 && m_fPositionOffsetFromSelection <= 0 ))
{
ChangeMusic ( m_Moving );
if ( PREFSMAN -> m_iMusicWheelSwitchSpeed < MAX_WHEEL_SOUND_SPEED )
m_soundChangeMusic . Play ();
}
if ( PREFSMAN -> m_iMusicWheelSwitchSpeed >= MAX_WHEEL_SOUND_SPEED &&
m_MovingSoundTimer . PeekDeltaTime () >= 1.0f / MAX_WHEEL_SOUND_SPEED )
{
m_MovingSoundTimer . GetDeltaTime ();
m_soundChangeMusic . Play ();
}
}
2002-01-20 08:59:38 +00:00
else
{
2002-06-24 22:04:31 +00:00
// "rotate" wheel toward selected song
2003-01-21 07:04:53 +00:00
float fSpinSpeed = 0.2f + fabsf ( m_fPositionOffsetFromSelection ) / SWITCH_SECONDS ;
2002-06-24 22:04:31 +00:00
if ( m_fPositionOffsetFromSelection > 0 )
2002-06-29 11:59:09 +00:00
{
m_fPositionOffsetFromSelection -= fSpinSpeed * fDeltaTime ;
if ( m_fPositionOffsetFromSelection < 0 )
m_fPositionOffsetFromSelection = 0 ;
}
2002-06-24 22:04:31 +00:00
else if ( m_fPositionOffsetFromSelection < 0 )
2002-06-29 11:59:09 +00:00
{
m_fPositionOffsetFromSelection += fSpinSpeed * fDeltaTime ;
if ( m_fPositionOffsetFromSelection > 0 )
m_fPositionOffsetFromSelection = 0 ;
}
2002-01-20 08:59:38 +00:00
}
2002-01-16 10:01:32 +00:00
}
2003-01-21 07:04:53 +00:00
void MusicWheel :: ChangeMusic ( int dist )
2002-01-16 10:01:32 +00:00
{
2003-01-21 07:04:53 +00:00
m_iSelection += dist ;
2003-01-02 02:59:25 +00:00
if ( m_iSelection < 0 )
m_iSelection = m_CurWheelItemData . size () - 1 ;
2003-01-21 07:04:53 +00:00
else if ( m_iSelection > int ( m_CurWheelItemData . size () - 1 ) )
2003-01-02 02:59:25 +00:00
m_iSelection = 0 ;
2003-03-31 23:06:15 +00:00
RebuildMusicWheelItems ();
2002-01-16 10:01:32 +00:00
2003-01-21 07:04:53 +00:00
m_fPositionOffsetFromSelection += dist ;
2002-06-30 23:19:33 +00:00
2003-03-25 21:17:29 +00:00
SCREENMAN -> PostMessageToTopScreen ( SM_SongChanged , 0 );
2003-01-21 07:04:53 +00:00
/* If we're moving automatically, don't play this; it'll be called in Update. */
if ( ! IsMoving ())
m_soundChangeMusic . Play ();
2002-01-16 10:01:32 +00:00
}
2003-06-16 17:28:58 +00:00
bool MusicWheel :: ChangeSort ( SongSortOrder new_so ) // return true if change successful
2002-01-16 10:01:32 +00:00
{
2003-07-20 08:54:31 +00:00
ASSERT ( new_so < NUM_SORT_ORDERS );
2003-06-19 19:31:46 +00:00
if ( GAMESTATE -> m_SongSortOrder == new_so )
return false ;
2002-01-18 22:18:41 +00:00
switch ( m_WheelState )
{
2002-06-24 22:04:31 +00:00
case STATE_SELECTING_MUSIC :
2002-01-24 08:01:24 +00:00
case STATE_FLYING_ON_AFTER_NEXT_SORT :
2002-01-18 22:18:41 +00:00
break ; // fall through
default :
2002-08-20 21:00:56 +00:00
return false ; // don't continue
2002-01-18 22:18:41 +00:00
}
2002-01-16 10:01:32 +00:00
2003-07-20 08:54:31 +00:00
SCREENMAN -> PostMessageToTopScreen ( SM_SortOrderChanging , 0 );
2002-04-28 20:42:32 +00:00
m_soundChangeSort . Play ();
2002-01-16 10:01:32 +00:00
2003-01-02 02:59:25 +00:00
TweenOffScreen ( true );
2002-05-28 20:01:22 +00:00
2003-06-16 17:28:58 +00:00
m_LastSongSortOrder = GAMESTATE -> m_SongSortOrder ;
GAMESTATE -> m_SongSortOrder = new_so ;
2002-01-18 21:19:05 +00:00
m_WheelState = STATE_FLYING_OFF_BEFORE_NEXT_SORT ;
2002-08-20 21:00:56 +00:00
return true ;
2002-01-16 10:01:32 +00:00
}
2003-06-16 17:28:58 +00:00
bool MusicWheel :: NextSort () // return true if change successful
{
2003-06-30 06:53:21 +00:00
/* Is the current sort in the default sort order? */
int cur = 0 ;
while ( SortOrder [ cur ] != SORT_INVALID && SortOrder [ cur ] != GAMESTATE -> m_SongSortOrder )
++ cur ;
2003-06-16 17:28:58 +00:00
2003-06-30 06:53:21 +00:00
SongSortOrder so ;
if ( SortOrder [ cur ] == SORT_INVALID )
{
/* It isn't, which means we're either in the sort menu or in a sort selected
* from the sort menu. If we're in the sort menu, return to the first sort.
* Otherwise, return to the sort menu. */
2003-07-20 08:54:31 +00:00
if ( GAMESTATE -> m_SongSortOrder == SORT_MENU )
2003-06-30 06:53:21 +00:00
so = SortOrder [ 0 ];
else
2003-07-20 08:54:31 +00:00
so = SORT_MENU ;
2003-06-30 06:53:21 +00:00
} else {
++ cur ;
if ( SortOrder [ cur ] == SORT_INVALID )
cur = 0 ;
so = SortOrder [ cur ];
}
2003-06-16 17:28:58 +00:00
return ChangeSort ( so );
}
bool MusicWheel :: Select () // return true if this selection ends the screen
2002-01-16 10:01:32 +00:00
{
2002-07-31 19:40:40 +00:00
LOG -> Trace ( "MusicWheel::Select()" );
2002-06-24 22:04:31 +00:00
2003-01-03 03:24:00 +00:00
if ( m_WheelState == STATE_ROULETTE_SLOWING_DOWN )
return false ;
2003-01-22 01:30:07 +00:00
m_Moving = 0 ;
2002-06-14 22:25:22 +00:00
if ( m_WheelState == STATE_ROULETTE_SPINNING )
{
m_WheelState = STATE_ROULETTE_SLOWING_DOWN ;
2002-08-13 23:26:46 +00:00
m_iSwitchesLeftInSpinDown = ROULETTE_SLOW_DOWN_SWITCHES / 2 + 1 + rand () % ( ROULETTE_SLOW_DOWN_SWITCHES / 2 );
2002-06-24 22:04:31 +00:00
m_fTimeLeftInState = 0.1f ;
2002-06-14 22:25:22 +00:00
return false ;
}
2003-01-22 01:30:07 +00:00
2003-01-19 00:47:06 +00:00
if ( m_WheelState == STATE_RANDOM_SPINNING )
{
m_fPositionOffsetFromSelection = max ( m_fPositionOffsetFromSelection , 0.3f );
m_WheelState = STATE_LOCKED ;
m_soundStart . Play ();
m_fLockedWheelVelocity = 0 ;
2003-03-25 21:17:29 +00:00
SCREENMAN -> PostMessageToTopScreen ( SM_SongChanged , 0 );
2003-01-19 00:47:06 +00:00
return false ;
}
2003-03-31 23:06:15 +00:00
switch ( m_CurWheelItemData [ m_iSelection ] -> m_Type )
2002-01-16 10:01:32 +00:00
{
2002-02-09 04:30:27 +00:00
case TYPE_SECTION :
2002-01-16 10:01:32 +00:00
{
2003-06-16 17:28:58 +00:00
CString sThisItemSectionName = m_CurWheelItemData [ m_iSelection ] -> m_sSectionName ;
if ( m_sExpandedSectionName == sThisItemSectionName ) // already expanded
m_sExpandedSectionName = "" ; // collapse it
else // already collapsed
m_sExpandedSectionName = sThisItemSectionName ; // expand it
2002-01-16 10:01:32 +00:00
2003-06-16 17:28:58 +00:00
m_soundExpand . Play ();
2002-01-16 10:01:32 +00:00
2003-06-16 17:28:58 +00:00
SetOpenGroup ( m_sExpandedSectionName );
2002-01-16 10:01:32 +00:00
}
return false ;
2003-07-09 11:38:50 +00:00
case TYPE_ROULETTE :
2002-08-20 21:00:56 +00:00
StartRoulette ();
2002-05-19 01:59:48 +00:00
return false ;
2003-01-03 03:24:00 +00:00
case TYPE_RANDOM :
2003-01-19 00:47:06 +00:00
StartRandom ();
2003-01-03 03:24:00 +00:00
return false ;
2002-04-16 17:31:00 +00:00
case TYPE_SONG :
2003-07-18 08:04:47 +00:00
GAMESTATE -> m_pUnlockingSys -> RouletteUnlock ( m_CurWheelItemData [ m_iSelection ] -> m_pSong );
2003-07-09 11:38:50 +00:00
// fall-through - we want to check for unlocking only if its a song
2003-06-16 17:28:58 +00:00
case TYPE_COURSE :
2002-01-16 10:01:32 +00:00
return true ;
2003-06-16 17:28:58 +00:00
case TYPE_SORT :
2003-07-20 08:54:31 +00:00
m_CurWheelItemData [ m_iSelection ] -> m_Action . ApplyToAllPlayers ();
2003-06-16 17:28:58 +00:00
ChangeSort ( m_CurWheelItemData [ m_iSelection ] -> m_SongSortOrder );
return false ;
default :
ASSERT ( 0 );
return false ;
2002-01-16 10:01:32 +00:00
}
}
2002-08-20 21:00:56 +00:00
void MusicWheel :: StartRoulette ()
{
m_WheelState = STATE_ROULETTE_SPINNING ;
2003-01-02 02:59:25 +00:00
m_Moving = 1 ;
m_TimeBeforeMovingBegins = 0 ;
m_SpinSpeed = 1.0f / ROULETTE_SWITCH_SECONDS ;
2003-01-03 03:24:00 +00:00
SetOpenGroup ( "" , SongSortOrder ( SORT_ROULETTE ));
2002-08-20 21:00:56 +00:00
}
2003-01-19 00:47:06 +00:00
void MusicWheel :: StartRandom ()
{
/* Shuffle the roulette wheel. */
unsigned total = m_WheelItemDatas [ SORT_ROULETTE ]. size ();
for ( unsigned i = 0 ; i < total ; ++ i )
swap ( m_WheelItemDatas [ SORT_ROULETTE ][ i ], m_WheelItemDatas [ SORT_ROULETTE ][ rand () % total ]);
SetOpenGroup ( "" , SongSortOrder ( SORT_ROULETTE ));
m_Moving = - 1 ;
m_TimeBeforeMovingBegins = 0 ;
m_SpinSpeed = 1.0f / ROULETTE_SWITCH_SECONDS ;
2003-02-12 06:25:51 +00:00
m_SpinSpeed *= 20.0f ; /* faster! */
2003-01-19 00:47:06 +00:00
m_WheelState = STATE_RANDOM_SPINNING ;
2003-02-12 06:25:51 +00:00
this -> Select ();
2003-03-31 23:06:15 +00:00
RebuildMusicWheelItems ();
2003-01-19 00:47:06 +00:00
}
2003-01-03 03:24:00 +00:00
void MusicWheel :: SetOpenGroup ( CString group , SongSortOrder so )
2002-08-20 21:00:56 +00:00
{
2003-06-16 17:28:58 +00:00
if ( so == SORT_INVALID )
2003-01-03 03:24:00 +00:00
so = GAMESTATE -> m_SongSortOrder ;
2003-01-02 02:59:25 +00:00
m_sExpandedSectionName = group ;
WheelItemData * old = NULL ;
if ( ! m_CurWheelItemData . empty ())
old = m_CurWheelItemData [ m_iSelection ];
m_CurWheelItemData . clear ();
2003-01-03 03:24:00 +00:00
vector < WheelItemData > & from = m_WheelItemDatas [ so ];
2003-01-02 02:59:25 +00:00
unsigned i ;
for ( i = 0 ; i < from . size (); ++ i )
{
2003-03-31 23:06:15 +00:00
if (( from [ i ]. m_Type == TYPE_SONG ||
from [ i ]. m_Type == TYPE_COURSE ) &&
2003-01-02 02:59:25 +00:00
! from [ i ]. m_sSectionName . empty () &&
from [ i ]. m_sSectionName != group )
continue ;
m_CurWheelItemData . push_back ( & from [ i ]);
}
2003-06-16 17:28:58 +00:00
//
// Try to select the item that was selected before chaning groups
//
2003-01-02 02:59:25 +00:00
m_iSelection = 0 ;
2003-06-16 17:28:58 +00:00
for ( i = 0 ; i < m_CurWheelItemData . size (); i ++ )
2003-01-02 02:59:25 +00:00
{
2003-06-16 17:28:58 +00:00
if ( m_CurWheelItemData [ i ] == old )
{
2003-01-02 02:59:25 +00:00
m_iSelection = i ;
2003-06-16 17:28:58 +00:00
break ;
}
2003-01-02 02:59:25 +00:00
}
2003-01-03 03:24:00 +00:00
2003-03-31 23:06:15 +00:00
RebuildMusicWheelItems ();
2002-08-20 21:00:56 +00:00
}
2003-01-02 02:59:25 +00:00
bool MusicWheel :: IsRouletting () const
2002-02-09 04:30:27 +00:00
{
2003-01-03 03:24:00 +00:00
return m_WheelState == STATE_ROULETTE_SPINNING || m_WheelState == STATE_ROULETTE_SLOWING_DOWN ||
m_WheelState == STATE_RANDOM_SPINNING ;
2003-01-02 02:59:25 +00:00
}
int MusicWheel :: IsMoving () const
{
2003-01-21 07:04:53 +00:00
return m_Moving && m_TimeBeforeMovingBegins == 0 ;
2003-01-02 02:59:25 +00:00
}
void MusicWheel :: TweenOnScreen ( bool changing_sort )
{
float factor = 1.0f ;
if ( changing_sort ) factor = 0.25 ;
2002-02-07 02:16:14 +00:00
m_WheelState = STATE_TWEENING_ON_SCREEN ;
2002-05-28 20:01:22 +00:00
2003-04-02 04:41:49 +00:00
float fX , fY , fZ , fRotationX ;
GetItemPosition ( 0 , fX , fY , fZ , fRotationX );
2002-05-29 09:47:24 +00:00
2002-08-13 23:26:46 +00:00
m_sprSelectionOverlay . SetXY ( fX + 320 , fY );
2003-04-02 04:41:49 +00:00
m_sprSelectionOverlay . SetZ ( fZ );
m_sprSelectionOverlay . SetRotationX ( fRotationX );
2003-01-02 02:59:25 +00:00
if ( changing_sort ) {
2003-03-26 19:15:38 +00:00
m_sprSelectionOverlay . BeginTweening ( 0.04f * NUM_WHEEL_ITEMS / 2 * factor ); // sleep
2003-03-02 01:43:33 +00:00
m_sprSelectionOverlay . BeginTweening ( 0.2f * factor , Actor :: TWEEN_ACCELERATE );
2003-01-02 02:59:25 +00:00
} else {
m_sprSelectionOverlay . BeginTweening ( 0.05f * factor ); // sleep
2003-03-02 01:43:33 +00:00
m_sprSelectionOverlay . BeginTweening ( 0.4f * factor , Actor :: TWEEN_ACCELERATE );
2003-01-02 02:59:25 +00:00
}
2003-04-12 06:16:12 +00:00
m_sprSelectionOverlay . SetX ( fX );
2002-05-29 09:47:24 +00:00
2002-08-31 06:43:28 +00:00
m_ScrollBar . SetX ( SCROLL_BAR_X + 30 );
2003-01-02 02:59:25 +00:00
if ( changing_sort )
m_ScrollBar . BeginTweening ( 0.2f * factor ); // sleep
else
m_ScrollBar . BeginTweening ( 0.7f * factor ); // sleep
2003-03-02 01:43:33 +00:00
m_ScrollBar . BeginTweening ( 0.2f * factor , Actor :: TWEEN_ACCELERATE );
2003-04-12 06:16:12 +00:00
m_ScrollBar . SetX ( SCROLL_BAR_X );
2002-05-28 20:01:22 +00:00
2003-03-26 19:15:38 +00:00
for ( int i = 0 ; i < NUM_WHEEL_ITEMS ; i ++ )
2002-05-28 20:01:22 +00:00
{
2003-03-31 23:06:15 +00:00
MusicWheelItem & display = m_MusicWheelItems [ i ];
2003-03-26 19:15:38 +00:00
float fThisBannerPositionOffsetFromSelection = i - NUM_WHEEL_ITEMS / 2 + m_fPositionOffsetFromSelection ;
2002-05-28 20:01:22 +00:00
2003-04-02 04:41:49 +00:00
float fX , fY , fZ , fRotationX ;
GetItemPosition ( fThisBannerPositionOffsetFromSelection , fX , fY , fZ , fRotationX );
2002-05-28 20:01:22 +00:00
display . SetXY ( fX + 320 , fY );
2003-04-02 04:41:49 +00:00
display . SetZ ( fZ );
display . SetRotationX ( fRotationX );
2003-01-02 02:59:25 +00:00
display . BeginTweening ( 0.04f * i * factor ); // sleep
2003-03-02 01:43:33 +00:00
display . BeginTweening ( 0.2f * factor , Actor :: TWEEN_ACCELERATE );
2003-04-12 06:16:12 +00:00
display . SetX ( fX );
2002-05-28 20:01:22 +00:00
}
2003-01-02 02:59:25 +00:00
2003-03-02 01:43:33 +00:00
m_fTimeLeftInState = GetTweenTimeLeft () + 0.100f ;
2002-02-07 02:16:14 +00:00
}
2003-01-02 02:59:25 +00:00
void MusicWheel :: TweenOffScreen ( bool changing_sort )
2002-02-09 04:30:27 +00:00
{
2003-01-02 02:59:25 +00:00
float factor = 1.0f ;
if ( changing_sort ) factor = 0.25 ;
2002-05-28 20:01:22 +00:00
2003-01-02 02:59:25 +00:00
m_WheelState = STATE_TWEENING_OFF_SCREEN ;
2002-05-28 20:01:22 +00:00
2003-04-02 04:41:49 +00:00
float fX , fY , fZ , fRotationX ;
GetItemPosition ( 0 , fX , fY , fZ , fRotationX );
2002-08-13 23:26:46 +00:00
m_sprSelectionOverlay . SetXY ( fX , fY );
2003-04-02 04:41:49 +00:00
m_sprSelectionOverlay . SetZ ( fZ );
m_sprSelectionOverlay . SetRotationX ( fRotationX );
2003-01-02 02:59:25 +00:00
if ( changing_sort ) {
/* When changing sort, tween the overlay with the item in the center;
* having it separate looks messy when we're moving fast. */
2003-03-26 19:15:38 +00:00
m_sprSelectionOverlay . BeginTweening ( 0.04f * NUM_WHEEL_ITEMS / 2 * factor ); // sleep
2003-03-02 01:43:33 +00:00
m_sprSelectionOverlay . BeginTweening ( 0.2f * factor , Actor :: TWEEN_DECELERATE );
2003-01-02 02:59:25 +00:00
} else {
m_sprSelectionOverlay . BeginTweening ( 0 ); // sleep
2003-03-02 01:43:33 +00:00
m_sprSelectionOverlay . BeginTweening ( 0.2f * factor , Actor :: TWEEN_DECELERATE );
2003-01-02 02:59:25 +00:00
}
2003-04-12 06:16:12 +00:00
m_sprSelectionOverlay . SetX ( fX + 320 );
2002-05-29 09:47:24 +00:00
2002-09-02 21:59:58 +00:00
m_ScrollBar . BeginTweening ( 0 );
2003-03-02 01:43:33 +00:00
m_ScrollBar . BeginTweening ( 0.2f * factor , Actor :: TWEEN_ACCELERATE );
2003-04-12 06:16:12 +00:00
m_ScrollBar . SetX ( SCROLL_BAR_X + 30 );
2002-05-28 20:01:22 +00:00
2003-03-26 19:15:38 +00:00
for ( int i = 0 ; i < NUM_WHEEL_ITEMS ; i ++ )
2002-05-28 20:01:22 +00:00
{
2003-03-31 23:06:15 +00:00
MusicWheelItem & display = m_MusicWheelItems [ i ];
2003-03-26 19:15:38 +00:00
float fThisBannerPositionOffsetFromSelection = i - NUM_WHEEL_ITEMS / 2 + m_fPositionOffsetFromSelection ;
2002-05-28 20:01:22 +00:00
2003-04-02 04:41:49 +00:00
float fX , fY , fZ , fRotationX ;
GetItemPosition ( fThisBannerPositionOffsetFromSelection , fX , fY , fZ , fRotationX );
2002-05-28 20:01:22 +00:00
display . SetXY ( fX , fY );
2003-04-02 04:41:49 +00:00
display . SetZ ( fZ );
display . SetRotationX ( fRotationX );
2003-01-02 02:59:25 +00:00
display . BeginTweening ( 0.04f * i * factor ); // sleep
2003-03-02 01:43:33 +00:00
display . BeginTweening ( 0.2f * factor , Actor :: TWEEN_DECELERATE );
2003-04-12 06:16:12 +00:00
display . SetX ( fX + 320 );
2002-05-28 20:01:22 +00:00
}
2003-03-02 01:43:33 +00:00
m_fTimeLeftInState = GetTweenTimeLeft () + 0.100f ;
2002-06-24 22:04:31 +00:00
}
2002-12-30 21:57:54 +00:00
2003-02-11 23:52:18 +00:00
CString MusicWheel :: GetSectionNameFromSongAndSort ( const Song * pSong , SongSortOrder so )
2002-12-30 21:57:54 +00:00
{
if ( pSong == NULL )
return "" ;
switch ( so )
{
2003-06-16 20:23:07 +00:00
case SORT_PREFERRED :
return "" ;
2002-12-30 21:57:54 +00:00
case SORT_GROUP :
2003-06-16 20:23:07 +00:00
return pSong -> m_sGroupName ;
2002-12-30 21:57:54 +00:00
case SORT_TITLE :
2003-06-16 20:23:07 +00:00
case SORT_ARTIST :
{
CString s ;
switch ( so )
{
case SORT_TITLE : s = pSong -> GetTranslitMainTitle (); break ;
2003-06-19 05:30:01 +00:00
case SORT_ARTIST : s = pSong -> GetTranslitArtist (); break ;
2003-06-16 20:23:07 +00:00
default : ASSERT ( 0 );
}
s = MakeSortString ( s ); // resulting string will be uppercase
if ( s . empty () )
return "" ;
else if ( s [ 0 ] >= '0' && s [ 0 ] <= '9' )
return "NUM" ;
else if ( s [ 0 ] < 'A' || s [ 0 ] > 'Z' )
return "OTHER" ;
else
return s . Left ( 1 );
}
2002-12-30 21:57:54 +00:00
case SORT_BPM :
2003-06-16 17:28:58 +00:00
{
const int iBPMGroupSize = 20 ;
float fMinBPM , fMaxBPM ;
pSong -> GetDisplayBPM ( fMinBPM , fMaxBPM );
int iMaxBPM = ( int ) fMaxBPM ;
2003-06-19 05:30:01 +00:00
iMaxBPM += iBPMGroupSize - ( iMaxBPM % iBPMGroupSize ) - 1 ;
2003-06-16 17:28:58 +00:00
return ssprintf ( "%03d-%03d" , iMaxBPM - ( iBPMGroupSize - 1 ), iMaxBPM );
}
2002-12-30 21:57:54 +00:00
case SORT_MOST_PLAYED :
2003-06-16 20:23:07 +00:00
return "" ;
case SORT_GRADE :
{
for ( int i = NUM_GRADES ; i > GRADE_NO_DATA ; i -- )
{
Grade g = ( Grade ) i ;
int iCount = pSong -> GetNumNotesWithGrade ( g );
if ( iCount > 0 )
return ssprintf ( "%4s x %d" , GradeToString ( g ). c_str (), iCount );
}
return "NO DATA" ;
}
2003-06-27 08:06:22 +00:00
case SORT_EASY_METER :
{
Notes * pNotes = pSong -> GetNotes ( GAMESTATE -> GetCurrentStyleDef () -> m_NotesType , DIFFICULTY_EASY );
if ( pNotes )
return ssprintf ( "%02d" , pNotes -> GetMeter () );
return "N/A" ;
}
case SORT_MEDIUM_METER :
{
Notes * pNotes = pSong -> GetNotes ( GAMESTATE -> GetCurrentStyleDef () -> m_NotesType , DIFFICULTY_MEDIUM );
if ( pNotes )
return ssprintf ( "%02d" , pNotes -> GetMeter () );
return "N/A" ;
}
case SORT_HARD_METER :
{
Notes * pNotes = pSong -> GetNotes ( GAMESTATE -> GetCurrentStyleDef () -> m_NotesType , DIFFICULTY_HARD );
if ( pNotes )
return ssprintf ( "%02d" , pNotes -> GetMeter () );
return "N/A" ;
}
2003-07-20 08:54:31 +00:00
case SORT_MENU :
2003-06-16 20:23:07 +00:00
return "" ;
2003-07-20 08:54:31 +00:00
case SORT_ALL_COURSES :
case SORT_NONSTOP_COURSES :
case SORT_ONI_COURSES :
case SORT_ENDLESS_COURSES :
2002-12-30 21:57:54 +00:00
default :
2003-06-16 20:23:07 +00:00
ASSERT ( 0 );
2002-12-30 21:57:54 +00:00
return "" ;
}
}
2002-12-30 22:40:34 +00:00
2003-01-02 02:59:25 +00:00
void MusicWheel :: Move ( int n )
2002-12-30 22:40:34 +00:00
{
2003-01-02 02:59:25 +00:00
if ( n == m_Moving )
return ;
2002-12-30 22:40:34 +00:00
2003-01-21 07:04:53 +00:00
if ( m_WheelState == STATE_LOCKED )
{
if ( n )
{
2003-03-24 21:37:13 +00:00
int iSign = n / abs ( n );
m_fLockedWheelVelocity = iSign * LOCKED_INITIAL_VELOCITY ;
2003-01-21 07:04:53 +00:00
m_soundLocked . Play ();
}
return ;
}
2002-12-30 22:40:34 +00:00
2003-01-21 07:04:53 +00:00
/* If we're not selecting, discard this. We won't ignore it; we'll
* get called again every time the key is repeated. */
if ( m_WheelState != STATE_SELECTING_MUSIC )
return ;
if ( m_Moving != 0 && n == 0 && m_TimeBeforeMovingBegins == 0 )
{
/* We were moving, and now we're stopping. If we're really close to
* the selection, move to the next one, so we have a chance to spin down
* smoothly. */
if ( fabsf ( m_fPositionOffsetFromSelection ) < 0.25f )
ChangeMusic ( m_Moving );
/* Make sure the user always gets an SM_SongChanged when
* Moving() is 0, so the final banner, etc. always gets set. */
2003-03-25 21:17:29 +00:00
SCREENMAN -> PostMessageToTopScreen ( SM_SongChanged , 0 );
2003-01-21 07:04:53 +00:00
}
2003-01-02 02:59:25 +00:00
m_TimeBeforeMovingBegins = TIME_BEFORE_SLOW_REPEATS ;
2003-01-21 07:04:53 +00:00
m_SpinSpeed = float ( PREFSMAN -> m_iMusicWheelSwitchSpeed );
2003-01-02 02:59:25 +00:00
m_Moving = n ;
2003-01-21 07:04:53 +00:00
if ( fabsf ( m_fPositionOffsetFromSelection ) > 0.5f ) // wheel is very busy spinning
return ;
if ( m_Moving )
ChangeMusic ( m_Moving );
2002-12-30 22:40:34 +00:00
}