From fbf7bc4f263fbd63a520834d227a5f1ba700390f Mon Sep 17 00:00:00 2001 From: Chris Danford Date: Thu, 24 Feb 2005 04:56:36 +0000 Subject: [PATCH] split OptionRowHandler out of ScreenOptionsMaster --- stepmania/src/Makefile.am | 1 + stepmania/src/OptionRowHandler.cpp | 679 +++++++++++++++++++++ stepmania/src/OptionRowHandler.h | 153 +++++ stepmania/src/ScreenOptionsMaster.cpp | 823 +++----------------------- stepmania/src/ScreenOptionsMaster.h | 61 +- stepmania/src/StepMania.dsp | 12 +- stepmania/src/StepMania.vcproj | 6 + 7 files changed, 933 insertions(+), 802 deletions(-) create mode 100644 stepmania/src/OptionRowHandler.cpp create mode 100644 stepmania/src/OptionRowHandler.h diff --git a/stepmania/src/Makefile.am b/stepmania/src/Makefile.am index 95ef279a74..b3ceccdefb 100644 --- a/stepmania/src/Makefile.am +++ b/stepmania/src/Makefile.am @@ -76,6 +76,7 @@ NoteData.cpp NoteData.h NoteDataUtil.cpp NoteDataUtil.h NoteDataWithScoring.cpp NoteFieldPositioning.cpp NoteFieldPositioning.h NoteTypes.cpp NoteTypes.h NotesLoader.cpp NotesLoader.h \ NotesLoaderBMS.cpp NotesLoaderBMS.h NotesLoaderDWI.cpp NotesLoaderDWI.h NotesLoaderKSF.cpp NotesLoaderKSF.h \ NotesLoaderSM.cpp NotesLoaderSM.h NotesWriterDWI.cpp NotesWriterDWI.h NotesWriterSM.cpp NotesWriterSM.h \ +OptionRowHandler.cpp OptionRowHandler.h \ PlayerAI.cpp PlayerAI.h PlayerNumber.cpp PlayerNumber.h PlayerOptions.cpp PlayerOptions.h \ PlayerStageStats.cpp PlayerStageStats.h \ PlayerState.cpp PlayerState.h Preference.cpp Preference.h Profile.cpp Profile.h \ diff --git a/stepmania/src/OptionRowHandler.cpp b/stepmania/src/OptionRowHandler.cpp new file mode 100644 index 0000000000..1fa0f87045 --- /dev/null +++ b/stepmania/src/OptionRowHandler.cpp @@ -0,0 +1,679 @@ +#include "global.h" +#include "OptionRowHandler.h" +#include "LuaManager.h" +#include "ScreenOptionsMasterPrefs.h" +#include "NoteSkinManager.h" +#include "RageUtil.h" +#include "RageLog.h" +#include "GameState.h" +#include "Course.h" +#include "Steps.h" +#include "Style.h" +#include "song.h" +#include "SongManager.h" +#include "Character.h" +#include "PrefsManager.h" +#include "StepsUtil.h" +#include "GameManager.h" +#include "Foreach.h" + +#define ENTRY(s) THEME->GetMetric ("ScreenOptionsMaster",s) +#define ENTRY_NAME(s) THEME->GetMetric ("OptionNames", s) +#define ENTRY_MODE(s,i) THEME->GetMetric ("ScreenOptionsMaster",ssprintf("%s,%i",(s).c_str(),(i+1))) +#define ENTRY_DEFAULT(s) THEME->GetMetric ("ScreenOptionsMaster",(s) + "Default") + + +static void SelectExactlyOne( int iSelection, vector &vbSelectedOut ) +{ + for( int i=0; i<(int)vbSelectedOut.size(); i++ ) + vbSelectedOut[i] = i==iSelection; +} + +static int GetOneSelection( const vector &vbSelected ) +{ + for( unsigned i=0; i &vbSelectedOut ) const +{ + int FallbackOption = -1; + bool UseFallbackOption = true; + + for( unsigned e = 0; e < ListEntries.size(); ++e ) + { + const GameCommand &mc = ListEntries[e]; + + vbSelectedOut[e] = false; + + if( mc.IsZero() ) + { + /* The entry has no effect. This is usually a default "none of the + * above" entry. It will always return true for DescribesCurrentMode(). + * It's only the selected choice if nothing else matches. */ + if( row.selectType != SELECT_MULTIPLE ) + FallbackOption = e; + continue; + } + + if( row.bOneChoiceForAllPlayers ) + { + if( mc.DescribesCurrentModeForAllPlayers() ) + { + UseFallbackOption = false; + if( row.selectType != SELECT_MULTIPLE ) + SelectExactlyOne( e, vbSelectedOut ); + else + vbSelectedOut[e] = true; + } + } + else + { + if( mc.DescribesCurrentMode( pn) ) + { + UseFallbackOption = false; + if( row.selectType != SELECT_MULTIPLE ) + SelectExactlyOne( e, vbSelectedOut ); + else + vbSelectedOut[e] = true; + } + } + } + + if( row.selectType == SELECT_ONE && + UseFallbackOption && + FallbackOption != -1 ) + { + SelectExactlyOne( FallbackOption, vbSelectedOut ); + } +} + +int OptionRowHandlerList::ExportOption( const OptionRowDefinition &def, PlayerNumber pn, const vector &vbSelected ) const +{ + Default.Apply( pn ); + for( unsigned i=0; i &vbSelectedOut ) const +{ + ASSERT( lua_gettop(LUA->L) == 0 ); + + /* Evaluate the LoadSelections(self,array,pn) function, where array is a table + * representing vbSelectedOut. */ + + /* All selections default to false. */ + for( unsigned i = 0; i < vbSelectedOut.size(); ++i ) + vbSelectedOut[i] = false; + + /* Create the vbSelectedOut table. */ + LUA->CreateTableFromArrayB( vbSelectedOut ); + ASSERT( lua_gettop(LUA->L) == 1 ); /* vbSelectedOut table */ + + /* Get the function to call from m_LuaTable. */ + m_pLuaTable->PushSelf( LUA->L ); + ASSERT( lua_istable( LUA->L, -1 ) ); + + lua_pushstring( LUA->L, "LoadSelections" ); + lua_gettable( LUA->L, -2 ); + if( !lua_isfunction( LUA->L, -1 ) ) + RageException::Throw( "\"%s\" \"LoadSelections\" entry is not a function", row.name.c_str() ); + + /* Argument 1 (self): */ + m_pLuaTable->PushSelf( LUA->L ); + + /* Argument 2 (vbSelectedOut): */ + lua_pushvalue( LUA->L, 1 ); + + /* Argument 3 (pn): */ + LUA->PushStack( (int) pn ); + + ASSERT( lua_gettop(LUA->L) == 6 ); /* vbSelectedOut, m_iLuaTable, function, self, arg, arg */ + + lua_call( LUA->L, 3, 0 ); // call function with 3 arguments and 0 results + ASSERT( lua_gettop(LUA->L) == 2 ); + + lua_pop( LUA->L, 1 ); /* pop option table */ + + LUA->ReadArrayFromTableB( vbSelectedOut ); + + lua_pop( LUA->L, 1 ); /* pop vbSelectedOut table */ + + ASSERT( lua_gettop(LUA->L) == 0 ); +} + +int OptionRowHandlerLua::ExportOption( const OptionRowDefinition &def, PlayerNumber pn, const vector &vbSelected ) const +{ + ASSERT( lua_gettop(LUA->L) == 0 ); + + /* Evaluate SaveSelections(self,array,pn) function, where array is a table + * representing vbSelectedOut. */ + + vector vbSelectedCopy = vbSelected; + + /* Create the vbSelectedOut table. */ + LUA->CreateTableFromArrayB( vbSelectedCopy ); + ASSERT( lua_gettop(LUA->L) == 1 ); /* vbSelectedOut table */ + + /* Get the function to call. */ + m_pLuaTable->PushSelf( LUA->L ); + ASSERT( lua_istable( LUA->L, -1 ) ); + + lua_pushstring( LUA->L, "SaveSelections" ); + lua_gettable( LUA->L, -2 ); + if( !lua_isfunction( LUA->L, -1 ) ) + RageException::Throw( "\"%s\" \"SaveSelections\" entry is not a function", def.name.c_str() ); + + /* Argument 1 (self): */ + m_pLuaTable->PushSelf( LUA->L ); + + /* Argument 2 (vbSelectedOut): */ + lua_pushvalue( LUA->L, 1 ); + + /* Argument 3 (pn): */ + LUA->PushStack( (int) pn ); + + ASSERT( lua_gettop(LUA->L) == 6 ); /* vbSelectedOut, m_iLuaTable, function, self, arg, arg */ + + lua_call( LUA->L, 3, 0 ); // call function with 3 arguments and 0 results + ASSERT( lua_gettop(LUA->L) == 2 ); + + lua_pop( LUA->L, 1 ); /* pop option table */ + lua_pop( LUA->L, 1 ); /* pop vbSelected table */ + + ASSERT( lua_gettop(LUA->L) == 0 ); + + // XXX: allow specifying the mask + return 0; +} + +void OptionRowHandlerLua::Reload( OptionRowDefinition &def ) +{ + OptionRowHandlerUtil::FillLua( this, def, m_sName ); +} + + +void OptionRowHandlerConfig::ImportOption( const OptionRowDefinition &row, PlayerNumber pn, vector &vbSelectedOut ) const +{ + int iSelection = opt->Get(); + SelectExactlyOne( iSelection, vbSelectedOut ); +} + +int OptionRowHandlerConfig::ExportOption( const OptionRowDefinition &def, PlayerNumber pn, const vector &vbSelected ) const +{ + int sel = GetOneSelection(vbSelected); + + /* Get the original choice. */ + int Original = opt->Get(); + + /* Apply. */ + opt->Put( sel ); + + /* Get the new choice. */ + int New = opt->Get(); + + /* If it didn't change, don't return any side-effects. */ + if( Original == New ) + return 0; + + return opt->GetEffects(); +} + + +/* Add the list named "ListName" to the given row/handler. */ +void OptionRowHandlerUtil::FillList( OptionRowHandlerList* pHand, OptionRowDefinition &row, CString _ListName ) +{ + CString ListName = _ListName; + + pHand->Init(); + row.Init(); + + pHand->m_sName = ListName; + pHand->m_bUseModNameForIcon = true; + + row.name = ListName; + if( !ListName.CompareNoCase("noteskins") ) + { + pHand->Default.Init(); /* none */ + row.bOneChoiceForAllPlayers = false; + + CStringArray arraySkinNames; + NOTESKIN->GetNoteSkinNames( arraySkinNames ); + for( unsigned skin=0; skinListEntries.push_back( mc ); + row.choices.push_back( arraySkinNames[skin] ); + } + return; + } + + pHand->Default.Load( -1, ParseCommands(ENTRY_DEFAULT(ListName)) ); + + /* Parse the basic configuration metric. */ + Commands cmds = ParseCommands( ENTRY(ListName) ); + if( cmds.v.size() < 1 ) + RageException::Throw( "Parse error in OptionRowHandlerUtilEntries::ListName%s", ListName.c_str() ); + + row.bOneChoiceForAllPlayers = false; + const int NumCols = atoi( cmds.v[0].m_vsArgs[0] ); + for( unsigned i=1; im_vsRefreshRowNames.push_back( cmd.m_vsArgs[a] ); + } + else if( sName == "enabledforplayers" ) + { + row.m_vEnabledForPlayers.clear(); + for( unsigned a=1; a= 0 && pn < NUM_PLAYERS ); + row.m_vEnabledForPlayers.insert( pn ); + } + } + else if( sName == "exportonchange" ) pHand->m_bExportOnChange = true; + else RageException::Throw( "Unkown row flag \"%s\"", sName.c_str() ); + } + + for( int col = 0; col < NumCols; ++col ) + { + GameCommand mc; + mc.Load( 0, ParseCommands(ENTRY_MODE(ListName, col)) ); + if( mc.m_sName == "" ) + RageException::Throw( "List \"%s\", col %i has no name", ListName.c_str(), col ); + + if( !mc.IsPlayable() ) + continue; + + pHand->ListEntries.push_back( mc ); + + CString sName = mc.m_sName; + CString sChoice = ENTRY_NAME(mc.m_sName); + row.choices.push_back( sChoice ); + } +} + +void OptionRowHandlerUtil::FillLua( OptionRowHandlerLua* pHand, OptionRowDefinition &row, CString sLuaFunction ) +{ + pHand->Init(); + row.Init(); + + pHand->m_sName = sLuaFunction; +// pHand->m_bUseModNameForIcon = true; + + /* Run the Lua expression. It should return a table. */ + pHand->m_pLuaTable->SetFromExpression( sLuaFunction ); + + if( pHand->m_pLuaTable->GetLuaType() != LUA_TTABLE ) + RageException::Throw( "Result of \"%s\" is not a table", sLuaFunction.c_str() ); + + { + pHand->m_pLuaTable->PushSelf( LUA->L ); + + lua_pushstring( LUA->L, "Name" ); + lua_gettable( LUA->L, -2 ); + const char *pStr = lua_tostring( LUA->L, -1 ); + if( pStr == NULL ) + RageException::Throw( "\"%s\" \"Name\" entry is not a string", sLuaFunction.c_str() ); + row.name = pStr; + lua_pop( LUA->L, 1 ); + + + lua_pushstring( LUA->L, "OneChoiceForAllPlayers" ); + lua_gettable( LUA->L, -2 ); + row.bOneChoiceForAllPlayers = !!lua_toboolean( LUA->L, -1 ); + lua_pop( LUA->L, 1 ); + + + lua_pushstring( LUA->L, "LayoutType" ); + lua_gettable( LUA->L, -2 ); + pStr = lua_tostring( LUA->L, -1 ); + if( pStr == NULL ) + RageException::Throw( "\"%s\" \"LayoutType\" entry is not a string", sLuaFunction.c_str() ); + row.layoutType = StringToLayoutType( pStr ); + ASSERT( row.layoutType != LAYOUT_INVALID ); + lua_pop( LUA->L, 1 ); + + + lua_pushstring( LUA->L, "SelectType" ); + lua_gettable( LUA->L, -2 ); + pStr = lua_tostring( LUA->L, -1 ); + if( pStr == NULL ) + RageException::Throw( "\"%s\" \"SelectType\" entry is not a string", sLuaFunction.c_str() ); + row.selectType = StringToSelectType( pStr ); + ASSERT( row.selectType != SELECT_INVALID ); + lua_pop( LUA->L, 1 ); + + + /* Iterate over the "Choices" table. */ + lua_pushstring( LUA->L, "Choices" ); + lua_gettable( LUA->L, -2 ); + if( !lua_istable( LUA->L, -1 ) ) + RageException::Throw( "\"%s\" \"Choices\" is not a table", sLuaFunction.c_str() ); + + lua_pushnil( LUA->L ); + while( lua_next(LUA->L, -2) != 0 ) + { + /* `key' is at index -2 and `value' at index -1 */ + const char *pValue = lua_tostring( LUA->L, -1 ); + if( pValue == NULL ) + RageException::Throw( "\"%s\" Column entry is not a string", sLuaFunction.c_str() ); + LOG->Trace( "'%s'", pValue); + + row.choices.push_back( pValue ); + + lua_pop( LUA->L, 1 ); /* removes `value'; keeps `key' for next iteration */ + } + + lua_pop( LUA->L, 1 ); /* pop choices table */ + + + /* Iterate over the "EnabledForPlayers" table. */ + lua_pushstring( LUA->L, "EnabledForPlayers" ); + lua_gettable( LUA->L, -2 ); + if( !lua_isnil( LUA->L, -1 ) ) + { + if( !lua_istable( LUA->L, -1 ) ) + RageException::Throw( "\"%s\" \"EnabledForPlayers\" is not a table", sLuaFunction.c_str() ); + + row.m_vEnabledForPlayers.clear(); // and fill in with supplied PlayerNumbers below + + lua_pushnil( LUA->L ); + while( lua_next(LUA->L, -2) != 0 ) + { + /* `key' is at index -2 and `value' at index -1 */ + PlayerNumber pn = (PlayerNumber)luaL_checkint( LUA->L, -1 ); + + row.m_vEnabledForPlayers.insert( pn ); + + lua_pop( LUA->L, 1 ); /* removes `value'; keeps `key' for next iteration */ + } + } + lua_pop( LUA->L, 1 ); /* pop EnabledForPlayers table */ + + + /* Look for "ExportOnChange" value. */ + lua_pushstring( LUA->L, "ExportOnChange" ); + lua_gettable( LUA->L, -2 ); + if( !lua_isnil( LUA->L, -1 ) ) + { + pHand->m_bExportOnChange = !!MyLua_checkboolean( LUA->L, -1 ); + } + lua_pop( LUA->L, 1 ); /* pop ExportOnChange value */ + + + /* Iterate over the "RefreshRowNames" table. */ + lua_pushstring( LUA->L, "RefreshRowNames" ); + lua_gettable( LUA->L, -2 ); + if( !lua_isnil( LUA->L, -1 ) ) + { + if( !lua_istable( LUA->L, -1 ) ) + RageException::Throw( "\"%s\" \"RefreshRowNames\" is not a table", sLuaFunction.c_str() ); + + pHand->m_vsRefreshRowNames.clear(); // and fill in with supplied PlayerNumbers below + + lua_pushnil( LUA->L ); + while( lua_next(LUA->L, -2) != 0 ) + { + /* `key' is at index -2 and `value' at index -1 */ + const char *pValue = lua_tostring( LUA->L, -1 ); + if( pValue == NULL ) + RageException::Throw( "\"%s\" Column entry is not a string", sLuaFunction.c_str() ); + LOG->Trace( "'%s'", pValue); + + pHand->m_vsRefreshRowNames.push_back( pValue ); + + lua_pop( LUA->L, 1 ); /* removes `value'; keeps `key' for next iteration */ + } + } + lua_pop( LUA->L, 1 ); /* pop RefreshRowNames table */ + + + lua_pop( LUA->L, 1 ); /* pop main table */ + ASSERT( lua_gettop(LUA->L) == 0 ); + } +} + + +/* Add a list of difficulties/edits to the given row/handler. */ +void OptionRowHandlerUtil::FillSteps( OptionRowHandlerList* pHand, OptionRowDefinition &row ) +{ + pHand->Init(); + row.Init(); + + row.name = "Steps"; + row.bOneChoiceForAllPlayers = false; + + // fill in difficulty names + if( GAMESTATE->m_bEditing ) + { + row.choices.push_back( "" ); + pHand->ListEntries.push_back( GameCommand() ); + } + else if( GAMESTATE->IsCourseMode() ) // playing a course + { + row.bOneChoiceForAllPlayers = PREFSMAN->m_bLockCourseDifficulties; + + vector vTrails; + GAMESTATE->m_pCurCourse->GetTrails( vTrails, GAMESTATE->GetCurrentStyle()->m_StepsType ); + for( unsigned i=0; im_CourseDifficulty ); + row.choices.push_back( s ); + GameCommand mc; + mc.m_pTrail = pTrail; + pHand->ListEntries.push_back( mc ); + } + } + else // !GAMESTATE->IsCourseMode(), playing a song + { + vector vSteps; + GAMESTATE->m_pCurSong->GetSteps( vSteps, GAMESTATE->GetCurrentStyle()->m_StepsType ); + StepsUtil::SortNotesArrayByDifficulty( vSteps ); + for( unsigned i=0; iGetDifficulty() == DIFFICULTY_EDIT ) + s = pSteps->GetDescription(); + else + s = DifficultyToThemedString( pSteps->GetDifficulty() ); + s += ssprintf( " (%d)", pSteps->GetMeter() ); + + row.choices.push_back( s ); + GameCommand mc; + mc.m_pSteps = pSteps; + mc.m_dc = pSteps->GetDifficulty(); + pHand->ListEntries.push_back( mc ); + } + } +} + + +/* Add the given configuration value to the given row/handler. */ +void OptionRowHandlerUtil::FillConf( OptionRowHandlerConfig* pHand, OptionRowDefinition &row, CString param ) +{ + pHand->Init(); + row.Init(); + + /* Configuration values are never per-player. */ + row.bOneChoiceForAllPlayers = true; + + ConfOption *pConfOption = ConfOption::Find( param ); + if( pConfOption == NULL ) + RageException::Throw( "Invalid Conf type \"%s\"", param.c_str() ); + + pConfOption->UpdateAvailableOptions(); + + pHand->opt = pConfOption; + pHand->opt->MakeOptionsList( row.choices ); + + row.name = pHand->opt->name; +} + +/* Add a list of available characters to the given row/handler. */ +void OptionRowHandlerUtil::FillCharacters( OptionRowHandlerList* pHand, OptionRowDefinition &row ) +{ + pHand->Init(); + row.Init(); + + row.bOneChoiceForAllPlayers = false; + row.name = "Characters"; + pHand->Default.m_pCharacter = GAMESTATE->GetDefaultCharacter(); + + { + row.choices.push_back( ENTRY_NAME("Off") ); + GameCommand mc; + mc.m_pCharacter = NULL; + pHand->ListEntries.push_back( mc ); + } + + vector apCharacters; + GAMESTATE->GetCharacters( apCharacters ); + for( unsigned i=0; im_sName; + s.MakeUpper(); + + row.choices.push_back( s ); + GameCommand mc; + mc.m_pCharacter = pCharacter; + pHand->ListEntries.push_back( mc ); + } +} + +/* Add a list of available styles to the given row/handler. */ +void OptionRowHandlerUtil::FillStyles( OptionRowHandlerList* pHand, OptionRowDefinition &row ) +{ + pHand->Init(); + row.Init(); + + row.bOneChoiceForAllPlayers = true; + row.name = "Style"; + row.bOneChoiceForAllPlayers = true; + + vector vStyles; + GAMEMAN->GetStylesForGame( GAMESTATE->m_pCurGame, vStyles ); + ASSERT( vStyles.size() ); + FOREACH_CONST( const Style*, vStyles, s ) + { + row.choices.push_back( GAMEMAN->StyleToThemedString(*s) ); + GameCommand mc; + mc.m_pStyle = *s; + pHand->ListEntries.push_back( mc ); + } + + pHand->Default.m_pStyle = vStyles[0]; +} + +/* Add a list of available song groups to the given row/handler. */ +void OptionRowHandlerUtil::FillGroups( OptionRowHandlerList* pHand, OptionRowDefinition &row ) +{ + pHand->Init(); + row.Init(); + + row.bOneChoiceForAllPlayers = true; + row.name = "Group"; + pHand->Default.m_sSongGroup = GROUP_ALL_MUSIC; + + vector vGroups; + SONGMAN->GetGroupNames( vGroups ); + ASSERT( vGroups.size() ); + + { + row.choices.push_back( ENTRY_NAME("AllGroups") ); + GameCommand mc; + mc.m_sSongGroup = GROUP_ALL_MUSIC; + pHand->ListEntries.push_back( mc ); + } + + FOREACH_CONST( CString, vGroups, g ) + { + row.choices.push_back( *g ); + GameCommand mc; + mc.m_sSongGroup = *g; + pHand->ListEntries.push_back( mc ); + } +} + +/* Add a list of available difficulties to the given row/handler. */ +void OptionRowHandlerUtil::FillDifficulties( OptionRowHandlerList* pHand, OptionRowDefinition &row ) +{ + pHand->Init(); + row.Init(); + + set vDifficulties; + GAMESTATE->GetDifficultiesToShow( vDifficulties ); + + row.bOneChoiceForAllPlayers = true; + row.name = "Difficulty"; + pHand->Default.m_dc = DIFFICULTY_INVALID; + + { + row.choices.push_back( ENTRY_NAME("AllDifficulties") ); + GameCommand mc; + mc.m_dc = DIFFICULTY_INVALID; + pHand->ListEntries.push_back( mc ); + } + + FOREACHS_CONST( Difficulty, vDifficulties, d ) + { + CString s = DifficultyToThemedString( *d ); + + row.choices.push_back( s ); + GameCommand mc; + mc.m_dc = *d; + pHand->ListEntries.push_back( mc ); + } +} + + +/* + * (c) 2002-2004 Chris Danford + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ diff --git a/stepmania/src/OptionRowHandler.h b/stepmania/src/OptionRowHandler.h new file mode 100644 index 0000000000..8113b53ab8 --- /dev/null +++ b/stepmania/src/OptionRowHandler.h @@ -0,0 +1,153 @@ +/* OptionRowHandler - Shows PlayerOptions and SongOptions in icon form. */ + +#ifndef OptionRowHandler_H +#define OptionRowHandler_H + +#include "OptionRow.h" +#include "GameCommand.h" +#include "LuaReference.h" + +struct ConfOption; + +class OptionRowHandler +{ +public: + CString m_sName; + bool m_bExportOnChange; + vector m_vsRefreshRowNames; // refresh these rows when the value of this row changes + + OptionRowHandler::OptionRowHandler() { Init(); } + virtual void Init() + { + m_sName = ""; + m_vsRefreshRowNames.clear(); + m_bExportOnChange = false; + } + virtual void ImportOption( const OptionRowDefinition &row, PlayerNumber pn, vector &vbSelectedOut ) const = 0; + /* Returns an OPT mask. */ + virtual int ExportOption( const OptionRowDefinition &def, PlayerNumber pn, const vector &vbSelected ) const = 0; + virtual void Reload( OptionRowDefinition &def ) {} + virtual CString GetIconText( const OptionRowDefinition &def, int iFirstSelection ) const { return ""; } + virtual CString GetAndEraseScreen( int iChoice ) { return ""; } +}; + +class OptionRowHandlerList : public OptionRowHandler +{ +public: + vector ListEntries; + GameCommand Default; + bool m_bUseModNameForIcon; + + OptionRowHandlerList::OptionRowHandlerList() { Init(); } + virtual void Init() + { + OptionRowHandler::Init(); + ListEntries.clear(); + Default.Init(); + m_bUseModNameForIcon = false; + } + virtual void ImportOption( const OptionRowDefinition &row, PlayerNumber pn, vector &vbSelectedOut ) const; + virtual int ExportOption( const OptionRowDefinition &def, PlayerNumber pn, const vector &vbSelected ) const; + virtual CString GetIconText( const OptionRowDefinition &def, int iFirstSelection ) const + { + return m_bUseModNameForIcon ? + ListEntries[iFirstSelection].m_sModifiers : + def.choices[iFirstSelection]; + } + virtual CString GetAndEraseScreen( int iChoice ) + { + GameCommand &mc = ListEntries[iChoice]; + if( mc.m_sScreen != "" ) + { + /* Hack: instead of applying screen commands here, store them in + * m_sNextScreen and apply them after we tween out. If we don't set + * m_sScreen to "", we'll load it twice (once for each player) and + * then again for m_sNextScreen. */ + CString sNextScreen = mc.m_sScreen; + mc.m_sScreen = ""; + return sNextScreen; + } + return ""; + } +}; + +class OptionRowHandlerLua : public OptionRowHandler +{ +public: + LuaExpression *m_pLuaTable; + + OptionRowHandlerLua::OptionRowHandlerLua() { m_pLuaTable = NULL; Init(); } + void Init() + { + OptionRowHandler::Init(); + delete m_pLuaTable; + m_pLuaTable = new LuaExpression; + } + virtual void ImportOption( const OptionRowDefinition &row, PlayerNumber pn, vector &vbSelectedOut ) const; + virtual int ExportOption( const OptionRowDefinition &def, PlayerNumber pn, const vector &vbSelected ) const; + virtual void Reload( OptionRowDefinition &def ); +}; + +class OptionRowHandlerConfig : public OptionRowHandler +{ +public: + const ConfOption *opt; + + OptionRowHandlerConfig::OptionRowHandlerConfig() { Init(); } + void Init() + { + OptionRowHandler::Init(); + opt = NULL; + } + virtual void ImportOption( const OptionRowDefinition &row, PlayerNumber pn, vector &vbSelectedOut ) const; + virtual int ExportOption( const OptionRowDefinition &def, PlayerNumber pn, const vector &vbSelected ) const; +}; + +namespace OptionRowHandlerUtil +{ + void FillList( OptionRowHandlerList* pHand, OptionRowDefinition &def, CString param ); + void FillLua( OptionRowHandlerLua* pHand, OptionRowDefinition &def, CString sLuaFunction ); + void FillSteps( OptionRowHandlerList* pHand, OptionRowDefinition &def ); + void FillConf( OptionRowHandlerConfig* pHand, OptionRowDefinition &def, CString param ); + void FillCharacters( OptionRowHandlerList* pHand, OptionRowDefinition &def ); + void FillStyles( OptionRowHandlerList* pHand, OptionRowDefinition &def ); + void FillGroups( OptionRowHandlerList* pHand, OptionRowDefinition &def ); + void FillDifficulties( OptionRowHandlerList* pHand, OptionRowDefinition &def ); + + inline OptionRowHandler* MakeList( OptionRowDefinition &def, CString param ) { OptionRowHandlerList *pHand = new OptionRowHandlerList; FillList( pHand, def, param ); return pHand; } + inline OptionRowHandler* MakeLua( OptionRowDefinition &def, CString sLuaFunction ) { OptionRowHandlerLua *pHand = new OptionRowHandlerLua; FillLua( pHand, def, sLuaFunction ); return pHand; } + inline OptionRowHandler* MakeSteps( OptionRowDefinition &def ) { OptionRowHandlerList *pHand = new OptionRowHandlerList; FillSteps( pHand, def ); return pHand; } + inline OptionRowHandler* MakeConf( OptionRowDefinition &def, CString param ) { OptionRowHandlerConfig *pHand = new OptionRowHandlerConfig; FillConf( pHand, def, param ); return pHand; } + inline OptionRowHandler* MakeCharacters( OptionRowDefinition &def ) { OptionRowHandlerList *pHand = new OptionRowHandlerList; FillCharacters( pHand, def ); return pHand; } + inline OptionRowHandler* MakeStyles( OptionRowDefinition &def ) { OptionRowHandlerList *pHand = new OptionRowHandlerList; FillStyles( pHand, def ); return pHand; } + inline OptionRowHandler* MakeGroups( OptionRowDefinition &def ) { OptionRowHandlerList *pHand = new OptionRowHandlerList; FillGroups( pHand, def ); return pHand; } + inline OptionRowHandler* MakeDifficulties( OptionRowDefinition &def ) { OptionRowHandlerList *pHand = new OptionRowHandlerList; FillDifficulties( pHand, def ); return pHand; } +} + + +#endif + +/* + * (c) 2002-2004 Chris Danford + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ diff --git a/stepmania/src/ScreenOptionsMaster.cpp b/stepmania/src/ScreenOptionsMaster.cpp index 7a52b4aa6f..70697f3dab 100644 --- a/stepmania/src/ScreenOptionsMaster.cpp +++ b/stepmania/src/ScreenOptionsMaster.cpp @@ -7,451 +7,27 @@ #include "ThemeManager.h" #include "GameState.h" #include "ScreenManager.h" -#include "NoteSkinManager.h" -#include "Course.h" -#include "Steps.h" -#include "Style.h" -#include "song.h" #include "SongManager.h" -#include "Character.h" #include "PrefsManager.h" -#include "ScreenOptionsMasterPrefs.h" #include "GameSoundManager.h" #include "StepMania.h" #include "RageSoundManager.h" -#include "ProfileManager.h" -#include "StepsUtil.h" -#include "LuaManager.h" -#include "GameManager.h" #include "Foreach.h" +#include "OptionRowHandler.h" +#include "ScreenOptionsMasterPrefs.h" #define LINE_NAMES THEME->GetMetric (m_sName,"LineNames") #define OPTION_MENU_FLAGS THEME->GetMetric (m_sName,"OptionMenuFlags") #define LINE(sLineName) THEME->GetMetric (m_sName,ssprintf("Line%s",sLineName.c_str())) -#define ENTRY(s) THEME->GetMetric ("ScreenOptionsMaster",s) +// keep this in sync with OptionRowHandler.cpp #define ENTRY_NAME(s) THEME->GetMetric ("OptionNames", s) -#define ENTRY_MODE(s,i) THEME->GetMetric ("ScreenOptionsMaster",ssprintf("%s,%i",(s).c_str(),(i+1))) -#define ENTRY_DEFAULT(s) THEME->GetMetric ("ScreenOptionsMaster",(s) + "Default") + #define NEXT_SCREEN THEME->GetMetric (m_sName,"NextScreen") #define PREV_SCREEN THEME->GetMetric (m_sName,"PrevScreen") -/* Add the list named "ListName" to the given row/handler. */ -void ScreenOptionsMaster::SetList( OptionRowDefinition &row, OptionRowHandler &hand, CString _ListName ) -{ - CString ListName = _ListName; +const CString NEXT_ROW_NAME = "NextRow"; - row.Init(); - hand.Init(); - - hand.type = ROW_LIST; - hand.m_sName = ListName; - hand.m_bUseModNameForIcon = true; - - row.name = ListName; - if( !ListName.CompareNoCase("noteskins") ) - { - hand.Default.Init(); /* none */ - row.bOneChoiceForAllPlayers = false; - - CStringArray arraySkinNames; - NOTESKIN->GetNoteSkinNames( arraySkinNames ); - for( unsigned skin=0; skin= 0 && pn < NUM_PLAYERS ); - row.m_vEnabledForPlayers.insert( pn ); - } - } - else if( sName == "exportonchange" ) hand.m_bExportOnChange = true; - else RageException::Throw( "Unkown row flag \"%s\"", sName.c_str() ); - } - - for( int col = 0; col < NumCols; ++col ) - { - GameCommand mc; - mc.Load( 0, ParseCommands(ENTRY_MODE(ListName, col)) ); - if( mc.m_sName == "" ) - RageException::Throw( "List \"%s\", col %i has no name", ListName.c_str(), col ); - - if( !mc.IsPlayable() ) - continue; - - hand.ListEntries.push_back( mc ); - - CString sName = mc.m_sName; - CString sChoice = ENTRY_NAME(mc.m_sName); - row.choices.push_back( sChoice ); - } -} - -void ScreenOptionsMaster::SetLua( OptionRowDefinition &row, OptionRowHandler &hand, const CString &_sLuaFunction ) -{ - CString sLuaFunction = _sLuaFunction; - - row.Init(); - hand.Init(); - - hand.type = ROW_LUA; - hand.m_sName = sLuaFunction; - hand.m_bUseModNameForIcon = true; - - /* Run the Lua expression. It should return a table. */ - hand.m_pLuaTable->SetFromExpression( sLuaFunction ); - - if( hand.m_pLuaTable->GetLuaType() != LUA_TTABLE ) - RageException::Throw( "Result of \"%s\" is not a table", sLuaFunction.c_str() ); - - { - hand.m_pLuaTable->PushSelf( LUA->L ); - - lua_pushstring( LUA->L, "Name" ); - lua_gettable( LUA->L, -2 ); - const char *pStr = lua_tostring( LUA->L, -1 ); - if( pStr == NULL ) - RageException::Throw( "\"%s\" \"Name\" entry is not a string", sLuaFunction.c_str() ); - row.name = pStr; - lua_pop( LUA->L, 1 ); - - - lua_pushstring( LUA->L, "OneChoiceForAllPlayers" ); - lua_gettable( LUA->L, -2 ); - row.bOneChoiceForAllPlayers = !!lua_toboolean( LUA->L, -1 ); - lua_pop( LUA->L, 1 ); - - - lua_pushstring( LUA->L, "LayoutType" ); - lua_gettable( LUA->L, -2 ); - pStr = lua_tostring( LUA->L, -1 ); - if( pStr == NULL ) - RageException::Throw( "\"%s\" \"LayoutType\" entry is not a string", sLuaFunction.c_str() ); - row.layoutType = StringToLayoutType( pStr ); - ASSERT( row.layoutType != LAYOUT_INVALID ); - lua_pop( LUA->L, 1 ); - - - lua_pushstring( LUA->L, "SelectType" ); - lua_gettable( LUA->L, -2 ); - pStr = lua_tostring( LUA->L, -1 ); - if( pStr == NULL ) - RageException::Throw( "\"%s\" \"SelectType\" entry is not a string", sLuaFunction.c_str() ); - row.selectType = StringToSelectType( pStr ); - ASSERT( row.selectType != SELECT_INVALID ); - lua_pop( LUA->L, 1 ); - - - /* Iterate over the "Choices" table. */ - lua_pushstring( LUA->L, "Choices" ); - lua_gettable( LUA->L, -2 ); - if( !lua_istable( LUA->L, -1 ) ) - RageException::Throw( "\"%s\" \"Choices\" is not a table", sLuaFunction.c_str() ); - - lua_pushnil( LUA->L ); - while( lua_next(LUA->L, -2) != 0 ) - { - /* `key' is at index -2 and `value' at index -1 */ - const char *pValue = lua_tostring( LUA->L, -1 ); - if( pValue == NULL ) - RageException::Throw( "\"%s\" Column entry is not a string", sLuaFunction.c_str() ); - LOG->Trace( "'%s'", pValue); - - row.choices.push_back( pValue ); - - lua_pop( LUA->L, 1 ); /* removes `value'; keeps `key' for next iteration */ - } - - lua_pop( LUA->L, 1 ); /* pop choices table */ - - - /* Iterate over the "EnabledForPlayers" table. */ - lua_pushstring( LUA->L, "EnabledForPlayers" ); - lua_gettable( LUA->L, -2 ); - if( !lua_isnil( LUA->L, -1 ) ) - { - if( !lua_istable( LUA->L, -1 ) ) - RageException::Throw( "\"%s\" \"EnabledForPlayers\" is not a table", sLuaFunction.c_str() ); - - row.m_vEnabledForPlayers.clear(); // and fill in with supplied PlayerNumbers below - - lua_pushnil( LUA->L ); - while( lua_next(LUA->L, -2) != 0 ) - { - /* `key' is at index -2 and `value' at index -1 */ - PlayerNumber pn = (PlayerNumber)luaL_checkint( LUA->L, -1 ); - - row.m_vEnabledForPlayers.insert( pn ); - - lua_pop( LUA->L, 1 ); /* removes `value'; keeps `key' for next iteration */ - } - } - lua_pop( LUA->L, 1 ); /* pop EnabledForPlayers table */ - - - /* Look for "ExportOnChange" value. */ - lua_pushstring( LUA->L, "ExportOnChange" ); - lua_gettable( LUA->L, -2 ); - if( !lua_isnil( LUA->L, -1 ) ) - { - hand.m_bExportOnChange = !!MyLua_checkboolean( LUA->L, -1 ); - } - lua_pop( LUA->L, 1 ); /* pop ExportOnChange value */ - - - /* Iterate over the "RefreshRowNames" table. */ - lua_pushstring( LUA->L, "RefreshRowNames" ); - lua_gettable( LUA->L, -2 ); - if( !lua_isnil( LUA->L, -1 ) ) - { - if( !lua_istable( LUA->L, -1 ) ) - RageException::Throw( "\"%s\" \"RefreshRowNames\" is not a table", sLuaFunction.c_str() ); - - hand.m_vsRefreshRowNames.clear(); // and fill in with supplied PlayerNumbers below - - lua_pushnil( LUA->L ); - while( lua_next(LUA->L, -2) != 0 ) - { - /* `key' is at index -2 and `value' at index -1 */ - const char *pValue = lua_tostring( LUA->L, -1 ); - if( pValue == NULL ) - RageException::Throw( "\"%s\" Column entry is not a string", sLuaFunction.c_str() ); - LOG->Trace( "'%s'", pValue); - - hand.m_vsRefreshRowNames.push_back( pValue ); - - lua_pop( LUA->L, 1 ); /* removes `value'; keeps `key' for next iteration */ - } - } - lua_pop( LUA->L, 1 ); /* pop RefreshRowNames table */ - - - lua_pop( LUA->L, 1 ); /* pop main table */ - ASSERT( lua_gettop(LUA->L) == 0 ); - } -} - - -/* Add a list of difficulties/edits to the given row/handler. */ -void ScreenOptionsMaster::SetSteps( OptionRowDefinition &row, OptionRowHandler &hand ) -{ - hand.type = ROW_LIST; - row.name = "Steps"; - row.bOneChoiceForAllPlayers = false; - - // fill in difficulty names - if( GAMESTATE->m_bEditing ) - { - row.choices.push_back( "" ); - hand.ListEntries.push_back( GameCommand() ); - } - else if( GAMESTATE->IsCourseMode() ) // playing a course - { - row.bOneChoiceForAllPlayers = PREFSMAN->m_bLockCourseDifficulties; - - vector vTrails; - GAMESTATE->m_pCurCourse->GetTrails( vTrails, GAMESTATE->GetCurrentStyle()->m_StepsType ); - for( unsigned i=0; im_CourseDifficulty ); - row.choices.push_back( s ); - GameCommand mc; - mc.m_pTrail = pTrail; - hand.ListEntries.push_back( mc ); - } - } - else // !GAMESTATE->IsCourseMode(), playing a song - { - vector vSteps; - GAMESTATE->m_pCurSong->GetSteps( vSteps, GAMESTATE->GetCurrentStyle()->m_StepsType ); - StepsUtil::SortNotesArrayByDifficulty( vSteps ); - for( unsigned i=0; iGetDifficulty() == DIFFICULTY_EDIT ) - s = pSteps->GetDescription(); - else - s = DifficultyToThemedString( pSteps->GetDifficulty() ); - s += ssprintf( " (%d)", pSteps->GetMeter() ); - - row.choices.push_back( s ); - GameCommand mc; - mc.m_pSteps = pSteps; - mc.m_dc = pSteps->GetDifficulty(); - hand.ListEntries.push_back( mc ); - } - } -} - - -/* Add the given configuration value to the given row/handler. */ -void ScreenOptionsMaster::SetConf( OptionRowDefinition &row, OptionRowHandler &hand, CString param ) -{ - /* Configuration values are never per-player. */ - row.bOneChoiceForAllPlayers = true; - hand.type = ROW_CONFIG; - - ConfOption *pConfOption = ConfOption::Find( param ); - if( pConfOption == NULL ) - RageException::Throw( "Invalid Conf type \"%s\"", param.c_str() ); - - pConfOption->UpdateAvailableOptions(); - - hand.opt = pConfOption; - hand.opt->MakeOptionsList( row.choices ); - - row.name = hand.opt->name; -} - -/* Add a list of available characters to the given row/handler. */ -void ScreenOptionsMaster::SetCharacters( OptionRowDefinition &row, OptionRowHandler &hand ) -{ - hand.type = ROW_LIST; - row.bOneChoiceForAllPlayers = false; - row.name = "Characters"; - hand.Default.m_pCharacter = GAMESTATE->GetDefaultCharacter(); - - { - row.choices.push_back( ENTRY_NAME("Off") ); - GameCommand mc; - mc.m_pCharacter = NULL; - hand.ListEntries.push_back( mc ); - } - - vector apCharacters; - GAMESTATE->GetCharacters( apCharacters ); - for( unsigned i=0; im_sName; - s.MakeUpper(); - - row.choices.push_back( s ); - GameCommand mc; - mc.m_pCharacter = pCharacter; - hand.ListEntries.push_back( mc ); - } -} - -/* Add a list of available styles to the given row/handler. */ -void ScreenOptionsMaster::SetStyles( OptionRowDefinition &row, OptionRowHandler &hand ) -{ - hand.type = ROW_LIST; - row.bOneChoiceForAllPlayers = true; - row.name = "Style"; - row.bOneChoiceForAllPlayers = true; - - vector vStyles; - GAMEMAN->GetStylesForGame( GAMESTATE->m_pCurGame, vStyles ); - ASSERT( vStyles.size() ); - FOREACH_CONST( const Style*, vStyles, s ) - { - row.choices.push_back( GAMEMAN->StyleToThemedString(*s) ); - GameCommand mc; - mc.m_pStyle = *s; - hand.ListEntries.push_back( mc ); - } - - hand.Default.m_pStyle = vStyles[0]; -} - -/* Add a list of available song groups to the given row/handler. */ -void ScreenOptionsMaster::SetGroups( OptionRowDefinition &row, OptionRowHandler &hand ) -{ - hand.type = ROW_LIST; - row.bOneChoiceForAllPlayers = true; - row.name = "Group"; - hand.Default.m_sSongGroup = GROUP_ALL_MUSIC; - - vector vGroups; - SONGMAN->GetGroupNames( vGroups ); - ASSERT( vGroups.size() ); - - { - row.choices.push_back( ENTRY_NAME("AllGroups") ); - GameCommand mc; - mc.m_sSongGroup = GROUP_ALL_MUSIC; - hand.ListEntries.push_back( mc ); - } - - FOREACH_CONST( CString, vGroups, g ) - { - row.choices.push_back( *g ); - GameCommand mc; - mc.m_sSongGroup = *g; - hand.ListEntries.push_back( mc ); - } -} - -/* Add a list of available difficulties to the given row/handler. */ -void ScreenOptionsMaster::SetDifficulties( OptionRowDefinition &row, OptionRowHandler &hand ) -{ - set vDifficulties; - GAMESTATE->GetDifficultiesToShow( vDifficulties ); - - hand.type = ROW_LIST; - row.bOneChoiceForAllPlayers = true; - row.name = "Difficulty"; - hand.Default.m_dc = DIFFICULTY_INVALID; - - { - row.choices.push_back( ENTRY_NAME("AllDifficulties") ); - GameCommand mc; - mc.m_dc = DIFFICULTY_INVALID; - hand.ListEntries.push_back( mc ); - } - - FOREACHS_CONST( Difficulty, vDifficulties, d ) - { - CString s = DifficultyToThemedString( *d ); - - row.choices.push_back( s ); - GameCommand mc; - mc.m_dc = *d; - hand.ListEntries.push_back( mc ); - } -} REGISTER_SCREEN_CLASS( ScreenOptionsMaster ); ScreenOptionsMaster::ScreenOptionsMaster( CString sClassName ): @@ -501,7 +77,8 @@ void ScreenOptionsMaster::Init() RageException::Throw( "Unknown flag \"%s\"", sFlag.c_str() ); } - m_OptionRowAlloc = new OptionRowDefinition[asLineNames.size()]; + m_OptionRowAlloc.resize( asLineNames.size() ); + OptionRowHandlers.resize( asLineNames.size() ); for( unsigned i = 0; i < asLineNames.size(); ++i ) { CString sLineName = asLineNames[i]; @@ -516,7 +93,9 @@ void ScreenOptionsMaster::Init() if( vCommands.v.size() < 1 ) RageException::Throw( "Parse error in %s::Line%i", m_sName.c_str(), i+1 ); - OptionRowHandler hand; + OptionRowHandler* &pHand = OptionRowHandlers[i]; + pHand = NULL; + for( unsigned c=0; c &vbSelectedOut ) -{ - for( int i=0; i<(int)vbSelectedOut.size(); i++ ) - vbSelectedOut[i] = i==iSelection; -} +//if( row.selectType != SELECT_MULTIPLE ) +//{ +// // The first row ("go down") should not be selected. +// ASSERT( !vbSelectedOut[0] ); -void ScreenOptionsMaster::ImportOption( const OptionRowDefinition &row, const OptionRowHandler &hand, PlayerNumber pn, int rowno, vector &vbSelectedOut ) -{ - /* Figure out which selection is the default. */ - switch( hand.type ) - { - case ROW_LIST: - { - int FallbackOption = -1; - bool UseFallbackOption = true; - - for( unsigned e = 0; e < hand.ListEntries.size(); ++e ) - { - const GameCommand &mc = hand.ListEntries[e]; - - vbSelectedOut[e] = false; - - if( mc.IsZero() ) - { - /* The entry has no effect. This is usually a default "none of the - * above" entry. It will always return true for DescribesCurrentMode(). - * It's only the selected choice if nothing else matches. */ - if( row.selectType != SELECT_MULTIPLE ) - FallbackOption = e; - continue; - } - - if( row.bOneChoiceForAllPlayers ) - { - if( mc.DescribesCurrentModeForAllPlayers() ) - { - UseFallbackOption = false; - if( row.selectType != SELECT_MULTIPLE ) - SelectExactlyOne( e, vbSelectedOut ); - else - vbSelectedOut[e] = true; - } - } - else - { - if( mc.DescribesCurrentMode( pn) ) - { - UseFallbackOption = false; - if( row.selectType != SELECT_MULTIPLE ) - SelectExactlyOne( e, vbSelectedOut ); - else - vbSelectedOut[e] = true; - } - } - } - - if( row.selectType == SELECT_ONE && - UseFallbackOption && - FallbackOption != -1 ) - { - SelectExactlyOne( FallbackOption, vbSelectedOut ); - } - - return; - } - - case ROW_LUA: - { - ASSERT( lua_gettop(LUA->L) == 0 ); - - /* Evaluate the LoadSelections(self,array,pn) function, where array is a table - * representing vbSelectedOut. */ - - /* Hack: the NextRow entry is never set, and should be transparent. Remove - * it, and readd it below. */ - if( m_OptionsNavigation == NAV_TOGGLE_THREE_KEY ) - vbSelectedOut.erase( vbSelectedOut.begin() ); - - /* All selections default to false. */ - for( unsigned i = 0; i < vbSelectedOut.size(); ++i ) - vbSelectedOut[i] = false; - - /* Create the vbSelectedOut table. */ - LUA->CreateTableFromArrayB( vbSelectedOut ); - ASSERT( lua_gettop(LUA->L) == 1 ); /* vbSelectedOut table */ - - /* Get the function to call from m_LuaTable. */ - hand.m_pLuaTable->PushSelf( LUA->L ); - ASSERT( lua_istable( LUA->L, -1 ) ); - - lua_pushstring( LUA->L, "LoadSelections" ); - lua_gettable( LUA->L, -2 ); - if( !lua_isfunction( LUA->L, -1 ) ) - RageException::Throw( "\"%s\" \"LoadSelections\" entry is not a function", row.name.c_str() ); - - /* Argument 1 (self): */ - hand.m_pLuaTable->PushSelf( LUA->L ); - - /* Argument 2 (vbSelectedOut): */ - lua_pushvalue( LUA->L, 1 ); - - /* Argument 3 (pn): */ - LUA->PushStack( (int) pn ); - - ASSERT( lua_gettop(LUA->L) == 6 ); /* vbSelectedOut, m_iLuaTable, function, self, arg, arg */ - - lua_call( LUA->L, 3, 0 ); // call function with 3 arguments and 0 results - ASSERT( lua_gettop(LUA->L) == 2 ); - - lua_pop( LUA->L, 1 ); /* pop option table */ - - LUA->ReadArrayFromTableB( vbSelectedOut ); - if( m_OptionsNavigation == NAV_TOGGLE_THREE_KEY ) - vbSelectedOut.insert( vbSelectedOut.begin(), false ); - - lua_pop( LUA->L, 1 ); /* pop vbSelectedOut table */ - - ASSERT( lua_gettop(LUA->L) == 0 ); - return; - } - - case ROW_CONFIG: - { - int iSelection = hand.opt->Get(); - SelectExactlyOne( iSelection+(m_OptionsNavigation==NAV_TOGGLE_THREE_KEY?1:0), vbSelectedOut ); - return; - } - - default: - ASSERT(0); - } - - if( row.selectType != SELECT_MULTIPLE ) - { - // The first row ("go down") should not be selected. - ASSERT( !vbSelectedOut[0] ); - - // there should be exactly one option selected - int iNumSelected = 0; - for( unsigned e = 1; e < hand.ListEntries.size(); ++e ) - if( vbSelectedOut[e] ) - iNumSelected++; - ASSERT( iNumSelected == 1 ); - } -} +// // there should be exactly one option selected +// int iNumSelected = 0; +// for( unsigned e = 1; e < pHand->ListEntries.size(); ++e ) +// if( vbSelectedOut[e] ) +// iNumSelected++; +// ASSERT( iNumSelected == 1 ); +//} void ScreenOptionsMaster::ImportOptions( int r ) { - const OptionRowHandler &hand = OptionRowHandlers[r]; + const OptionRowHandler *pHand = OptionRowHandlers[r]; const OptionRowDefinition &def = m_OptionRowAlloc[r]; OptionRow &row = *m_Rows[r]; + /* Hack: the NextRow entry is never set, and should be transparent. Remove + * it, and readd it below. */ + if( m_OptionsNavigation == NAV_TOGGLE_THREE_KEY ) + { + if( def.bOneChoiceForAllPlayers ) + row.m_vbSelected[0].erase( row.m_vbSelected[0].begin() ); + else + FOREACH_HumanPlayer( p ) + row.m_vbSelected[p].erase( row.m_vbSelected[p].begin() ); + } + if( def.bOneChoiceForAllPlayers ) { - ImportOption(def, hand, PLAYER_1, r, row.m_vbSelected[0] ); + pHand->ImportOption(def, PLAYER_1, row.m_vbSelected[0] ); } else { FOREACH_HumanPlayer( p ) - ImportOption( def, hand, p, r, row.m_vbSelected[p] ); + pHand->ImportOption( def, p, row.m_vbSelected[p] ); + } + + if( m_OptionsNavigation == NAV_TOGGLE_THREE_KEY ) + { + if( def.bOneChoiceForAllPlayers ) + row.m_vbSelected[0].insert( row.m_vbSelected[0].begin(), false ); + else + FOREACH_HumanPlayer( p ) + row.m_vbSelected[p].insert( row.m_vbSelected[p].begin(), false ); } } @@ -748,125 +211,26 @@ void ScreenOptionsMaster::ImportOptionsForPlayer( PlayerNumber pn ) for( unsigned i = 0; i < OptionRowHandlers.size(); ++i ) { - const OptionRowHandler &hand = OptionRowHandlers[i]; + const OptionRowHandler *pHand = OptionRowHandlers[i]; const OptionRowDefinition &def = m_OptionRowAlloc[i]; OptionRow &row = *m_Rows[i]; if( def.bOneChoiceForAllPlayers ) continue; - ImportOption( def, hand, pn, i, row.m_vbSelected[pn] ); + pHand->ImportOption( def, pn, row.m_vbSelected[pn] ); } } -int GetOneSelection( const vector &vbSelected ) -{ - for( unsigned i=0; i &vbSelected ) -{ - /* Figure out which selection is the default. */ - switch( hand.type ) - { - case ROW_LIST: - { - hand.Default.Apply( pn ); - for( unsigned i=0; iL) == 0 ); - - /* Evaluate SaveSelections(self,array,pn) function, where array is a table - * representing vbSelectedOut. */ - - /* Hack: the NextRow entry is never set, and should be transparent. Remove it. */ - vector vbSelectedCopy = vbSelected; - if( m_OptionsNavigation == NAV_TOGGLE_THREE_KEY ) - vbSelectedCopy.erase( vbSelectedCopy.begin() ); - - /* Create the vbSelectedOut table. */ - LUA->CreateTableFromArrayB( vbSelectedCopy ); - ASSERT( lua_gettop(LUA->L) == 1 ); /* vbSelectedOut table */ - - /* Get the function to call. */ - hand.m_pLuaTable->PushSelf( LUA->L ); - ASSERT( lua_istable( LUA->L, -1 ) ); - - lua_pushstring( LUA->L, "SaveSelections" ); - lua_gettable( LUA->L, -2 ); - if( !lua_isfunction( LUA->L, -1 ) ) - RageException::Throw( "\"%s\" \"SaveSelections\" entry is not a function", row.name.c_str() ); - - /* Argument 1 (self): */ - hand.m_pLuaTable->PushSelf( LUA->L ); - - /* Argument 2 (vbSelectedOut): */ - lua_pushvalue( LUA->L, 1 ); - - /* Argument 3 (pn): */ - LUA->PushStack( (int) pn ); - - ASSERT( lua_gettop(LUA->L) == 6 ); /* vbSelectedOut, m_iLuaTable, function, self, arg, arg */ - - lua_call( LUA->L, 3, 0 ); // call function with 3 arguments and 0 results - ASSERT( lua_gettop(LUA->L) == 2 ); - - lua_pop( LUA->L, 1 ); /* pop option table */ - lua_pop( LUA->L, 1 ); /* pop vbSelected table */ - - ASSERT( lua_gettop(LUA->L) == 0 ); - - // XXX: allow specifying the mask - return 0; - } - - case ROW_CONFIG: - { - int sel = GetOneSelection(vbSelected) - (m_OptionsNavigation==NAV_TOGGLE_THREE_KEY?1:0); - - /* Get the original choice. */ - int Original = hand.opt->Get(); - - /* Apply. */ - hand.opt->Put( sel ); - - /* Get the new choice. */ - int New = hand.opt->Get(); - - /* If it didn't change, don't return any side-effects. */ - if( Original == New ) - return 0; - - return hand.opt->GetEffects(); - } - break; - - default: - ASSERT(0); - break; - } - return 0; -} - void ScreenOptionsMaster::ExportOptions( int iRow ) { - const OptionRowHandler &hand = OptionRowHandlers[iRow]; + const OptionRowHandler *pHand = OptionRowHandlers[iRow]; const OptionRowDefinition &def = m_OptionRowAlloc[iRow]; OptionRow &row = *m_Rows[iRow]; FOREACH_HumanPlayer( pn ) { vector &vbSelected = row.m_vbSelected[pn]; - m_iChangeMask |= ExportOption( def, hand, pn, vbSelected ); + m_iChangeMask |= pHand->ExportOption( def, pn, vbSelected ); } } @@ -917,17 +281,8 @@ void ScreenOptionsMaster::RefreshIcons() } else if( iFirstSelection != -1 ) { - const OptionRowHandler &handler = OptionRowHandlers[i]; - switch( handler.type ) - { - case ROW_LIST: - sIcon = handler.m_bUseModNameForIcon ? - handler.ListEntries[iFirstSelection].m_sModifiers : - def.choices[iFirstSelection]; - break; - case ROW_CONFIG: - break; - } + const OptionRowHandler *pHand = OptionRowHandlers[i]; + sIcon = pHand->GetIconText( def, iFirstSelection ); } @@ -946,12 +301,12 @@ void ScreenOptionsMaster::ChangeValueInRow( PlayerNumber pn, int iDelta, bool Re int iRow = m_iCurrentRow[pn]; - const OptionRowHandler &hand = OptionRowHandlers[iRow]; + const OptionRowHandler *pHand = OptionRowHandlers[iRow]; - if( hand.m_bExportOnChange || !hand.m_vsRefreshRowNames.empty() ) + if( pHand->m_bExportOnChange || !pHand->m_vsRefreshRowNames.empty() ) ExportOptions( iRow ); - FOREACH_CONST( CString, hand.m_vsRefreshRowNames, sRowToRefreshName ) + FOREACH_CONST( CString, pHand->m_vsRefreshRowNames, sRowToRefreshName ) { for( unsigned r=0; rm_sName ) { - switch( handOther.type ) - { - case ROW_LIST: - SetList( defOther, handOther, handOther.m_sName ); - break; - case ROW_LUA: - SetLua( defOther, handOther, handOther.m_sName ); - break; - } + pHandOther->Reload( defOther ); ScreenOptions::RefreshRowChoices( r, defOther ); } } @@ -998,33 +345,25 @@ void ScreenOptionsMaster::HandleScreenMessage( const ScreenMessage SM ) * honor it. */ m_sNextScreen = ""; - for( unsigned i = 0; i < OptionRowHandlers.size(); ++i ) + for( unsigned r = 0; r < OptionRowHandlers.size(); ++r ) { - CHECKPOINT_M( ssprintf("%i/%i", i, int(OptionRowHandlers.size())) ); + OptionRow &row = *m_Rows[r]; + + CHECKPOINT_M( ssprintf("%i/%i", r, int(OptionRowHandlers.size())) ); /* If SELECT_NONE, only apply it if it's the selected option. */ - const OptionRowDefinition &def = m_OptionRowAlloc[i]; - if( def.selectType == SELECT_NONE && i != uFocusRow ) + const OptionRowDefinition &def = m_OptionRowAlloc[r]; + if( def.selectType == SELECT_NONE && r != uFocusRow ) continue; - OptionRowHandler &hand = OptionRowHandlers[i]; + OptionRowHandler *pHand = OptionRowHandlers[r]; - if( hand.type == ROW_LIST ) - { - const int choice = m_Rows[i]->m_iChoiceInRowWithFocus[GAMESTATE->m_MasterPlayerNumber]; - GameCommand &mc = hand.ListEntries[choice]; - if( mc.m_sScreen != "" ) - { - /* Hack: instead of applying screen commands here, store them in - * m_sNextScreen and apply them after we tween out. If we don't set - * m_sScreen to "", we'll load it twice (once for each player) and - * then again for m_sNextScreen. */ - m_sNextScreen = mc.m_sScreen; - mc.m_sScreen = ""; - } - } + const int iChoice = row.m_iChoiceInRowWithFocus[GAMESTATE->m_MasterPlayerNumber]; + CString sScreen = pHand->GetAndEraseScreen( iChoice ); + if( !sScreen.empty() ) + m_sNextScreen = sScreen; - ExportOptions( i ); + ExportOptions( r ); } CHECKPOINT; diff --git a/stepmania/src/ScreenOptionsMaster.h b/stepmania/src/ScreenOptionsMaster.h index 7e22350298..5ad0ad0b28 100644 --- a/stepmania/src/ScreenOptionsMaster.h +++ b/stepmania/src/ScreenOptionsMaster.h @@ -2,18 +2,8 @@ #define SCREEN_OPTIONS_MASTER_H #include "ScreenOptions.h" -#include "GameCommand.h" -#include "LuaReference.h" -struct ConfOption; - -enum OptionRowHandlerType -{ - ROW_LIST, /* list of custom settings */ - ROW_LUA, /* lua tells us what to do */ - ROW_CONFIG, /* global pref */ - NUM_OPTION_ROW_TYPES -}; +class OptionRowHandler; class ScreenOptionsMaster: public ScreenOptions { @@ -25,57 +15,12 @@ public: protected: - struct OptionRowHandler - { - OptionRowHandler() { m_pLuaTable=NULL; Init(); } - void Init() - { - type = ROW_LIST; - m_sName = ""; - m_vsRefreshRowNames.clear(); - ListEntries.clear(); - Default.Init(); - m_bUseModNameForIcon = false; - delete m_pLuaTable; - m_pLuaTable = new LuaExpression; - opt = NULL; - } - - OptionRowHandlerType type; - CString m_sName; - bool m_bExportOnChange; - vector m_vsRefreshRowNames; // refresh these rows when the value of this row changes - - /* ROW_LIST: */ - vector ListEntries; - GameCommand Default; - bool m_bUseModNameForIcon; - - /* ROW_LUA: */ - LuaExpression *m_pLuaTable; - - /* ROW_CONFIG: */ - const ConfOption *opt; - }; - int m_iChangeMask; CString m_sNextScreen; - vector OptionRowHandlers; - OptionRowDefinition *m_OptionRowAlloc; - - int ExportOption( const OptionRowDefinition &def, const OptionRowHandler &hand, PlayerNumber pn, const vector &vbSelected ); - void ImportOption( const OptionRowDefinition &def, const OptionRowHandler &hand, PlayerNumber pn, int rowno, vector &vbSelectedOut ); + vector OptionRowHandlers; + vector m_OptionRowAlloc; - static void SetList( OptionRowDefinition &def, OptionRowHandler &hand, CString param ); - static void SetLua( OptionRowDefinition &def, OptionRowHandler &hand, const CString &sLuaFunction ); - static void SetSteps( OptionRowDefinition &def, OptionRowHandler &hand ); - static void SetConf( OptionRowDefinition &def, OptionRowHandler &hand, CString param ); - static void SetCharacters( OptionRowDefinition &def, OptionRowHandler &hand ); - static void SetStyles( OptionRowDefinition &def, OptionRowHandler &hand ); - static void SetGroups( OptionRowDefinition &def, OptionRowHandler &hand ); - static void SetDifficulties( OptionRowDefinition &def, OptionRowHandler &hand ); - protected: void HandleScreenMessage( const ScreenMessage SM ); diff --git a/stepmania/src/StepMania.dsp b/stepmania/src/StepMania.dsp index af4b15cc81..e6d4eb1a21 100644 --- a/stepmania/src/StepMania.dsp +++ b/stepmania/src/StepMania.dsp @@ -62,7 +62,7 @@ IntDir=.\../Debug6 TargetDir=\stepmania\stepmania\Program TargetName=StepMania-debug SOURCE="$(InputPath)" -PreLink_Cmds=archutils\Win32\verinc cl /Zl /nologo /c verstub.cpp /Fo$(IntDir)\ +PreLink_Cmds=archutils\Win32\verinc cl /Zl /nologo /c verstub.cpp /Fo$(IntDir)\ PostBuild_Cmds=archutils\Win32\mapconv $(IntDir)\$(TargetName).map $(TargetDir)\StepMania.vdi # End Special Build Tool @@ -99,7 +99,7 @@ IntDir=.\../Release6 TargetDir=\stepmania\stepmania\Program TargetName=StepMania SOURCE="$(InputPath)" -PreLink_Cmds=archutils\Win32\verinc cl /Zl /nologo /c verstub.cpp /Fo$(IntDir)\ +PreLink_Cmds=archutils\Win32\verinc cl /Zl /nologo /c verstub.cpp /Fo$(IntDir)\ PostBuild_Cmds=archutils\Win32\mapconv $(IntDir)\$(TargetName).map $(TargetDir)\StepMania.vdi # End Special Build Tool @@ -980,6 +980,14 @@ SOURCE=.\NoteTypes.h # End Source File # Begin Source File +SOURCE=.\OptionRowHandler.cpp +# End Source File +# Begin Source File + +SOURCE=.\OptionRowHandler.h +# End Source File +# Begin Source File + SOURCE=.\PlayerAI.cpp # End Source File # Begin Source File diff --git a/stepmania/src/StepMania.vcproj b/stepmania/src/StepMania.vcproj index f555f370be..f1e5d552b2 100644 --- a/stepmania/src/StepMania.vcproj +++ b/stepmania/src/StepMania.vcproj @@ -881,6 +881,12 @@ cl /Zl /nologo /c verstub.cpp /Fo"$(IntDir)"\ + + + +