Adds Dual List Mode to ScreenSelectMaster. This allows for themers to maintain two separate lists depending on number of players joined. Overcomes some problems such as wanting the list to only contain selectable items if using a scroller. Untested with icon cursor and needs optimising still.
This commit is contained in:
@@ -120,6 +120,12 @@ IdleTimeoutSeconds=30
|
||||
IdleTimeoutScreen=THEME:GetMetric("Common","FirstAttractScreen")
|
||||
OutDelay=.2
|
||||
DoublePressToSelect=false
|
||||
UseTwoLists=false
|
||||
OptionOrderBUp=""
|
||||
OptionOrderBDown=""
|
||||
OptionOrderBLeft=""
|
||||
OptionOrderBRight=""
|
||||
OptionOrderBAuto=""
|
||||
|
||||
[ScreenExit]
|
||||
Class="ScreenExit"
|
||||
@@ -130,6 +136,13 @@ AllowOperatorMenuButton=false
|
||||
Class="ScreenTitleMenu"
|
||||
Fallback="ScreenTitleMenu"
|
||||
ChoiceNames="1"
|
||||
ChoiceNamesB=""
|
||||
OptionOrderBUp=""
|
||||
OptionOrderBDown=""
|
||||
OptionOrderBLeft=""
|
||||
OptionOrderBRight=""
|
||||
OptionOrderBAuto=""
|
||||
|
||||
|
||||
[ScreenCaution]
|
||||
Fallback="ScreenSplash"
|
||||
@@ -209,6 +222,13 @@ ExplanationPage2Y=0
|
||||
HeaderOnCommand=
|
||||
HeaderOffCommand=
|
||||
DoublePressToSelect=false
|
||||
UseTwoLists=false
|
||||
ChoiceNamesB=""
|
||||
OptionOrderBUp=""
|
||||
OptionOrderBDown=""
|
||||
OptionOrderBLeft=""
|
||||
OptionOrderBRight=""
|
||||
OptionOrderBAuto=""
|
||||
|
||||
[ScreenSelectPlayMode]
|
||||
Fallback="ScreenWithMenuElements"
|
||||
@@ -266,6 +286,12 @@ ExplanationPage2Y=0
|
||||
HeaderOnCommand=
|
||||
HeaderOffCommand=
|
||||
DoublePressToSelect=false
|
||||
OptionOrderBUp=
|
||||
OptionOrderBDown=
|
||||
OptionOrderBLeft=
|
||||
OptionOrderBRight=
|
||||
OptionOrderBAuto=
|
||||
UseTwoLists=
|
||||
|
||||
[ScreenSelectMode]
|
||||
Fallback="ScreenSelect"
|
||||
@@ -2656,6 +2682,7 @@ DisabledColor=#606060
|
||||
|
||||
DoublePressToSelect=false
|
||||
|
||||
|
||||
# Blank defaults for a few options.
|
||||
IconChoice1SwitchToPage1Command=
|
||||
IconChoice1SwitchToPage2Command=
|
||||
@@ -2946,7 +2973,7 @@ Unlock0020X=SCREEN_CENTER_X-70
|
||||
Unlock0020Y=SCREEN_CENTER_Y+85
|
||||
DancePointsZoom=2
|
||||
|
||||
[ScreenHighScores]
|
||||
[ScreenHighScores]http://clickingandscreaming.com/2009/05/01/youtube-and-bullying-cause-or-solution/
|
||||
Fallback="ScreenAttract"
|
||||
Class="ScreenHighScores"
|
||||
TimerSeconds=-1
|
||||
|
||||
+117
-13
@@ -13,6 +13,10 @@
|
||||
#define CHOICE( s ) THEME->GetMetric (m_sName,ssprintf("Choice%s",s.c_str()))
|
||||
#define IDLE_TIMEOUT_SCREEN THEME->GetMetric (m_sName,"IdleTimeoutScreen")
|
||||
#define UPDATE_ON_MESSAGE THEME->GetMetric (m_sName,"UpdateOnMessage")
|
||||
#define USE_TWO_LISTS THEME->GetMetricB (m_sName,"UseTwoLists")
|
||||
|
||||
#define CHOICE_NAMESB THEME->GetMetric (m_sName,"ChoiceNamesB")
|
||||
#define CHOICEB( s ) THEME->GetMetric (m_sName,ssprintf("ChoiceB%s",s.c_str()))
|
||||
|
||||
void ScreenSelect::Init()
|
||||
{
|
||||
@@ -54,16 +58,55 @@ void ScreenSelect::Init()
|
||||
mc.Load( c, cmd );
|
||||
m_aGameCommands.push_back( mc );
|
||||
}
|
||||
|
||||
m_iSelectedList = 0;
|
||||
if(USE_TWO_LISTS)
|
||||
{
|
||||
m_bUsingTwoLists = true;
|
||||
vector<RString> asChoiceNames2;
|
||||
split( CHOICE_NAMESB, ",", asChoiceNames2, true );
|
||||
|
||||
for( unsigned c=0; c<asChoiceNames2.size(); c++ )
|
||||
{
|
||||
RString sChoiceName = asChoiceNames2[c];
|
||||
|
||||
GameCommand mc;
|
||||
mc.ApplyCommitsScreens( false );
|
||||
mc.m_sName = sChoiceName;
|
||||
Commands cmd = ParseCommands( CHOICEB(sChoiceName) );
|
||||
mc.Load( c, cmd );
|
||||
m_aGameCommandsB.push_back( mc );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bUsingTwoLists = false;
|
||||
}
|
||||
}
|
||||
|
||||
if( !m_aGameCommands.size() )
|
||||
RageException::Throw( "Screen \"%s\" does not set any choices.", m_sName.c_str() );
|
||||
|
||||
if(USE_TWO_LISTS)
|
||||
{
|
||||
if(!m_aGameCommandsB.size() )
|
||||
RageException::Throw ("Screen \"%s\" has specified two lists, but does not set any choices for the second list.",m_sName.c_str() );
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenSelect::BeginScreen()
|
||||
{
|
||||
ScreenWithMenuElements::BeginScreen();
|
||||
|
||||
if(USE_TWO_LISTS)
|
||||
{
|
||||
if( GAMESTATE->GetNumSidesJoined() > 1 )
|
||||
{
|
||||
m_iSelectedList = 1;
|
||||
this->UpdateSelectableChoices();
|
||||
}
|
||||
}
|
||||
|
||||
m_timerIdleComment.GetDeltaTime();
|
||||
m_timerIdleTimeout.GetDeltaTime();
|
||||
}
|
||||
@@ -111,11 +154,20 @@ void ScreenSelect::Input( const InputEventPlus &input )
|
||||
|
||||
if( input.MenuI == GAME_BUTTON_START && input.type == IET_FIRST_PRESS && GAMESTATE->JoinInput(input.pn) )
|
||||
{
|
||||
// HACK: Only play start sound for the 2nd player who joins. The
|
||||
// start sound for the 1st player will be played by ScreenTitleMenu
|
||||
// when the player makes a selection on the screen.
|
||||
if( GAMESTATE->GetNumSidesJoined() > 1 )
|
||||
{
|
||||
if(USE_TWO_LISTS)
|
||||
{
|
||||
m_iSelectedList = 1;
|
||||
this->UpdateSelectableChoices();
|
||||
}
|
||||
|
||||
|
||||
// HACK: Only play start sound for the 2nd player who joins. The
|
||||
// start sound for the 1st player will be played by ScreenTitleMenu
|
||||
// when the player makes a selection on the screen.
|
||||
SCREENMAN->PlayStartSound();
|
||||
}
|
||||
|
||||
if( !ALLOW_DISABLED_PLAYER_INPUT )
|
||||
return; // don't let the screen handle the MENU_START press
|
||||
@@ -162,20 +214,72 @@ void ScreenSelect::HandleScreenMessage( const ScreenMessage SM )
|
||||
|
||||
if( bAllPlayersChoseTheSame )
|
||||
{
|
||||
const GameCommand &gc = m_aGameCommands[iMastersIndex];
|
||||
m_sNextScreen = gc.m_sScreen;
|
||||
if( !gc.m_bInvalid )
|
||||
gc.ApplyToAllPlayers();
|
||||
if(USE_TWO_LISTS) // using two lists
|
||||
{
|
||||
if(m_iSelectedList == 0) // first list is selected
|
||||
{
|
||||
const GameCommand &gc = m_aGameCommands[iMastersIndex];
|
||||
|
||||
m_sNextScreen = gc.m_sScreen;
|
||||
if( !gc.m_bInvalid )
|
||||
gc.ApplyToAllPlayers();
|
||||
}
|
||||
else // second list is selected
|
||||
{
|
||||
const GameCommand &gc = m_aGameCommandsB[iMastersIndex];
|
||||
|
||||
m_sNextScreen = gc.m_sScreen;
|
||||
if( !gc.m_bInvalid )
|
||||
gc.ApplyToAllPlayers();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else // not using two lists
|
||||
{
|
||||
const GameCommand &gc = m_aGameCommands[iMastersIndex];
|
||||
m_sNextScreen = gc.m_sScreen;
|
||||
if( !gc.m_bInvalid )
|
||||
gc.ApplyToAllPlayers();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FOREACH_HumanPlayer( p )
|
||||
if(USE_TWO_LISTS) // using two lists
|
||||
{
|
||||
int iIndex = this->GetSelectionIndex(p);
|
||||
const GameCommand &gc = m_aGameCommands[iIndex];
|
||||
m_sNextScreen = gc.m_sScreen;
|
||||
if( !gc.m_bInvalid )
|
||||
gc.Apply( p );
|
||||
if(m_iSelectedList == 0) // first list is selected
|
||||
{
|
||||
FOREACH_HumanPlayer( p )
|
||||
{
|
||||
int iIndex = this->GetSelectionIndex(p);
|
||||
const GameCommand &gc = m_aGameCommands[iIndex];
|
||||
m_sNextScreen = gc.m_sScreen;
|
||||
if( !gc.m_bInvalid )
|
||||
gc.Apply( p );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FOREACH_HumanPlayer( p )
|
||||
{
|
||||
int iIndex = this->GetSelectionIndex(p);
|
||||
const GameCommand &gc = m_aGameCommandsB[iIndex];
|
||||
m_sNextScreen = gc.m_sScreen;
|
||||
if( !gc.m_bInvalid )
|
||||
gc.Apply( p );
|
||||
}
|
||||
}
|
||||
}
|
||||
else // only using a single list
|
||||
{
|
||||
FOREACH_HumanPlayer( p )
|
||||
{
|
||||
int iIndex = this->GetSelectionIndex(p);
|
||||
const GameCommand &gc = m_aGameCommands[iIndex];
|
||||
m_sNextScreen = gc.m_sScreen;
|
||||
if( !gc.m_bInvalid )
|
||||
gc.Apply( p );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,11 @@ protected:
|
||||
virtual int GetSelectionIndex( PlayerNumber pn ) = 0;
|
||||
virtual void UpdateSelectableChoices() = 0; // derived screens must handle this
|
||||
|
||||
unsigned int m_iSelectedList;
|
||||
bool m_bUsingTwoLists;
|
||||
|
||||
vector<GameCommand> m_aGameCommands; // derived classes should look here for what choices are available
|
||||
vector<GameCommand> m_aGameCommandsB; // only used if the theme requires a second list
|
||||
|
||||
vector<RString> m_asSubscribedMessages;
|
||||
|
||||
|
||||
@@ -29,6 +29,9 @@ static RString CURSOR_OFFSET_Y_FROM_ICON_NAME( size_t p ) { return ssprintf("Cur
|
||||
/* e.g. "OptionOrderLeft=0:1,1:2,2:3,3:4" */
|
||||
static RString OPTION_ORDER_NAME( size_t dir ) { return "OptionOrder"+MenuDirToString((MenuDir)dir); }
|
||||
|
||||
static RString OPTION_ORDER_NAME_LIST2( size_t dir ) { return "OptionOrderB"+MenuDirToString((MenuDir)dir); }
|
||||
|
||||
|
||||
REGISTER_SCREEN_CLASS( ScreenSelectMaster );
|
||||
|
||||
#define GetActiveElementPlayerNumbers( vpns ) \
|
||||
@@ -60,6 +63,10 @@ void ScreenSelectMaster::Init()
|
||||
PRE_SWITCH_PAGE_SECONDS.Load( m_sName, "PreSwitchPageSeconds" );
|
||||
POST_SWITCH_PAGE_SECONDS.Load( m_sName, "PostSwitchPageSeconds" );
|
||||
OPTION_ORDER.Load( m_sName, OPTION_ORDER_NAME, NUM_MenuDir );
|
||||
|
||||
OPTION_ORDER2.Load( m_sName, OPTION_ORDER_NAME_LIST2, NUM_MenuDir );
|
||||
|
||||
|
||||
WRAP_CURSOR.Load( m_sName, "WrapCursor" );
|
||||
WRAP_SCROLLER.Load( m_sName, "WrapScroller" );
|
||||
LOOP_SCROLLER.Load( m_sName, "LoopScroller" );
|
||||
@@ -102,7 +109,6 @@ void ScreenSelectMaster::Init()
|
||||
FOREACH( PlayerNumber, vpns, p )
|
||||
m_vsprScroll[*p].resize( m_aGameCommands.size() );
|
||||
|
||||
|
||||
for( unsigned c=0; c<m_aGameCommands.size(); c++ )
|
||||
{
|
||||
GameCommand& mc = m_aGameCommands[c];
|
||||
@@ -148,6 +154,125 @@ void ScreenSelectMaster::Init()
|
||||
}
|
||||
}
|
||||
|
||||
// using two lists, load the stuff for the 2nd one
|
||||
if(m_bUsingTwoLists)
|
||||
{
|
||||
// Resize vectors depending on how many choices there are
|
||||
m_vsprIconB.resize( m_aGameCommandsB.size() );
|
||||
FOREACH( PlayerNumber, vpns, p )
|
||||
m_vsprScrollB[*p].resize( m_aGameCommandsB.size() );
|
||||
|
||||
for( unsigned c=0; c<m_aGameCommandsB.size(); c++ )
|
||||
{
|
||||
GameCommand& mc = m_aGameCommandsB[c];
|
||||
|
||||
LuaThreadVariable var( "GameCommand", LuaReference::Create(&mc) );
|
||||
|
||||
// init icon
|
||||
if( SHOW_ICON )
|
||||
{
|
||||
vector<RString> vs;
|
||||
vs.push_back( "List2 Icon" );
|
||||
if( PER_CHOICE_ICON_ELEMENT )
|
||||
vs.push_back( "List2 Choice" + mc.m_sName );
|
||||
RString sElement = join( " ", vs );
|
||||
m_vsprIconB[c].Load( THEME->GetPathG(m_sName,sElement) );
|
||||
RString sName = "List2 Icon" "List2 Choice" + mc.m_sName;
|
||||
m_vsprIconB[c]->SetName( sName );
|
||||
if( USE_ICON_METRICS )
|
||||
LOAD_ALL_COMMANDS_AND_SET_XY( m_vsprIconB[c] );
|
||||
this->AddChild( m_vsprIconB[c] );
|
||||
}
|
||||
|
||||
// init scroll
|
||||
if( SHOW_SCROLLER )
|
||||
{
|
||||
FOREACH( PlayerNumber, vpns, p )
|
||||
{
|
||||
vector<RString> vs;
|
||||
vs.push_back( "List2 Scroll" );
|
||||
if( PER_CHOICE_SCROLL_ELEMENT )
|
||||
vs.push_back( "List2 Choice" + mc.m_sName );
|
||||
if( !SHARED_SELECTION )
|
||||
vs.push_back( PLAYER_APPEND_NO_SPACE(*p) );
|
||||
RString sElement = join( " ", vs );
|
||||
m_vsprScrollB[*p][c].Load( THEME->GetPathG(m_sName,sElement) );
|
||||
RString sName = "List2 Scroll" "List2 Choice" + mc.m_sName;
|
||||
if( !SHARED_SELECTION )
|
||||
sName += PLAYER_APPEND_NO_SPACE(*p);
|
||||
m_vsprScrollB[*p][c]->SetName( sName );
|
||||
m_ScrollerB[*p].AddChild( m_vsprScrollB[*p][c] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// init scroll
|
||||
if( SHOW_SCROLLER )
|
||||
{
|
||||
FOREACH( PlayerNumber, vpns, p )
|
||||
{
|
||||
m_ScrollerB[*p].SetLoop( LOOP_SCROLLER );
|
||||
m_ScrollerB[*p].SetNumItemsToDraw( SCROLLER_NUM_ITEMS_TO_DRAW );
|
||||
m_ScrollerB[*p].Load2();
|
||||
m_ScrollerB[*p].SetTransformFromReference( SCROLLER_TRANSFORM );
|
||||
m_ScrollerB[*p].SetSecondsPerItem( SCROLLER_SECONDS_PER_ITEM );
|
||||
m_ScrollerB[*p].SetNumSubdivisions( SCROLLER_SUBDIVISIONS );
|
||||
m_ScrollerB[*p].SetName( "Scroller"+PLAYER_APPEND_NO_SPACE(*p) );
|
||||
LOAD_ALL_COMMANDS_AND_SET_XY( m_ScrollerB[*p] );
|
||||
this->AddChild( &m_ScrollerB[*p] );
|
||||
}
|
||||
}
|
||||
|
||||
FOREACH_MenuDir( dir )
|
||||
{
|
||||
const RString order = OPTION_ORDER2.GetValue( dir );
|
||||
vector<RString> parts;
|
||||
split( order, ",", parts, true );
|
||||
|
||||
for( unsigned part = 0; part < parts.size(); ++part )
|
||||
{
|
||||
int from, to;
|
||||
if( sscanf( parts[part], "%d:%d", &from, &to ) != 2 )
|
||||
{
|
||||
LOG->Warn( "%s::OptionOrderB%s parse error", m_sName.c_str(), MenuDirToString(dir).c_str() );
|
||||
continue;
|
||||
}
|
||||
|
||||
--from;
|
||||
--to;
|
||||
|
||||
m_mapCurrentChoiceToNextChoiceB[dir][from] = to;
|
||||
}
|
||||
|
||||
if( m_mapCurrentChoiceToNextChoiceB[dir].empty() ) // Didn't specify any mappings
|
||||
{
|
||||
// Fill with reasonable defaults
|
||||
for( unsigned c = 0; c < m_aGameCommandsB.size(); ++c )
|
||||
{
|
||||
int add;
|
||||
switch( dir )
|
||||
{
|
||||
case MenuDir_Up:
|
||||
case MenuDir_Left:
|
||||
add = -1;
|
||||
break;
|
||||
default:
|
||||
add = +1;
|
||||
break;
|
||||
}
|
||||
|
||||
m_mapCurrentChoiceToNextChoiceB[dir][c] = c + add;
|
||||
/* Always wrap around MenuDir_Auto. */
|
||||
if( dir == MenuDir_Auto || (bool)WRAP_CURSOR )
|
||||
wrap( m_mapCurrentChoiceToNextChoiceB[dir][c], m_aGameCommandsB.size() );
|
||||
else
|
||||
m_mapCurrentChoiceToNextChoiceB[dir][c] = clamp( m_mapCurrentChoiceToNextChoiceB[dir][c], 0, (int)m_aGameCommandsB.size()-1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
} // end of list2 init
|
||||
|
||||
|
||||
// init scroll
|
||||
if( SHOW_SCROLLER )
|
||||
{
|
||||
@@ -331,8 +456,8 @@ void ScreenSelectMaster::HandleScreenMessage( const ScreenMessage SM )
|
||||
MenuStart( iep );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int ScreenSelectMaster::GetSelectionIndex( PlayerNumber pn )
|
||||
@@ -345,15 +470,62 @@ void ScreenSelectMaster::UpdateSelectableChoices()
|
||||
vector<PlayerNumber> vpns;
|
||||
GetActiveElementPlayerNumbers( vpns );
|
||||
|
||||
|
||||
for( unsigned c=0; c<m_aGameCommands.size(); c++ )
|
||||
if(m_bUsingTwoLists && m_iSelectedList == 1) // using two lists and on the 2nd list
|
||||
{
|
||||
if( SHOW_ICON )
|
||||
m_vsprIcon[c]->PlayCommand( m_aGameCommands[c].IsPlayable()? "Enabled":"Disabled" );
|
||||
|
||||
FOREACH( PlayerNumber, vpns, p )
|
||||
if( m_vsprScroll[*p][c].IsLoaded() )
|
||||
m_vsprScroll[*p][c]->PlayCommand( m_aGameCommands[c].IsPlayable()? "Enabled":"Disabled" );
|
||||
for( unsigned c=0; c<m_aGameCommands.size(); c++ )
|
||||
{
|
||||
if( SHOW_ICON )
|
||||
{
|
||||
m_vsprIcon[c]->PlayCommand( "List2Enabled" );
|
||||
}
|
||||
|
||||
FOREACH( PlayerNumber, vpns, p )
|
||||
if( m_vsprScroll[*p][c].IsLoaded() )
|
||||
{
|
||||
m_vsprScroll[*p][c]->PlayCommand( "List2Enabled" );
|
||||
}
|
||||
}
|
||||
|
||||
for( unsigned c=0; c<m_aGameCommandsB.size(); c++ )
|
||||
{
|
||||
if( SHOW_ICON )
|
||||
{
|
||||
m_vsprIconB[c]->PlayCommand( "List2Enabled" );
|
||||
m_vsprIconB[c]->PlayCommand( m_aGameCommandsB[c].IsPlayable()? "Enabled":"Disabled" );
|
||||
|
||||
// we will make element 0 the new selection, so it will gain focus
|
||||
if(c==0)
|
||||
m_vsprIconB[c]->PlayCommand( "GainFocus" );
|
||||
else // everything else loses focus
|
||||
m_vsprIconB[c]->PlayCommand( "LoseFocus" );
|
||||
}
|
||||
|
||||
FOREACH( PlayerNumber, vpns, p )
|
||||
if( m_vsprScrollB[*p][c].IsLoaded() )
|
||||
{
|
||||
m_vsprScrollB[*p][c]->PlayCommand( "List2Enabled" );
|
||||
m_vsprScrollB[*p][c]->PlayCommand( m_aGameCommandsB[c].IsPlayable()? "Enabled":"Disabled" );
|
||||
|
||||
if(c==0)
|
||||
m_vsprScrollB[*p][c]->PlayCommand( "GainFocus" );
|
||||
else // everything else loses focus
|
||||
m_vsprScrollB[*p][c]->PlayCommand( "LoseFocus" );
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
for( unsigned c=0; c<m_aGameCommands.size(); c++ )
|
||||
{
|
||||
if( SHOW_ICON )
|
||||
m_vsprIcon[c]->PlayCommand( m_aGameCommands[c].IsPlayable()? "Enabled":"Disabled" );
|
||||
|
||||
FOREACH( PlayerNumber, vpns, p )
|
||||
if( m_vsprScroll[*p][c].IsLoaded() )
|
||||
m_vsprScroll[*p][c]->PlayCommand( m_aGameCommands[c].IsPlayable()? "Enabled":"Disabled" );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -363,15 +535,36 @@ void ScreenSelectMaster::UpdateSelectableChoices()
|
||||
* If any options are playable, make sure one is selected.
|
||||
*/
|
||||
FOREACH_HumanPlayer( p )
|
||||
if( !m_aGameCommands[m_iChoice[p]].IsPlayable() )
|
||||
Move( p, MenuDir_Auto );
|
||||
{
|
||||
if(m_bUsingTwoLists && m_iSelectedList == 1)
|
||||
{
|
||||
m_iChoice[p] = 0; // reset their choice position since we are moving to the new list
|
||||
if( !m_aGameCommandsB[m_iChoice[p]].IsPlayable() )
|
||||
Move( p, MenuDir_Auto );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !m_aGameCommands[m_iChoice[p]].IsPlayable() )
|
||||
Move( p, MenuDir_Auto );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ScreenSelectMaster::AnyOptionsArePlayable() const
|
||||
{
|
||||
for( unsigned i = 0; i < m_aGameCommands.size(); ++i )
|
||||
if( m_aGameCommands[i].IsPlayable() )
|
||||
return true;
|
||||
// if they're using the second list
|
||||
if(m_bUsingTwoLists && m_iSelectedList == 1)
|
||||
{
|
||||
for( unsigned i = 0; i < m_aGameCommandsB.size(); ++i )
|
||||
if( m_aGameCommandsB[i].IsPlayable() )
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
for( unsigned i = 0; i < m_aGameCommands.size(); ++i )
|
||||
if( m_aGameCommands[i].IsPlayable() )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -384,18 +577,38 @@ bool ScreenSelectMaster::Move( PlayerNumber pn, MenuDir dir )
|
||||
int iSwitchToIndex = m_iChoice[pn];
|
||||
set<int> seen;
|
||||
try_again:
|
||||
map<int,int>::const_iterator iter = m_mapCurrentChoiceToNextChoice[dir].find( iSwitchToIndex );
|
||||
if( iter != m_mapCurrentChoiceToNextChoice[dir].end() )
|
||||
iSwitchToIndex = iter->second;
|
||||
|
||||
if( iSwitchToIndex < 0 || iSwitchToIndex >= (int) m_aGameCommands.size() ) // out of choice range
|
||||
return false; // can't go that way
|
||||
if( seen.find(iSwitchToIndex) != seen.end() )
|
||||
return false; // went full circle and none found
|
||||
seen.insert( iSwitchToIndex );
|
||||
// moving list 2
|
||||
if(m_bUsingTwoLists && m_iSelectedList == 1)
|
||||
{
|
||||
map<int,int>::const_iterator iter = m_mapCurrentChoiceToNextChoiceB[dir].find( iSwitchToIndex );
|
||||
if( iter != m_mapCurrentChoiceToNextChoiceB[dir].end() )
|
||||
iSwitchToIndex = iter->second;
|
||||
|
||||
if( !m_aGameCommands[iSwitchToIndex].IsPlayable() )
|
||||
goto try_again;
|
||||
if( iSwitchToIndex < 0 || iSwitchToIndex >= (int) m_aGameCommandsB.size() ) // out of choice range
|
||||
return false; // can't go that way
|
||||
if( seen.find(iSwitchToIndex) != seen.end() )
|
||||
return false; // went full circle and none found
|
||||
seen.insert( iSwitchToIndex );
|
||||
|
||||
if( !m_aGameCommandsB[iSwitchToIndex].IsPlayable() )
|
||||
goto try_again;
|
||||
}
|
||||
else
|
||||
{
|
||||
map<int,int>::const_iterator iter = m_mapCurrentChoiceToNextChoice[dir].find( iSwitchToIndex );
|
||||
if( iter != m_mapCurrentChoiceToNextChoice[dir].end() )
|
||||
iSwitchToIndex = iter->second;
|
||||
|
||||
if( iSwitchToIndex < 0 || iSwitchToIndex >= (int) m_aGameCommands.size() ) // out of choice range
|
||||
return false; // can't go that way
|
||||
if( seen.find(iSwitchToIndex) != seen.end() )
|
||||
return false; // went full circle and none found
|
||||
seen.insert( iSwitchToIndex );
|
||||
|
||||
if( !m_aGameCommands[iSwitchToIndex].IsPlayable() )
|
||||
goto try_again;
|
||||
}
|
||||
|
||||
return ChangeSelection( pn, dir, iSwitchToIndex );
|
||||
}
|
||||
@@ -624,16 +837,75 @@ bool ScreenSelectMaster::ChangeSelection( PlayerNumber pn, MenuDir dir, int iNew
|
||||
bNewAlreadyHadFocus |= m_iChoice[p2] == iNewChoice;
|
||||
}
|
||||
|
||||
|
||||
//todo: condense this section
|
||||
if(DOUBLE_PRESS_TO_SELECT)
|
||||
{
|
||||
// this player is currently on a single press, which they are cancelling
|
||||
if(m_bDoubleChoice[pn])
|
||||
if(m_bUsingTwoLists && m_iSelectedList == 1)
|
||||
{
|
||||
// this player is currently on a single press, which they are cancelling
|
||||
if(m_bDoubleChoice[pn])
|
||||
{
|
||||
if( !bOldStillHasFocus )
|
||||
m_vsprIconB[iOldChoice]->PlayCommand( "LostSelectedLoseFocus" );
|
||||
if( !bNewAlreadyHadFocus )
|
||||
m_vsprIconB[iNewChoice]->PlayCommand( "LostSelectedGainFocus" );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !bOldStillHasFocus )
|
||||
m_vsprIconB[iOldChoice]->PlayCommand( "LoseFocus" );
|
||||
if( !bNewAlreadyHadFocus )
|
||||
m_vsprIconB[iNewChoice]->PlayCommand( "GainFocus" );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(m_bUsingTwoLists && m_iSelectedList == 1)
|
||||
{
|
||||
// this player is currently on a single press, which they are cancelling
|
||||
if(m_bDoubleChoice[pn])
|
||||
{
|
||||
if( !bOldStillHasFocus )
|
||||
m_vsprIcon[iOldChoice]->PlayCommand( "LostSelectedLoseFocus" );
|
||||
if( !bNewAlreadyHadFocus )
|
||||
m_vsprIcon[iNewChoice]->PlayCommand( "LostSelectedGainFocus" );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !bOldStillHasFocus )
|
||||
m_vsprIcon[iOldChoice]->PlayCommand( "LoseFocus" );
|
||||
if( !bNewAlreadyHadFocus )
|
||||
m_vsprIcon[iNewChoice]->PlayCommand( "GainFocus" );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// this player is currently on a single press, which they are cancelling
|
||||
if(m_bDoubleChoice[pn])
|
||||
{
|
||||
if( !bOldStillHasFocus )
|
||||
m_vsprIcon[iOldChoice]->PlayCommand( "LostSelectedLoseFocus" );
|
||||
if( !bNewAlreadyHadFocus )
|
||||
m_vsprIcon[iNewChoice]->PlayCommand( "LostSelectedGainFocus" );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !bOldStillHasFocus )
|
||||
m_vsprIcon[iOldChoice]->PlayCommand( "LoseFocus" );
|
||||
if( !bNewAlreadyHadFocus )
|
||||
m_vsprIcon[iNewChoice]->PlayCommand( "GainFocus" );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else // not using double selection
|
||||
{
|
||||
if(m_bUsingTwoLists && m_iSelectedList == 1)
|
||||
{
|
||||
if( !bOldStillHasFocus )
|
||||
m_vsprIcon[iOldChoice]->PlayCommand( "LoseFocus" );
|
||||
m_vsprIconB[iOldChoice]->PlayCommand( "LoseFocus" );
|
||||
if( !bNewAlreadyHadFocus )
|
||||
m_vsprIcon[iNewChoice]->PlayCommand( "GainFocus" );
|
||||
m_vsprIconB[iNewChoice]->PlayCommand( "GainFocus" );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -643,14 +915,6 @@ bool ScreenSelectMaster::ChangeSelection( PlayerNumber pn, MenuDir dir, int iNew
|
||||
m_vsprIcon[iNewChoice]->PlayCommand( "GainFocus" );
|
||||
}
|
||||
}
|
||||
else // not using double selection
|
||||
{
|
||||
|
||||
if( !bOldStillHasFocus )
|
||||
m_vsprIcon[iOldChoice]->PlayCommand( "LostSelectedLoseFocus" );
|
||||
if( !bNewAlreadyHadFocus )
|
||||
m_vsprIcon[iNewChoice]->PlayCommand( "LostSelectedGainFocus" );
|
||||
}
|
||||
}
|
||||
|
||||
if( SHOW_CURSOR )
|
||||
@@ -661,26 +925,51 @@ bool ScreenSelectMaster::ChangeSelection( PlayerNumber pn, MenuDir dir, int iNew
|
||||
|
||||
if( SHOW_SCROLLER )
|
||||
{
|
||||
ActorScroller &scroller = SHARED_SELECTION ? m_Scroller[0] : m_Scroller[*p];
|
||||
vector<AutoActor> &vScroll = SHARED_SELECTION ? m_vsprScroll[0] : m_vsprScroll[*p];
|
||||
if( WRAP_SCROLLER )
|
||||
|
||||
ActorScroller &scroller = (m_bUsingTwoLists && m_iSelectedList == 1)?(SHARED_SELECTION ? m_ScrollerB[0] : m_ScrollerB[*p]):(SHARED_SELECTION ? m_Scroller[0] : m_Scroller[*p]);
|
||||
vector<AutoActor> &vScroll = (m_bUsingTwoLists && m_iSelectedList == 1)?(SHARED_SELECTION ? m_vsprScrollB[0] : m_vsprScrollB[*p]):(SHARED_SELECTION ? m_vsprScroll[0] : m_vsprScroll[*p]);
|
||||
|
||||
// second list
|
||||
if(m_bUsingTwoLists && m_iSelectedList == 1)
|
||||
{
|
||||
// HACK: We can't tell from the option orders whether or not we wrapped.
|
||||
// For now, assume that the order is increasing left to right.
|
||||
int iPressedDir = (dir == MenuDir_Left) ? -1 : +1;
|
||||
int iActualDir = (iOldChoice < iNewChoice) ? +1 : -1;
|
||||
|
||||
if( iPressedDir != iActualDir ) // wrapped
|
||||
if( WRAP_SCROLLER )
|
||||
{
|
||||
float fItem = scroller.GetCurrentItem();
|
||||
int iNumChoices = m_aGameCommands.size();
|
||||
fItem += iActualDir * iNumChoices;
|
||||
scroller.SetCurrentAndDestinationItem( fItem );
|
||||
}
|
||||
}
|
||||
// HACK: We can't tell from the option orders whether or not we wrapped.
|
||||
// For now, assume that the order is increasing left to right.
|
||||
int iPressedDir = (dir == MenuDir_Left) ? -1 : +1;
|
||||
int iActualDir = (iOldChoice < iNewChoice) ? +1 : -1;
|
||||
|
||||
scroller.SetDestinationItem( (float)iNewChoice );
|
||||
|
||||
if( iPressedDir != iActualDir ) // wrapped
|
||||
{
|
||||
float fItem = scroller.GetCurrentItem();
|
||||
int iNumChoices = m_aGameCommandsB.size();
|
||||
fItem += iActualDir * iNumChoices;
|
||||
scroller.SetCurrentAndDestinationItem( fItem );
|
||||
}
|
||||
}
|
||||
|
||||
scroller.SetDestinationItem( (float)iNewChoice );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( WRAP_SCROLLER )
|
||||
{
|
||||
// HACK: We can't tell from the option orders whether or not we wrapped.
|
||||
// For now, assume that the order is increasing left to right.
|
||||
int iPressedDir = (dir == MenuDir_Left) ? -1 : +1;
|
||||
int iActualDir = (iOldChoice < iNewChoice) ? +1 : -1;
|
||||
|
||||
if( iPressedDir != iActualDir ) // wrapped
|
||||
{
|
||||
float fItem = scroller.GetCurrentItem();
|
||||
int iNumChoices = m_aGameCommands.size();
|
||||
fItem += iActualDir * iNumChoices;
|
||||
scroller.SetCurrentAndDestinationItem( fItem );
|
||||
}
|
||||
}
|
||||
|
||||
scroller.SetDestinationItem( (float)iNewChoice );
|
||||
}
|
||||
// using double selections
|
||||
if(DOUBLE_PRESS_TO_SELECT)
|
||||
{
|
||||
@@ -783,15 +1072,23 @@ void ScreenSelectMaster::MenuStart( const InputEventPlus &input )
|
||||
|
||||
if(SHOW_SCROLLER)
|
||||
{
|
||||
vector<AutoActor> &vScroll = SHARED_SELECTION ? m_vsprScroll[0] : m_vsprScroll[pn];
|
||||
vScroll[m_iChoice[pn]]->PlayCommand( "InitialSelection" );
|
||||
if(m_bUsingTwoLists && m_iSelectedList == 1)
|
||||
{
|
||||
vector<AutoActor> &vScroll = SHARED_SELECTION ? m_vsprScrollB[0] : m_vsprScrollB[pn];
|
||||
vScroll[m_iChoice[pn]]->PlayCommand( "InitialSelection" );
|
||||
}
|
||||
else
|
||||
{
|
||||
vector<AutoActor> &vScroll = SHARED_SELECTION ? m_vsprScroll[0] : m_vsprScroll[pn];
|
||||
vScroll[m_iChoice[pn]]->PlayCommand( "InitialSelection" );
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const GameCommand &mc = m_aGameCommands[m_iChoice[pn]];
|
||||
const GameCommand &mc = (m_bUsingTwoLists && m_iSelectedList == 1)?m_aGameCommandsB[m_iChoice[pn]]:m_aGameCommands[m_iChoice[pn]];
|
||||
|
||||
/* If no options are playable, then we're just waiting for one to become available.
|
||||
* If any options are playable, then the selection must be playable. */
|
||||
@@ -852,26 +1149,55 @@ void ScreenSelectMaster::TweenOnScreen()
|
||||
|
||||
if( SHOW_ICON )
|
||||
{
|
||||
for( unsigned c=0; c<m_aGameCommands.size(); c++ )
|
||||
if(m_bUsingTwoLists && m_iSelectedList == 1)
|
||||
{
|
||||
m_vsprIcon[c]->PlayCommand( (int(c) == m_iChoice[0])? "GainFocus":"LoseFocus" );
|
||||
m_vsprIcon[c]->FinishTweening();
|
||||
for( unsigned c=0; c<m_aGameCommandsB.size(); c++ )
|
||||
{
|
||||
m_vsprIconB[c]->PlayCommand( (int(c) == m_iChoice[0])? "GainFocus":"LoseFocus" );
|
||||
m_vsprIconB[c]->FinishTweening();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( unsigned c=0; c<m_aGameCommands.size(); c++ )
|
||||
{
|
||||
m_vsprIcon[c]->PlayCommand( (int(c) == m_iChoice[0])? "GainFocus":"LoseFocus" );
|
||||
m_vsprIcon[c]->FinishTweening();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( SHOW_SCROLLER )
|
||||
{
|
||||
FOREACH( PlayerNumber, vpns, p )
|
||||
if(m_bUsingTwoLists && m_iSelectedList == 1)
|
||||
{
|
||||
// Play Gain/LoseFocus before playing the on command. Gain/Lose will
|
||||
// often stop tweening, which ruins the OnCommand.
|
||||
for( unsigned c=0; c<m_aGameCommands.size(); c++ )
|
||||
FOREACH( PlayerNumber, vpns, p )
|
||||
{
|
||||
m_vsprScroll[*p][c]->PlayCommand( int(c) == m_iChoice[*p]? "GainFocus":"LoseFocus" );
|
||||
m_vsprScroll[*p][c]->FinishTweening();
|
||||
}
|
||||
// Play Gain/LoseFocus before playing the on command. Gain/Lose will
|
||||
// often stop tweening, which ruins the OnCommand.
|
||||
for( unsigned c=0; c<m_aGameCommands.size(); c++ )
|
||||
{
|
||||
m_vsprScrollB[*p][c]->PlayCommand( int(c) == m_iChoice[*p]? "GainFocus":"LoseFocus" );
|
||||
m_vsprScrollB[*p][c]->FinishTweening();
|
||||
}
|
||||
|
||||
m_Scroller[*p].SetCurrentAndDestinationItem( (float)m_iChoice[*p] );
|
||||
m_ScrollerB[*p].SetCurrentAndDestinationItem( (float)m_iChoice[*p] );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FOREACH( PlayerNumber, vpns, p )
|
||||
{
|
||||
// Play Gain/LoseFocus before playing the on command. Gain/Lose will
|
||||
// often stop tweening, which ruins the OnCommand.
|
||||
for( unsigned c=0; c<m_aGameCommands.size(); c++ )
|
||||
{
|
||||
m_vsprScroll[*p][c]->PlayCommand( int(c) == m_iChoice[*p]? "GainFocus":"LoseFocus" );
|
||||
m_vsprScroll[*p][c]->FinishTweening();
|
||||
}
|
||||
|
||||
m_Scroller[*p].SetCurrentAndDestinationItem( (float)m_iChoice[*p] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -894,25 +1220,54 @@ void ScreenSelectMaster::TweenOffScreen()
|
||||
vector<PlayerNumber> vpns;
|
||||
GetActiveElementPlayerNumbers( vpns );
|
||||
|
||||
for( unsigned c=0; c<m_aGameCommands.size(); c++ )
|
||||
// using two lists -- may need to consider throwing a wider range of commands
|
||||
// for themers if tweening out with one/two lists/focussed/not focussed etc?
|
||||
if(m_bUsingTwoLists && m_iSelectedList == 1)
|
||||
{
|
||||
if( GetPage(c) != GetCurrentPage() )
|
||||
continue; // skip
|
||||
|
||||
bool bSelectedByEitherPlayer = false;
|
||||
FOREACH( PlayerNumber, vpns, p )
|
||||
for( unsigned c=0; c<m_aGameCommandsB.size(); c++ )
|
||||
{
|
||||
if( m_iChoice[*p] == (int)c )
|
||||
bSelectedByEitherPlayer = true;
|
||||
}
|
||||
if( GetPage(c) != GetCurrentPage() )
|
||||
continue; // skip
|
||||
|
||||
if( SHOW_ICON )
|
||||
m_vsprIcon[c]->PlayCommand( bSelectedByEitherPlayer? "OffFocused":"OffUnfocused" );
|
||||
|
||||
if( SHOW_SCROLLER )
|
||||
{
|
||||
bool bSelectedByEitherPlayer = false;
|
||||
FOREACH( PlayerNumber, vpns, p )
|
||||
m_vsprScroll[*p][c]->PlayCommand( bSelectedByEitherPlayer? "OffFocused":"OffUnfocused" );
|
||||
{
|
||||
if( m_iChoice[*p] == (int)c )
|
||||
bSelectedByEitherPlayer = true;
|
||||
}
|
||||
|
||||
if( SHOW_ICON )
|
||||
m_vsprIconB[c]->PlayCommand( bSelectedByEitherPlayer? "OffFocused":"OffUnfocused" );
|
||||
|
||||
if( SHOW_SCROLLER )
|
||||
{
|
||||
FOREACH( PlayerNumber, vpns, p )
|
||||
m_vsprScrollB[*p][c]->PlayCommand( bSelectedByEitherPlayer? "OffFocused":"OffUnfocused" );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( unsigned c=0; c<m_aGameCommands.size(); c++ )
|
||||
{
|
||||
if( GetPage(c) != GetCurrentPage() )
|
||||
continue; // skip
|
||||
|
||||
bool bSelectedByEitherPlayer = false;
|
||||
FOREACH( PlayerNumber, vpns, p )
|
||||
{
|
||||
if( m_iChoice[*p] == (int)c )
|
||||
bSelectedByEitherPlayer = true;
|
||||
}
|
||||
|
||||
if( SHOW_ICON )
|
||||
m_vsprIcon[c]->PlayCommand( bSelectedByEitherPlayer? "OffFocused":"OffUnfocused" );
|
||||
|
||||
if( SHOW_SCROLLER )
|
||||
{
|
||||
FOREACH( PlayerNumber, vpns, p )
|
||||
m_vsprScroll[*p][c]->PlayCommand( bSelectedByEitherPlayer? "OffFocused":"OffUnfocused" );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ class ScreenSelectMaster : public ScreenSelect
|
||||
{
|
||||
public:
|
||||
ScreenSelectMaster();
|
||||
//~ScreenSelectMaster();
|
||||
virtual void Init();
|
||||
virtual RString GetDefaultChoice();
|
||||
virtual void BeginScreen();
|
||||
@@ -44,6 +45,7 @@ protected:
|
||||
Page GetPage( int iChoiceIndex ) const;
|
||||
Page GetCurrentPage() const;
|
||||
|
||||
ThemeMetric<bool> USE_TWO_SCROLLERS;
|
||||
ThemeMetric<bool> DOUBLE_PRESS_TO_SELECT;
|
||||
ThemeMetric<bool> SHOW_ICON;
|
||||
ThemeMetric<bool> SHOW_SCROLLER;
|
||||
@@ -57,6 +59,7 @@ protected:
|
||||
ThemeMetric<float> PRE_SWITCH_PAGE_SECONDS;
|
||||
ThemeMetric<float> POST_SWITCH_PAGE_SECONDS;
|
||||
ThemeMetric1D<RString> OPTION_ORDER;
|
||||
ThemeMetric1D<RString> OPTION_ORDER2;
|
||||
ThemeMetric<bool> WRAP_CURSOR;
|
||||
ThemeMetric<bool> WRAP_SCROLLER;
|
||||
ThemeMetric<bool> LOOP_SCROLLER;
|
||||
@@ -69,6 +72,8 @@ protected:
|
||||
ThemeMetric<RString> DEFAULT_CHOICE;
|
||||
|
||||
map<int,int> m_mapCurrentChoiceToNextChoice[NUM_MenuDir];
|
||||
map<int,int> m_mapCurrentChoiceToNextChoiceB[NUM_MenuDir]; // if using two lists
|
||||
|
||||
|
||||
virtual int GetSelectionIndex( PlayerNumber pn );
|
||||
virtual void UpdateSelectableChoices();
|
||||
@@ -87,9 +92,17 @@ protected:
|
||||
AutoActor m_sprMore[NUM_Page];
|
||||
// icon is the shared, per-choice piece
|
||||
vector<AutoActor> m_vsprIcon;
|
||||
vector<AutoActor> m_vsprIconB; // used if the user wants two lists
|
||||
|
||||
// preview is per-player, per-choice piece
|
||||
vector<AutoActor> m_vsprScroll[NUM_PLAYERS];
|
||||
vector<AutoActor> m_vsprScrollB[NUM_PLAYERS]; // used if the user wants two lists
|
||||
|
||||
|
||||
ActorScroller m_Scroller[NUM_PLAYERS];
|
||||
ActorScroller m_ScrollerB[NUM_PLAYERS]; // used if the user wants two lists
|
||||
|
||||
|
||||
// cursor is the per-player, shared by all choices
|
||||
AutoActor m_sprCursor[NUM_PLAYERS];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user