diff --git a/stepmania/src/ActorUtil.cpp b/stepmania/src/ActorUtil.cpp index 55c5847035..bf17dc938b 100644 --- a/stepmania/src/ActorUtil.cpp +++ b/stepmania/src/ActorUtil.cpp @@ -109,7 +109,7 @@ retry: } -Actor* ActorUtil::LoadFromActorFile( const CString& sAniDir, const XNode* pNode ) +Actor* ActorUtil::LoadFromActorFile( const CString& sDir, const XNode* pNode ) { ASSERT( pNode ); @@ -122,6 +122,43 @@ Actor* ActorUtil::LoadFromActorFile( const CString& sAniDir, const XNode* pNode } } + // Load Params + { + FOREACH_CONST_Child( pNode, pChild ) + { + if( pChild->m_sName == "Param" ) + { + CString sName; + if( !pChild->GetAttrValue( "Name", sName ) ) + { + RageException::Throw( ssprintf("Param node in '%s' is missing the attribute 'Name'", sDir.c_str()) ); + } + + CString s; + if( pChild->GetAttrValue( "Function", s ) ) + { + LuaExpression expr; + expr.SetFromExpression( s ); + Lua *L = LUA->Get(); + expr.PushSelf( L ); + ASSERT( !lua_isnil(L, -1) ); + lua_call( L, 0, 1 ); // 0 args, 1 results + lua_setglobal( L, sName ); + LUA->Release(L); + } + else if( pChild->GetAttrValue( "Value", s ) ) + { + LUA->SetGlobalFromExpression( sName, s ); + } + else + { + RageException::Throw( ssprintf("Param node in '%s' is missing the attribute 'Function' or 'Value'", sDir.c_str()) ); + } + } + } + } + + // Element name is the type in XML. // Type= is the name in INI. CString sClass = pNode->m_sName; @@ -135,7 +172,7 @@ Actor* ActorUtil::LoadFromActorFile( const CString& sAniDir, const XNode* pNode if( sFile == "" ) { CString sError = ssprintf( "The actor file in '%s' is as a blank, invalid File attribute \"%s\"", - sAniDir.c_str(), sClass.c_str() ); + sDir.c_str(), sClass.c_str() ); RageException::Throw( sError ); } } @@ -160,10 +197,11 @@ Actor* ActorUtil::LoadFromActorFile( const CString& sAniDir, const XNode* pNode else if( sFile.CompareNoCase("coursebanner") == 0 ) sClass = "CourseBanner"; + Actor *pReturn = NULL; if( IsRegistered(sClass) ) { - return ActorUtil::Create( sClass, sAniDir, pNode ); + pReturn = ActorUtil::Create( sClass, sDir, pNode ); } else if( sClass == "SongBackground" ) { @@ -178,8 +216,8 @@ Actor* ActorUtil::LoadFromActorFile( const CString& sAniDir, const XNode* pNode * with duplicates. */ Sprite* pSprite = new Sprite; pSprite->LoadBG( sFile ); - pSprite->LoadFromNode( sAniDir, pNode ); - return pSprite; + pSprite->LoadFromNode( sDir, pNode ); + pReturn = pSprite; } else if( sClass == "SongBanner" ) { @@ -195,9 +233,9 @@ Actor* ActorUtil::LoadFromActorFile( const CString& sAniDir, const XNode* pNode * with duplicates. */ Sprite* pSprite = new Sprite; pSprite->Load( Sprite::SongBannerTexture(sFile) ); - pSprite->LoadFromNode( sAniDir, pNode ); + pSprite->LoadFromNode( sDir, pNode ); TEXTUREMAN->EnableOddDimensionWarning(); - return pSprite; + pReturn = pSprite; } else if( sClass == "CourseBanner" ) { @@ -210,9 +248,9 @@ Actor* ActorUtil::LoadFromActorFile( const CString& sAniDir, const XNode* pNode TEXTUREMAN->DisableOddDimensionWarning(); Sprite* pSprite = new Sprite; pSprite->Load( Sprite::SongBannerTexture(sFile) ); - pSprite->LoadFromNode( sAniDir, pNode ); + pSprite->LoadFromNode( sDir, pNode ); TEXTUREMAN->EnableOddDimensionWarning(); - return pSprite; + pReturn = pSprite; } else // sClass is empty or garbage (e.g. "1" // 0==Sprite") { @@ -222,21 +260,41 @@ Actor* ActorUtil::LoadFromActorFile( const CString& sAniDir, const XNode* pNode if( sFile == "" ) { CString sError = ssprintf( "The actor file in '%s' is missing the File attribute or has an invalid Class \"%s\"", - sAniDir.c_str(), sClass.c_str() ); + sDir.c_str(), sClass.c_str() ); Dialog::OK( sError ); - return NULL; + goto all_done; } - CString sNewPath = bIsAbsolutePath ? sFile : sAniDir+sFile; + CString sNewPath = bIsAbsolutePath ? sFile : sDir+sFile; - ActorUtil::ResolvePath( sNewPath, sAniDir ); + ActorUtil::ResolvePath( sNewPath, sDir ); - Actor *pActor = ActorUtil::MakeActor( sNewPath ); - if( pActor == NULL ) - return NULL; - pActor->LoadFromNode( sAniDir, pNode ); - return pActor; + pReturn = ActorUtil::MakeActor( sNewPath ); + if( pReturn == NULL ) + goto all_done; + pReturn->LoadFromNode( sDir, pNode ); } + +all_done: + + // Unload Params + { + FOREACH_CONST_Child( pNode, pChild ) + { + if( pChild->m_sName == "Param" ) + { + CString sName; + if( !pChild->GetAttrValue( "Name", sName ) ) + { + RageException::Throw( ssprintf("Param node in '%s' is missing the attribute 'Name'", sDir.c_str()) ); + } + + LUA->UnsetGlobal( sName ); + } + } + } + + return pReturn; } Actor* ActorUtil::MakeActor( const RageTextureID &ID ) diff --git a/stepmania/src/LuaManager.cpp b/stepmania/src/LuaManager.cpp index 3b436885a0..00c6dcf599 100644 --- a/stepmania/src/LuaManager.cpp +++ b/stepmania/src/LuaManager.cpp @@ -73,6 +73,24 @@ void LuaManager::SetGlobal( const CString &sName, const CString &val ) LUA->Release(L); } +void LuaManager::SetGlobalFromExpression( const CString &sName, const CString &expr ) +{ + Lua *L = LUA->Get(); + if( !LuaHelpers::RunScript(L, "return " + expr, "", 1) ) + { + LUA->Release(L); + return; + } + + /* Don't accept a function as a return value. */ + if( lua_isfunction( L, -1 ) ) + RageException::Throw( "result is a function; did you forget \"()\"?" ); + + lua_setglobal( L, sName ); + + LUA->Release(L); +} + void LuaManager::UnsetGlobal( const CString &sName ) { Lua *L = LUA->Get(); diff --git a/stepmania/src/LuaManager.h b/stepmania/src/LuaManager.h index fefa81cff9..223436e83d 100644 --- a/stepmania/src/LuaManager.h +++ b/stepmania/src/LuaManager.h @@ -34,6 +34,7 @@ public: void SetGlobal( const CString &sName, int val ); void SetGlobal( const CString &sName, bool val ); void SetGlobal( const CString &sName, const CString &val ); + void SetGlobalFromExpression( const CString &sName, const CString &expr ); void UnsetGlobal( const CString &sName ); private: