diff --git a/src/CMakeData-screen.cmake b/src/CMakeData-screen.cmake index 93bbd077d6..11f9ce40b0 100644 --- a/src/CMakeData-screen.cmake +++ b/src/CMakeData-screen.cmake @@ -3,13 +3,15 @@ list(APPEND SMDATA_SCREEN_GAMEPLAY_SRC "ScreenGameplayLesson.cpp" "ScreenGameplayNormal.cpp" "ScreenGameplayShared.cpp" - "ScreenGameplaySyncMachine.cpp") + "ScreenGameplaySyncMachine.cpp" + "GameplayHelpers.cpp") list(APPEND SMDATA_SCREEN_GAMEPLAY_HPP "ScreenGameplay.h" "ScreenGameplayNormal.h" "ScreenGameplayShared.h" - "ScreenGameplaySyncMachine.h") + "ScreenGameplaySyncMachine.h" + "GameplayHelpers.h") source_group("Screens\\\\Gameplay" FILES diff --git a/src/GameplayHelpers.cpp b/src/GameplayHelpers.cpp new file mode 100644 index 0000000000..d937b87829 --- /dev/null +++ b/src/GameplayHelpers.cpp @@ -0,0 +1,57 @@ +#include + +#include "global.h" + +#include "EnumHelper.h" +#include "GameplayHelpers.h" +#include "GameState.h" +#include "LuaManager.h" +#include "ThemeManager.h" +#include "Style.h" + +std::vector GetNotefieldMargins() { + LuaReference margin_func; + std::vector margins(2); + + THEME->GetMetric("ScreenGameplay", "MarginFunction", margin_func); + if (margin_func.GetLuaType() != LUA_TFUNCTION) + { + LuaHelpers::ReportScriptErrorFmt("MarginFunction metric for %s must be a function.", "ScreenGameplay"); + return margins; + } + + // Setup the lua. + Lua* lua_ptr = LUA->Get(); + margin_func.PushSelf(lua_ptr); + lua_createtable(lua_ptr, 0, 0); + int next_player_slot = 1; + FOREACH_EnabledPlayer(pn) + { + Enum::Push(lua_ptr, pn); + lua_rawseti(lua_ptr, -2, next_player_slot); + ++next_player_slot; + } + + Enum::Push(lua_ptr, GAMESTATE->GetCurrentStyle(PLAYER_INVALID)->m_StyleType); + RString err = "Error running MarginFunction: "; + + // Run the lua code. + if (LuaHelpers::RunScriptOnStack(lua_ptr, /*Error=*/err, /*Args=*/2, /*ReturnValues*/3, /*ReportOnError*/true)) + { + std::string margin_error_msg = "Margin value must be a number."; + + // Pull the values off the lua stack. Note that the lua function is + // returning the margins of P1 + P2 combined. Therefore, we need to use + // the center to tell where P1's margin ends and P2's begins, if + // applicable. + margins[PLAYER_1].left = SafeFArg(lua_ptr, -3, margin_error_msg, 40); + float center = SafeFArg(lua_ptr, -2, margin_error_msg, 80); + margins[PLAYER_1].right = center / 2.0f; + + margins[PLAYER_2].left = center / 2.0f; + margins[PLAYER_2].right = SafeFArg(lua_ptr, -1, margin_error_msg, 40); + } + lua_settop(lua_ptr, 0); + LUA->Release(lua_ptr); + return margins; +} diff --git a/src/GameplayHelpers.h b/src/GameplayHelpers.h new file mode 100644 index 0000000000..d18a2b8f13 --- /dev/null +++ b/src/GameplayHelpers.h @@ -0,0 +1,16 @@ +#include + + +// A very simple pair floats that represent the pixels of the left and right +// sides of a player's notefield margins. 40 is an arbitrary default value for +// the margins. +struct NotefieldMargins { + float left = 40; + float right = 40; +}; + +// Use the lua MarginFunction (defined in metrics.ini) to calculate where the notefields +// should be. This should (but doesn't have to) the engine's CenterP1 preference. +// +// By default points to GameplayMargins in Themes/_fallback/Scripts/03 Gameplay.lua +std::vector GetNotefieldMargins(); diff --git a/src/ScreenGameplay.cpp b/src/ScreenGameplay.cpp index 1012a81a0b..7b706e3cb0 100644 --- a/src/ScreenGameplay.cpp +++ b/src/ScreenGameplay.cpp @@ -60,6 +60,7 @@ #include "XmlFileUtil.h" #include "Profile.h" // for replay data stuff #include "RageDisplay.h" +#include "GameplayHelpers.h" #include #include @@ -519,48 +520,7 @@ void ScreenGameplay::Init() this->AddChild( &m_Toasty ); } - // Use the margin function to calculate where the notefields should be and - // what size to zoom them to. This way, themes get margins to put cut-ins - // in, and the engine can have players on different styles without the - // notefields overlapping. -Kyz - LuaReference margarine; - float margins[NUM_PLAYERS][2]; - FOREACH_PlayerNumber(pn) - { - margins[pn][0]= 40; - margins[pn][1]= 40; - } - THEME->GetMetric(m_sName, "MarginFunction", margarine); - if(margarine.GetLuaType() != LUA_TFUNCTION) - { - LuaHelpers::ReportScriptErrorFmt("MarginFunction metric for %s must be a function.", m_sName.c_str()); - } - else - { - Lua* L= LUA->Get(); - margarine.PushSelf(L); - lua_createtable(L, 0, 0); - int next_player_slot= 1; - FOREACH_EnabledPlayer(pn) - { - Enum::Push(L, pn); - lua_rawseti(L, -2, next_player_slot); - ++next_player_slot; - } - Enum::Push(L, GAMESTATE->GetCurrentStyle(PLAYER_INVALID)->m_StyleType); - RString err= "Error running MarginFunction: "; - if(LuaHelpers::RunScriptOnStack(L, err, 2, 3, true)) - { - RString marge= "Margin value must be a number."; - margins[PLAYER_1][0]= SafeFArg(L, -3, marge, 40); - float center= SafeFArg(L, -2, marge, 80); - margins[PLAYER_1][1]= center / 2.0f; - margins[PLAYER_2][0]= center / 2.0f; - margins[PLAYER_2][1]= SafeFArg(L, -1, marge, 40); - } - lua_settop(L, 0); - LUA->Release(L); - } + std::vector margins = GetNotefieldMargins(); float left_edge[NUM_PLAYERS]= {0.0f, SCREEN_WIDTH / 2.0f}; FOREACH_EnabledPlayerInfo( m_vPlayerInfo, pi ) @@ -579,8 +539,8 @@ void ScreenGameplay::Init() { \ edge= 0.0f; \ screen_space= SCREEN_WIDTH; \ - left_marge= margins[PLAYER_1][0]; \ - right_marge= margins[PLAYER_2][1]; \ + left_marge= margins[PLAYER_1].left; \ + right_marge= margins[PLAYER_2].right; \ field_space= screen_space - left_marge - right_marge; \ } // If pi->m_pn is set, then the player will be visible. If not, then it's not @@ -590,8 +550,8 @@ void ScreenGameplay::Init() else { screen_space= SCREEN_WIDTH / 2.0f; - left_marge= margins[pi->m_pn][0]; - right_marge= margins[pi->m_pn][1]; + left_marge= margins[pi->m_pn].left; + right_marge= margins[pi->m_pn].right; field_space= screen_space - left_marge - right_marge; if(Center1Player() || style->m_StyleType == StyleType_TwoPlayersSharedSides ||