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:
Andrew Livy
2009-05-02 15:30:04 +00:00
parent a84e00a39f
commit 2e8dc57f3d
5 changed files with 601 additions and 98 deletions
+28 -1
View File
@@ -120,6 +120,12 @@ IdleTimeoutSeconds=30
IdleTimeoutScreen=THEME:GetMetric("Common","FirstAttractScreen") IdleTimeoutScreen=THEME:GetMetric("Common","FirstAttractScreen")
OutDelay=.2 OutDelay=.2
DoublePressToSelect=false DoublePressToSelect=false
UseTwoLists=false
OptionOrderBUp=""
OptionOrderBDown=""
OptionOrderBLeft=""
OptionOrderBRight=""
OptionOrderBAuto=""
[ScreenExit] [ScreenExit]
Class="ScreenExit" Class="ScreenExit"
@@ -130,6 +136,13 @@ AllowOperatorMenuButton=false
Class="ScreenTitleMenu" Class="ScreenTitleMenu"
Fallback="ScreenTitleMenu" Fallback="ScreenTitleMenu"
ChoiceNames="1" ChoiceNames="1"
ChoiceNamesB=""
OptionOrderBUp=""
OptionOrderBDown=""
OptionOrderBLeft=""
OptionOrderBRight=""
OptionOrderBAuto=""
[ScreenCaution] [ScreenCaution]
Fallback="ScreenSplash" Fallback="ScreenSplash"
@@ -209,6 +222,13 @@ ExplanationPage2Y=0
HeaderOnCommand= HeaderOnCommand=
HeaderOffCommand= HeaderOffCommand=
DoublePressToSelect=false DoublePressToSelect=false
UseTwoLists=false
ChoiceNamesB=""
OptionOrderBUp=""
OptionOrderBDown=""
OptionOrderBLeft=""
OptionOrderBRight=""
OptionOrderBAuto=""
[ScreenSelectPlayMode] [ScreenSelectPlayMode]
Fallback="ScreenWithMenuElements" Fallback="ScreenWithMenuElements"
@@ -266,6 +286,12 @@ ExplanationPage2Y=0
HeaderOnCommand= HeaderOnCommand=
HeaderOffCommand= HeaderOffCommand=
DoublePressToSelect=false DoublePressToSelect=false
OptionOrderBUp=
OptionOrderBDown=
OptionOrderBLeft=
OptionOrderBRight=
OptionOrderBAuto=
UseTwoLists=
[ScreenSelectMode] [ScreenSelectMode]
Fallback="ScreenSelect" Fallback="ScreenSelect"
@@ -2656,6 +2682,7 @@ DisabledColor=#606060
DoublePressToSelect=false DoublePressToSelect=false
# Blank defaults for a few options. # Blank defaults for a few options.
IconChoice1SwitchToPage1Command= IconChoice1SwitchToPage1Command=
IconChoice1SwitchToPage2Command= IconChoice1SwitchToPage2Command=
@@ -2946,7 +2973,7 @@ Unlock0020X=SCREEN_CENTER_X-70
Unlock0020Y=SCREEN_CENTER_Y+85 Unlock0020Y=SCREEN_CENTER_Y+85
DancePointsZoom=2 DancePointsZoom=2
[ScreenHighScores] [ScreenHighScores]http://clickingandscreaming.com/2009/05/01/youtube-and-bullying-cause-or-solution/
Fallback="ScreenAttract" Fallback="ScreenAttract"
Class="ScreenHighScores" Class="ScreenHighScores"
TimerSeconds=-1 TimerSeconds=-1
+117 -13
View File
@@ -13,6 +13,10 @@
#define CHOICE( s ) THEME->GetMetric (m_sName,ssprintf("Choice%s",s.c_str())) #define CHOICE( s ) THEME->GetMetric (m_sName,ssprintf("Choice%s",s.c_str()))
#define IDLE_TIMEOUT_SCREEN THEME->GetMetric (m_sName,"IdleTimeoutScreen") #define IDLE_TIMEOUT_SCREEN THEME->GetMetric (m_sName,"IdleTimeoutScreen")
#define UPDATE_ON_MESSAGE THEME->GetMetric (m_sName,"UpdateOnMessage") #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() void ScreenSelect::Init()
{ {
@@ -54,16 +58,55 @@ void ScreenSelect::Init()
mc.Load( c, cmd ); mc.Load( c, cmd );
m_aGameCommands.push_back( mc ); 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() ) if( !m_aGameCommands.size() )
RageException::Throw( "Screen \"%s\" does not set any choices.", m_sName.c_str() ); 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() void ScreenSelect::BeginScreen()
{ {
ScreenWithMenuElements::BeginScreen(); ScreenWithMenuElements::BeginScreen();
if(USE_TWO_LISTS)
{
if( GAMESTATE->GetNumSidesJoined() > 1 )
{
m_iSelectedList = 1;
this->UpdateSelectableChoices();
}
}
m_timerIdleComment.GetDeltaTime(); m_timerIdleComment.GetDeltaTime();
m_timerIdleTimeout.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) ) 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( 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(); SCREENMAN->PlayStartSound();
}
if( !ALLOW_DISABLED_PLAYER_INPUT ) if( !ALLOW_DISABLED_PLAYER_INPUT )
return; // don't let the screen handle the MENU_START press return; // don't let the screen handle the MENU_START press
@@ -162,20 +214,72 @@ void ScreenSelect::HandleScreenMessage( const ScreenMessage SM )
if( bAllPlayersChoseTheSame ) if( bAllPlayersChoseTheSame )
{ {
const GameCommand &gc = m_aGameCommands[iMastersIndex]; if(USE_TWO_LISTS) // using two lists
m_sNextScreen = gc.m_sScreen; {
if( !gc.m_bInvalid ) if(m_iSelectedList == 0) // first list is selected
gc.ApplyToAllPlayers(); {
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 else
{ {
FOREACH_HumanPlayer( p ) if(USE_TWO_LISTS) // using two lists
{ {
int iIndex = this->GetSelectionIndex(p); if(m_iSelectedList == 0) // first list is selected
const GameCommand &gc = m_aGameCommands[iIndex]; {
m_sNextScreen = gc.m_sScreen; FOREACH_HumanPlayer( p )
if( !gc.m_bInvalid ) {
gc.Apply( 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 );
}
} }
} }
+4
View File
@@ -25,7 +25,11 @@ protected:
virtual int GetSelectionIndex( PlayerNumber pn ) = 0; virtual int GetSelectionIndex( PlayerNumber pn ) = 0;
virtual void UpdateSelectableChoices() = 0; // derived screens must handle this 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_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; vector<RString> m_asSubscribedMessages;
+435 -80
View File
@@ -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" */ /* 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( 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 ); REGISTER_SCREEN_CLASS( ScreenSelectMaster );
#define GetActiveElementPlayerNumbers( vpns ) \ #define GetActiveElementPlayerNumbers( vpns ) \
@@ -60,6 +63,10 @@ void ScreenSelectMaster::Init()
PRE_SWITCH_PAGE_SECONDS.Load( m_sName, "PreSwitchPageSeconds" ); PRE_SWITCH_PAGE_SECONDS.Load( m_sName, "PreSwitchPageSeconds" );
POST_SWITCH_PAGE_SECONDS.Load( m_sName, "PostSwitchPageSeconds" ); POST_SWITCH_PAGE_SECONDS.Load( m_sName, "PostSwitchPageSeconds" );
OPTION_ORDER.Load( m_sName, OPTION_ORDER_NAME, NUM_MenuDir ); 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_CURSOR.Load( m_sName, "WrapCursor" );
WRAP_SCROLLER.Load( m_sName, "WrapScroller" ); WRAP_SCROLLER.Load( m_sName, "WrapScroller" );
LOOP_SCROLLER.Load( m_sName, "LoopScroller" ); LOOP_SCROLLER.Load( m_sName, "LoopScroller" );
@@ -102,7 +109,6 @@ void ScreenSelectMaster::Init()
FOREACH( PlayerNumber, vpns, p ) FOREACH( PlayerNumber, vpns, p )
m_vsprScroll[*p].resize( m_aGameCommands.size() ); m_vsprScroll[*p].resize( m_aGameCommands.size() );
for( unsigned c=0; c<m_aGameCommands.size(); c++ ) for( unsigned c=0; c<m_aGameCommands.size(); c++ )
{ {
GameCommand& mc = m_aGameCommands[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 // init scroll
if( SHOW_SCROLLER ) if( SHOW_SCROLLER )
{ {
@@ -331,8 +456,8 @@ void ScreenSelectMaster::HandleScreenMessage( const ScreenMessage SM )
MenuStart( iep ); MenuStart( iep );
} }
} }
} }
} }
int ScreenSelectMaster::GetSelectionIndex( PlayerNumber pn ) int ScreenSelectMaster::GetSelectionIndex( PlayerNumber pn )
@@ -345,15 +470,62 @@ void ScreenSelectMaster::UpdateSelectableChoices()
vector<PlayerNumber> vpns; vector<PlayerNumber> vpns;
GetActiveElementPlayerNumbers( vpns ); GetActiveElementPlayerNumbers( vpns );
if(m_bUsingTwoLists && m_iSelectedList == 1) // using two lists and on the 2nd list
for( unsigned c=0; c<m_aGameCommands.size(); c++ )
{ {
if( SHOW_ICON ) for( unsigned c=0; c<m_aGameCommands.size(); c++ )
m_vsprIcon[c]->PlayCommand( m_aGameCommands[c].IsPlayable()? "Enabled":"Disabled" ); {
if( SHOW_ICON )
{
m_vsprIcon[c]->PlayCommand( "List2Enabled" );
}
FOREACH( PlayerNumber, vpns, p ) FOREACH( PlayerNumber, vpns, p )
if( m_vsprScroll[*p][c].IsLoaded() ) if( m_vsprScroll[*p][c].IsLoaded() )
m_vsprScroll[*p][c]->PlayCommand( m_aGameCommands[c].IsPlayable()? "Enabled":"Disabled" ); {
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. * If any options are playable, make sure one is selected.
*/ */
FOREACH_HumanPlayer( p ) 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 bool ScreenSelectMaster::AnyOptionsArePlayable() const
{ {
for( unsigned i = 0; i < m_aGameCommands.size(); ++i ) // if they're using the second list
if( m_aGameCommands[i].IsPlayable() ) if(m_bUsingTwoLists && m_iSelectedList == 1)
return true; {
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; return false;
} }
@@ -384,18 +577,38 @@ bool ScreenSelectMaster::Move( PlayerNumber pn, MenuDir dir )
int iSwitchToIndex = m_iChoice[pn]; int iSwitchToIndex = m_iChoice[pn];
set<int> seen; set<int> seen;
try_again: 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 // moving list 2
return false; // can't go that way if(m_bUsingTwoLists && m_iSelectedList == 1)
if( seen.find(iSwitchToIndex) != seen.end() ) {
return false; // went full circle and none found map<int,int>::const_iterator iter = m_mapCurrentChoiceToNextChoiceB[dir].find( iSwitchToIndex );
seen.insert( iSwitchToIndex ); if( iter != m_mapCurrentChoiceToNextChoiceB[dir].end() )
iSwitchToIndex = iter->second;
if( !m_aGameCommands[iSwitchToIndex].IsPlayable() ) if( iSwitchToIndex < 0 || iSwitchToIndex >= (int) m_aGameCommandsB.size() ) // out of choice range
goto try_again; 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 ); return ChangeSelection( pn, dir, iSwitchToIndex );
} }
@@ -624,16 +837,75 @@ bool ScreenSelectMaster::ChangeSelection( PlayerNumber pn, MenuDir dir, int iNew
bNewAlreadyHadFocus |= m_iChoice[p2] == iNewChoice; bNewAlreadyHadFocus |= m_iChoice[p2] == iNewChoice;
} }
//todo: condense this section
if(DOUBLE_PRESS_TO_SELECT) if(DOUBLE_PRESS_TO_SELECT)
{ {
// this player is currently on a single press, which they are cancelling if(m_bUsingTwoLists && m_iSelectedList == 1)
if(m_bDoubleChoice[pn]) {
// 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 ) if( !bOldStillHasFocus )
m_vsprIcon[iOldChoice]->PlayCommand( "LoseFocus" ); m_vsprIconB[iOldChoice]->PlayCommand( "LoseFocus" );
if( !bNewAlreadyHadFocus ) if( !bNewAlreadyHadFocus )
m_vsprIcon[iNewChoice]->PlayCommand( "GainFocus" ); m_vsprIconB[iNewChoice]->PlayCommand( "GainFocus" );
} }
else else
{ {
@@ -643,14 +915,6 @@ bool ScreenSelectMaster::ChangeSelection( PlayerNumber pn, MenuDir dir, int iNew
m_vsprIcon[iNewChoice]->PlayCommand( "GainFocus" ); 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 ) if( SHOW_CURSOR )
@@ -661,26 +925,51 @@ bool ScreenSelectMaster::ChangeSelection( PlayerNumber pn, MenuDir dir, int iNew
if( SHOW_SCROLLER ) if( SHOW_SCROLLER )
{ {
ActorScroller &scroller = SHARED_SELECTION ? m_Scroller[0] : m_Scroller[*p];
vector<AutoActor> &vScroll = SHARED_SELECTION ? m_vsprScroll[0] : m_vsprScroll[*p]; ActorScroller &scroller = (m_bUsingTwoLists && m_iSelectedList == 1)?(SHARED_SELECTION ? m_ScrollerB[0] : m_ScrollerB[*p]):(SHARED_SELECTION ? m_Scroller[0] : m_Scroller[*p]);
if( WRAP_SCROLLER ) 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. if( WRAP_SCROLLER )
// 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(); // HACK: We can't tell from the option orders whether or not we wrapped.
int iNumChoices = m_aGameCommands.size(); // For now, assume that the order is increasing left to right.
fItem += iActualDir * iNumChoices; int iPressedDir = (dir == MenuDir_Left) ? -1 : +1;
scroller.SetCurrentAndDestinationItem( fItem ); int iActualDir = (iOldChoice < iNewChoice) ? +1 : -1;
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;
scroller.SetDestinationItem( (float)iNewChoice ); 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 // using double selections
if(DOUBLE_PRESS_TO_SELECT) if(DOUBLE_PRESS_TO_SELECT)
{ {
@@ -783,15 +1072,23 @@ void ScreenSelectMaster::MenuStart( const InputEventPlus &input )
if(SHOW_SCROLLER) if(SHOW_SCROLLER)
{ {
vector<AutoActor> &vScroll = SHARED_SELECTION ? m_vsprScroll[0] : m_vsprScroll[pn]; if(m_bUsingTwoLists && m_iSelectedList == 1)
vScroll[m_iChoice[pn]]->PlayCommand( "InitialSelection" ); {
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; 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 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. */ * If any options are playable, then the selection must be playable. */
@@ -852,26 +1149,55 @@ void ScreenSelectMaster::TweenOnScreen()
if( SHOW_ICON ) 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" ); for( unsigned c=0; c<m_aGameCommandsB.size(); c++ )
m_vsprIcon[c]->FinishTweening(); {
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 ) if( SHOW_SCROLLER )
{ {
FOREACH( PlayerNumber, vpns, p ) if(m_bUsingTwoLists && m_iSelectedList == 1)
{ {
// Play Gain/LoseFocus before playing the on command. Gain/Lose will FOREACH( PlayerNumber, vpns, p )
// 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" ); // Play Gain/LoseFocus before playing the on command. Gain/Lose will
m_vsprScroll[*p][c]->FinishTweening(); // 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; vector<PlayerNumber> vpns;
GetActiveElementPlayerNumbers( 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() ) for( unsigned c=0; c<m_aGameCommandsB.size(); c++ )
continue; // skip
bool bSelectedByEitherPlayer = false;
FOREACH( PlayerNumber, vpns, p )
{ {
if( m_iChoice[*p] == (int)c ) if( GetPage(c) != GetCurrentPage() )
bSelectedByEitherPlayer = true; continue; // skip
}
if( SHOW_ICON ) bool bSelectedByEitherPlayer = false;
m_vsprIcon[c]->PlayCommand( bSelectedByEitherPlayer? "OffFocused":"OffUnfocused" );
if( SHOW_SCROLLER )
{
FOREACH( PlayerNumber, vpns, p ) 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" );
}
} }
} }
} }
+13
View File
@@ -23,6 +23,7 @@ class ScreenSelectMaster : public ScreenSelect
{ {
public: public:
ScreenSelectMaster(); ScreenSelectMaster();
//~ScreenSelectMaster();
virtual void Init(); virtual void Init();
virtual RString GetDefaultChoice(); virtual RString GetDefaultChoice();
virtual void BeginScreen(); virtual void BeginScreen();
@@ -44,6 +45,7 @@ protected:
Page GetPage( int iChoiceIndex ) const; Page GetPage( int iChoiceIndex ) const;
Page GetCurrentPage() const; Page GetCurrentPage() const;
ThemeMetric<bool> USE_TWO_SCROLLERS;
ThemeMetric<bool> DOUBLE_PRESS_TO_SELECT; ThemeMetric<bool> DOUBLE_PRESS_TO_SELECT;
ThemeMetric<bool> SHOW_ICON; ThemeMetric<bool> SHOW_ICON;
ThemeMetric<bool> SHOW_SCROLLER; ThemeMetric<bool> SHOW_SCROLLER;
@@ -57,6 +59,7 @@ protected:
ThemeMetric<float> PRE_SWITCH_PAGE_SECONDS; ThemeMetric<float> PRE_SWITCH_PAGE_SECONDS;
ThemeMetric<float> POST_SWITCH_PAGE_SECONDS; ThemeMetric<float> POST_SWITCH_PAGE_SECONDS;
ThemeMetric1D<RString> OPTION_ORDER; ThemeMetric1D<RString> OPTION_ORDER;
ThemeMetric1D<RString> OPTION_ORDER2;
ThemeMetric<bool> WRAP_CURSOR; ThemeMetric<bool> WRAP_CURSOR;
ThemeMetric<bool> WRAP_SCROLLER; ThemeMetric<bool> WRAP_SCROLLER;
ThemeMetric<bool> LOOP_SCROLLER; ThemeMetric<bool> LOOP_SCROLLER;
@@ -69,6 +72,8 @@ protected:
ThemeMetric<RString> DEFAULT_CHOICE; ThemeMetric<RString> DEFAULT_CHOICE;
map<int,int> m_mapCurrentChoiceToNextChoice[NUM_MenuDir]; map<int,int> m_mapCurrentChoiceToNextChoice[NUM_MenuDir];
map<int,int> m_mapCurrentChoiceToNextChoiceB[NUM_MenuDir]; // if using two lists
virtual int GetSelectionIndex( PlayerNumber pn ); virtual int GetSelectionIndex( PlayerNumber pn );
virtual void UpdateSelectableChoices(); virtual void UpdateSelectableChoices();
@@ -87,9 +92,17 @@ protected:
AutoActor m_sprMore[NUM_Page]; AutoActor m_sprMore[NUM_Page];
// icon is the shared, per-choice piece // icon is the shared, per-choice piece
vector<AutoActor> m_vsprIcon; vector<AutoActor> m_vsprIcon;
vector<AutoActor> m_vsprIconB; // used if the user wants two lists
// preview is per-player, per-choice piece // preview is per-player, per-choice piece
vector<AutoActor> m_vsprScroll[NUM_PLAYERS]; 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_Scroller[NUM_PLAYERS];
ActorScroller m_ScrollerB[NUM_PLAYERS]; // used if the user wants two lists
// cursor is the per-player, shared by all choices // cursor is the per-player, shared by all choices
AutoActor m_sprCursor[NUM_PLAYERS]; AutoActor m_sprCursor[NUM_PLAYERS];