diff --git a/Docs/Luadoc/Lua.xml b/Docs/Luadoc/Lua.xml index 6b2d77b790..113836cd63 100644 --- a/Docs/Luadoc/Lua.xml +++ b/Docs/Luadoc/Lua.xml @@ -1661,6 +1661,7 @@ + diff --git a/Docs/Luadoc/LuaDocumentation.xml b/Docs/Luadoc/LuaDocumentation.xml index 5d4ab8bf66..3c38b158fd 100644 --- a/Docs/Luadoc/LuaDocumentation.xml +++ b/Docs/Luadoc/LuaDocumentation.xml @@ -2181,7 +2181,10 @@ save yourself some time, copy this for undocumented things: Returns a table of all selectable games. - Sets the current game to Game. The second argument is optional, and if provided will determine which theme is loaded when the game changes. If Stepmania was run with a commandline argument setting the theme, that will override the second argument of this function. + Sets the current game to Game. The second argument is optional, and if provided will determine which theme is loaded when the game changes. If the second argument is not provided, the default theme from the preferences for the new game type will be loaded.
+ If only the game changes, the screen specified by the Common::AfterGameChangeScreen metric will be loaded.
+ If the game and the theme both change, the screen specified by the Common::AfterGameAndThemeChangeScreen metric will be loaded.
+ The Common::InitialScreen metric will be used if the appropriate metric for the change is blank or invalid.
@@ -4678,6 +4681,11 @@ save yourself some time, copy this for undocumented things: + + Changes the current theme.
+ After the theme changes, the screen specified by the Common::AfterThemeChangeScreen metric will be loaded.
+ The Common::InitialScreen metric will be used if Common::AfterThemeChangeScreen is blank or invalid. +
diff --git a/src/GameLoop.cpp b/src/GameLoop.cpp index 74ccdb0d6a..4fbe074a5d 100644 --- a/src/GameLoop.cpp +++ b/src/GameLoop.cpp @@ -114,17 +114,24 @@ static void CheckFocus() } // On the next update, change themes, and load sNewScreen. -static RString g_sNewTheme; -static RString g_sNewScreen; +static RString g_NewTheme; static bool g_bForceThemeReload; -void GameLoop::ChangeTheme( const RString &sNewTheme, const RString &sNewScreen, bool bForced ) +static RString g_NewGame; +void GameLoop::ChangeTheme( const RString &sNewTheme, bool bForced ) { - g_sNewTheme = sNewTheme; - g_sNewScreen = sNewScreen; + g_NewTheme = sNewTheme; g_bForceThemeReload = bForced; } +void GameLoop::ChangeGame(const RString& new_game, const RString& new_theme) +{ + g_NewGame= new_game; + g_NewTheme= new_theme; +} + #include "StepMania.h" // XXX +#include "GameManager.h" +#include "Game.h" namespace { void DoChangeTheme() @@ -135,8 +142,8 @@ namespace // In case the previous theme overloaded class bindings, reinitialize them. LUA->RegisterTypes(); - THEME->SwitchThemeAndLanguage( g_sNewTheme, THEME->GetCurLanguage(), PREFSMAN->m_bPseudoLocalize, g_bForceThemeReload ); - PREFSMAN->m_sTheme.Set( g_sNewTheme ); + THEME->SwitchThemeAndLanguage( g_NewTheme, THEME->GetCurLanguage(), PREFSMAN->m_bPseudoLocalize, g_bForceThemeReload ); + PREFSMAN->m_sTheme.Set( g_NewTheme ); // Apply the new window title, icon and aspect ratio. StepMania::ApplyGraphicOptions(); @@ -145,19 +152,97 @@ namespace StepMania::ResetGame(); SCREENMAN->ThemeChanged(); - // Not all themes use the same screen names! Check whether the new - // screen is valid in the new theme before setting it. Use the - // InitialScreen metric if it's not. - if(!SCREENMAN->IsScreenNameValid(g_sNewScreen)) + // The previous system for changing the theme fetched the "NextScreen" + // metric from the current theme, then changed the theme, then tried to + // set the new screen to the name that had been fetched. + // If the new screen didn't exist in the new theme, there would be a + // crash. + // So now the correct thing to do is for a theme to specify its entry + // point after a theme change, ensuring that we are going to a valid + // screen and not crashing. -Kyz + RString new_screen= THEME->GetMetric("Common", "InitialScreen"); + if(THEME->HasMetric("Common", "AfterThemeChangeScreen")) { - g_sNewScreen= THEME->GetMetric("Common", "InitialScreen"); + RString after_screen= THEME->GetMetric("Common", "AfterThemeChangeScreen"); + if(SCREENMAN->IsScreenNameValid(after_screen)) + { + new_screen= after_screen; + } } - SCREENMAN->SetNewScreen( g_sNewScreen ); + SCREENMAN->SetNewScreen(new_screen); - g_sNewTheme = RString(); - g_sNewScreen = RString(); + g_NewTheme = RString(); } + void DoChangeGame() + { + const Game* g= GAMEMAN->StringToGame(g_NewGame); + ASSERT(g != NULL); + GAMESTATE->SetCurGame(g); + + bool theme_changing= false; + // The prefs allow specifying a different default theme to use for each + // game type. So if a theme name isn't passed in, fetch from the prefs. + if(g_NewTheme.empty()) + { + g_NewTheme= PREFSMAN->m_sTheme; + } + if(g_NewTheme != THEME->GetCurThemeName() && THEME->IsThemeSelectable(g_NewTheme)) + { + theme_changing= true; + } + + if(theme_changing) + { + SAFE_DELETE(SCREENMAN); + TEXTUREMAN->DoDelayedDelete(); + LUA->RegisterTypes(); + THEME->SwitchThemeAndLanguage(g_NewTheme, THEME->GetCurLanguage(), + PREFSMAN->m_bPseudoLocalize); + PREFSMAN->m_sTheme.Set(g_NewTheme); + StepMania::ApplyGraphicOptions(); + SCREENMAN= new ScreenManager(); + } + StepMania::ResetGame(); + RString new_screen= THEME->GetMetric("Common", "InitialScreen"); + RString after_screen; + if(theme_changing) + { + SCREENMAN->ThemeChanged(); + if(THEME->HasMetric("Common", "AfterGameAndThemeChangeScreen")) + { + after_screen= THEME->GetMetric("Common", "AfterGameAndThemeChangeScreen"); + } + } + else + { + if(THEME->HasMetric("Common", "AfterGameChangeScreen")) + { + after_screen= THEME->GetMetric("Common", "AfterGameChangeScreen"); + } + } + if(SCREENMAN->IsScreenNameValid(after_screen)) + { + new_screen= after_screen; + } + SCREENMAN->SetNewScreen(new_screen); + + // Set the input scheme for the new game, and load keymaps. + if( INPUTMAPPER ) + { + INPUTMAPPER->SetInputScheme(&g->m_InputScheme); + INPUTMAPPER->ReadMappingsFromDisk(); + } + // aj's comment transplanted from ScreenOptionsMasterPrefs.cpp:GameSel. -Kyz + /* Reload metrics to force a refresh of CommonMetrics::DIFFICULTIES_TO_SHOW, + * mainly if we're not switching themes. I'm not sure if this was the + * case going from theme to theme, but if it was, it should be fixed + * now. There's probably be a better way to do it, but I'm not sure + * what it'd be. -aj */ + THEME->ReloadMetrics(); + g_NewGame= RString(); + g_NewTheme= RString(); + } } void GameLoop::RunGameLoop() @@ -169,8 +254,14 @@ void GameLoop::RunGameLoop() while( !ArchHooks::UserQuit() ) { - if( !g_sNewTheme.empty() ) + if(!g_NewGame.empty()) + { + DoChangeGame(); + } + if(!g_NewTheme.empty()) + { DoChangeTheme(); + } // Update float fDeltaTime = g_GameplayTimer.GetDeltaTime(); diff --git a/src/GameLoop.h b/src/GameLoop.h index 3bbc990acc..df59a0146e 100644 --- a/src/GameLoop.h +++ b/src/GameLoop.h @@ -5,7 +5,8 @@ namespace GameLoop { void RunGameLoop(); void SetUpdateRate( float fUpdateRate ); - void ChangeTheme( const RString &sNewTheme, const RString &sNewScreen, bool bForced = false ); + void ChangeTheme( const RString &sNewTheme, bool bForced = false ); + void ChangeGame(const RString& new_game, const RString& new_theme= ""); void StartConcurrentRendering(); void FinishConcurrentRendering(); }; diff --git a/src/GameManager.cpp b/src/GameManager.cpp index 6999da2a21..9006119391 100644 --- a/src/GameManager.cpp +++ b/src/GameManager.cpp @@ -1,9 +1,10 @@ #include "global.h" -#include "Stepmania.h" +#include "StepMania.h" #include "arch/Dialog/Dialog.h" #include "GameManager.h" #include "GameConstantsAndTypes.h" #include "GameInput.h" // for GameButton constants +#include "GameLoop.h" // for ChangeGame #include "RageLog.h" #include "RageUtil.h" #include "NoteSkinManager.h" @@ -3176,22 +3177,22 @@ public: static int SetGame( T* p, lua_State *L ) { - const Game *pGame = p->StringToGame(SArg(1)); - RString sTheme; + RString game_name= SArg(1); + const Game *pGame = p->StringToGame(game_name); + if(!pGame) + { + luaL_error(L, "SetGame: Invalid Game: '%s'", game_name.c_str()); + } + RString theme; if( lua_gettop(L) >= 2 && !lua_isnil(L, 2) ) { - sTheme = SArg(2); - } - if( pGame ) - { - StepMania::ChangeCurrentGame( pGame, sTheme ); - THEME->ReloadMetrics(); - } - else - { - LOG->Warn( "SetGame: Invalid Game, %s", pGame->m_szName ); - Dialog::OK( "SetGame: Invalid Game, %s", pGame->m_szName ); + theme = SArg(2); + if(!THEME->IsThemeSelectable(theme)) + { + luaL_error(L, "SetGame: Invalid Theme: '%s'", theme.c_str()); + } } + GameLoop::ChangeGame(game_name, theme); return 0; } diff --git a/src/ScreenManager.cpp b/src/ScreenManager.cpp index b8b75aa85d..3421f9689b 100644 --- a/src/ScreenManager.cpp +++ b/src/ScreenManager.cpp @@ -282,34 +282,14 @@ void ScreenManager::ThemeChanged() m_soundInvalid.Load( THEME->GetPathS("Common","invalid") ); m_soundScreenshot.Load( THEME->GetPathS("Common","screenshot") ); - // unload overlay screens - for( unsigned i=0; iGetMetric( "Common","OverlayScreens" ); - vector asOverlays; - split( sOverlays, ",", asOverlays ); - for( unsigned i=0; iGetName() ); - pScreen->BeginScreen(); - g_OverlayScreens.push_back( pScreen ); - } - } - // reload song manager colors (to avoid crashes) -aj SONGMAN->ResetGroupColors(); + ReloadOverlayScreens(); + // force recreate of new BGA SAFE_DELETE( g_pSharedBGA ); g_pSharedBGA = new Actor; - - this->RefreshCreditsMessages(); } void ScreenManager::ReloadOverlayScreens() @@ -369,7 +349,11 @@ bool ScreenManager::AllowOperatorMenuButton() const bool ScreenManager::IsScreenNameValid(RString const& name) const { - RString ClassName = THEME->GetMetric(name,"Class"); + if(name.empty() || !THEME->HasMetric(name, "Class")) + { + return false; + } + RString ClassName = THEME->GetMetric(name, "Class"); return g_pmapRegistrees->find(ClassName) != g_pmapRegistrees->end(); } diff --git a/src/ScreenOptionsMaster.cpp b/src/ScreenOptionsMaster.cpp index ea2aee1428..27b3b70c77 100644 --- a/src/ScreenOptionsMaster.cpp +++ b/src/ScreenOptionsMaster.cpp @@ -4,6 +4,7 @@ #include "RageUtil.h" #include "RageLog.h" #include "ThemeManager.h" +#include "GameManager.h" #include "GameState.h" #include "ScreenManager.h" #include "SongManager.h" @@ -127,8 +128,7 @@ void ScreenOptionsMaster::HandleScreenMessage( const ScreenMessage SM ) * Otherwise, only reload it if it changed. */ RString sNewTheme = PREFSMAN->m_sTheme.Get(); bool bForceThemeReload = !!(m_iChangeMask & OPT_APPLY_ASPECT_RATIO) || !!(m_iChangeMask & OPT_APPLY_GRAPHICS); - GameLoop::ChangeTheme( sNewTheme, this->GetNextScreenName(), bForceThemeReload ); - StepMania::ApplyGraphicOptions(); + GameLoop::ChangeTheme( sNewTheme, bForceThemeReload ); } if( m_iChangeMask & OPT_SAVE_PREFERENCES ) @@ -138,10 +138,9 @@ void ScreenOptionsMaster::HandleScreenMessage( const ScreenMessage SM ) PREFSMAN->SavePrefsToDisk(); } - if( m_iChangeMask & OPT_RESET_GAME ) + if( m_iChangeMask & OPT_CHANGE_GAME ) { - StepMania::ResetGame(); - m_sNextScreen = StepMania::GetInitialScreen(); + GameLoop::ChangeGame(PREFSMAN->GetCurrentGame()); } if( m_iChangeMask & OPT_APPLY_SOUND ) diff --git a/src/ScreenOptionsMasterPrefs.cpp b/src/ScreenOptionsMasterPrefs.cpp index e8c36de2d4..942540c69e 100644 --- a/src/ScreenOptionsMasterPrefs.cpp +++ b/src/ScreenOptionsMasterPrefs.cpp @@ -177,7 +177,7 @@ static void GameSel( int &sel, bool ToSel, const ConfOption *pConfOption ) if( ToSel ) { - const RString sCurGameName = GAMESTATE->m_pCurGame->m_szName; + const RString sCurGameName = PREFSMAN->GetCurrentGame(); sel = 0; for(unsigned i = 0; i < choices.size(); ++i) @@ -186,13 +186,7 @@ static void GameSel( int &sel, bool ToSel, const ConfOption *pConfOption ) } else { vector aGames; GAMEMAN->GetEnabledGames( aGames ); - StepMania::ChangeCurrentGame( aGames[sel] ); - /* Reload metrics to force a refresh of CommonMetrics::DIFFICULTIES_TO_SHOW, - * mainly if we're not switching themes. I'm not sure if this was the - * case going from theme to theme, but if it was, it should be fixed - * now. There's probably be a better way to do it, but I'm not sure - * what it'd be. -aj */ - THEME->ReloadMetrics(); + PREFSMAN->SetCurrentGame(aGames[sel]->m_szName); } } @@ -663,7 +657,7 @@ static void InitializeConfOptions() #define ADD(x) g_ConfOptions.push_back( x ) // Select game ADD( ConfOption( "Game", GameSel, GameChoices ) ); - g_ConfOptions.back().m_iEffects = OPT_RESET_GAME; + g_ConfOptions.back().m_iEffects = OPT_CHANGE_GAME; // Appearance options ADD( ConfOption( "Language", Language, LanguageChoices ) ); diff --git a/src/ScreenOptionsMasterPrefs.h b/src/ScreenOptionsMasterPrefs.h index a9758491e1..ef3eccabbf 100644 --- a/src/ScreenOptionsMasterPrefs.h +++ b/src/ScreenOptionsMasterPrefs.h @@ -5,7 +5,7 @@ static const int MAX_OPTIONS=16; #define OPT_SAVE_PREFERENCES (1<<0) #define OPT_APPLY_GRAPHICS (1<<1) #define OPT_APPLY_THEME (1<<2) -#define OPT_RESET_GAME (1<<3) +#define OPT_CHANGE_GAME (1<<3) #define OPT_APPLY_SOUND (1<<4) #define OPT_APPLY_SONG (1<<5) #define OPT_APPLY_ASPECT_RATIO (1<<6) diff --git a/src/ScreenTitleMenu.cpp b/src/ScreenTitleMenu.cpp index 54febb1625..404aae586f 100644 --- a/src/ScreenTitleMenu.cpp +++ b/src/ScreenTitleMenu.cpp @@ -54,10 +54,12 @@ bool ScreenTitleMenu::Input( const InputEventPlus &input ) if( input.type == IET_FIRST_PRESS ) { // detect codes + // Theme changing pad codes are marked as deprecated in _fallback's + // metrics.ini, remove them after SM5? -Kyz if( CodeDetector::EnteredCode(input.GameI.controller,CODE_NEXT_THEME) || CodeDetector::EnteredCode(input.GameI.controller,CODE_NEXT_THEME2) ) { - GameLoop::ChangeTheme( THEME->GetNextSelectableTheme(), m_sName ); + GameLoop::ChangeTheme(THEME->GetNextSelectableTheme()); bHandled = true; } if( CodeDetector::EnteredCode(input.GameI.controller,CODE_NEXT_ANNOUNCER) || diff --git a/src/StepMania.cpp b/src/StepMania.cpp index be90ff990e..a53766ea32 100644 --- a/src/StepMania.cpp +++ b/src/StepMania.cpp @@ -805,10 +805,11 @@ static void SwitchToLastPlayedGame() ASSERT( GAMEMAN->IsGameEnabled(pGame) ); - StepMania::ChangeCurrentGame( pGame ); + StepMania::InitializeCurrentGame( pGame ); } -void StepMania::ChangeCurrentGame( const Game* g, RString Theme ) +// This function is meant to only be called during start up. +void StepMania::InitializeCurrentGame( const Game* g ) { ASSERT( g != NULL ); ASSERT( GAMESTATE != NULL ); @@ -823,11 +824,9 @@ void StepMania::ChangeCurrentGame( const Game* g, RString Theme ) if( sAnnouncer.empty() ) sAnnouncer = GAMESTATE->GetCurrentGame()->m_szName; - if( sTheme.empty() ) - sTheme = GAMESTATE->GetCurrentGame()->m_szName; - if( Theme.size() ) - sTheme = Theme; - + // It doesn't matter if sTheme is blank or invalid, THEME->STAL will set + // a selectable theme for us. -Kyz + // process theme and language command line arguments; // these change the preferences in order for transparent loading -aj RString argTheme; @@ -1115,7 +1114,7 @@ int main(int argc, char* argv[]) INPUTFILTER = new InputFilter; INPUTMAPPER = new InputMapper; - StepMania::ChangeCurrentGame( GAMESTATE->GetCurrentGame() ); + StepMania::InitializeCurrentGame( GAMESTATE->GetCurrentGame() ); INPUTQUEUE = new InputQueue; SONGINDEX = new SongCacheIndex; diff --git a/src/StepMania.h b/src/StepMania.h index 82baed076b..3b0d284a6f 100644 --- a/src/StepMania.h +++ b/src/StepMania.h @@ -15,7 +15,7 @@ namespace StepMania void ResetGame(); RString GetInitialScreen(); RString GetSelectMusicScreen(); - void ChangeCurrentGame( const Game* g, RString Theme = "" ); + void InitializeCurrentGame(const Game* g); // If successful, return filename of screenshot in sDir, else return "" RString SaveScreenshot( RString Dir, bool SaveCompressed, bool MakeSignature, RString NamePrefix, RString NameSuffix ); diff --git a/src/ThemeManager.cpp b/src/ThemeManager.cpp index fbf70293a6..c80866f4da 100644 --- a/src/ThemeManager.cpp +++ b/src/ThemeManager.cpp @@ -17,6 +17,7 @@ #include "ActorUtil.h" #endif #include "Foreach.h" +#include "GameLoop.h" // For ChangeTheme #include "ThemeMetric.h" #include "SubscriptionManager.h" #include "LuaManager.h" @@ -1341,6 +1342,17 @@ public: return 1; } + static int SetTheme(T* p, lua_State* L) + { + RString theme_name= SArg(1); + if(!p->IsThemeSelectable(theme_name)) + { + luaL_error(L, "SetTheme: Invalid Theme: '%s'", theme_name.c_str()); + } + GameLoop::ChangeTheme(theme_name); + return 0; + } + LunaThemeManager() { ADD_METHOD( ReloadMetrics ); @@ -1367,6 +1379,7 @@ public: ADD_METHOD( HasString ); ADD_METHOD( GetMetricNamesInGroup ); ADD_METHOD( GetStringNamesInGroup ); + ADD_METHOD( SetTheme ); } };