diff --git a/src/ObjLoading/Parsing/Menu/Matcher/MenuMatcherFactory.cpp b/src/ObjLoading/Parsing/Menu/Matcher/MenuMatcherFactory.cpp index e8686b47..fb3134c5 100644 --- a/src/ObjLoading/Parsing/Menu/Matcher/MenuMatcherFactory.cpp +++ b/src/ObjLoading/Parsing/Menu/Matcher/MenuMatcherFactory.cpp @@ -2,6 +2,7 @@ #include "MenuExpressionMatchers.h" +#include #include using namespace menu; @@ -42,6 +43,22 @@ MatcherFactoryWrapper MenuMatcherFactory::Text() const })); } +MatcherFactoryWrapper MenuMatcherFactory::TextOrNumeric() const +{ + return Or({ + Text(), + Numeric().Transform( + [](const token_list_t& tokens) -> SimpleParserValue + { + const auto& token = tokens[0].get(); + if (token.m_type == SimpleParserValueType::INTEGER) + return SimpleParserValue::String(token.GetPos(), new std::string(std::to_string(token.IntegerValue()))); + + return SimpleParserValue::String(token.GetPos(), new std::string(std::format("{:g}", token.FloatingPointValue()))); + }), + }); +} + MatcherFactoryWrapper MenuMatcherFactory::TextNoChain() const { return MatcherFactoryWrapper(Or({ diff --git a/src/ObjLoading/Parsing/Menu/Matcher/MenuMatcherFactory.h b/src/ObjLoading/Parsing/Menu/Matcher/MenuMatcherFactory.h index cf766b6b..9ba057ad 100644 --- a/src/ObjLoading/Parsing/Menu/Matcher/MenuMatcherFactory.h +++ b/src/ObjLoading/Parsing/Menu/Matcher/MenuMatcherFactory.h @@ -25,6 +25,7 @@ namespace menu [[nodiscard]] MatcherFactoryWrapper StringChain() const; [[nodiscard]] MatcherFactoryWrapper Text() const; + [[nodiscard]] MatcherFactoryWrapper TextOrNumeric() const; [[nodiscard]] MatcherFactoryWrapper TextNoChain() const; [[nodiscard]] MatcherFactoryWrapper Numeric() const; diff --git a/src/ObjLoading/Parsing/Menu/Sequence/ItemScopeSequences.cpp b/src/ObjLoading/Parsing/Menu/Sequence/ItemScopeSequences.cpp index 2b7d36b9..fa3be032 100644 --- a/src/ObjLoading/Parsing/Menu/Sequence/ItemScopeSequences.cpp +++ b/src/ObjLoading/Parsing/Menu/Sequence/ItemScopeSequences.cpp @@ -308,10 +308,10 @@ namespace menu::item_scope_sequences create.KeywordIgnoreCase(std::move(keyName)).Capture(CAPTURE_FIRST_TOKEN), create.Char('{'), create.Optional(create.And({ - create.Text().Capture(CAPTURE_VALUE), + create.TextOrNumeric().Capture(CAPTURE_VALUE), create.OptionalLoop(create.And({ create.Char(';'), - create.Text().Capture(CAPTURE_VALUE), + create.TextOrNumeric().Capture(CAPTURE_VALUE), })), })), create.Char('}'), diff --git a/test/ObjLoadingTests/Game/IW4/Menu/LoaderMenuListIW4Test.cpp b/test/ObjLoadingTests/Game/IW4/Menu/LoaderMenuListIW4Test.cpp index d7106179..c2282f74 100644 --- a/test/ObjLoadingTests/Game/IW4/Menu/LoaderMenuListIW4Test.cpp +++ b/test/ObjLoadingTests/Game/IW4/Menu/LoaderMenuListIW4Test.cpp @@ -301,6 +301,36 @@ namespace test::game::iw4::menu::parsing::it REQUIRE(menu->items == nullptr); } + TEST_CASE("MenuParsingIW4IT: Can use numeric focus dvar values", "[parsing][converting][menu][it]") + { + MenuParsingItHelper helper; + + helper.AddFile(R"testmenu( +{ + menuDef + { + name "NumericFocusDvar" + itemDef + { + focusDvar { 0; 1.5; -2 } + } + } +} + )testmenu"); + + const auto result = helper.RunIntegrationTest(); + REQUIRE(result.HasBeenSuccessful()); + + const auto* menu = helper.GetMenuAsset("NumericFocusDvar"); + REQUIRE(menu->itemCount == 1); + REQUIRE(menu->items != nullptr); + + const auto* item = menu->items[0]; + REQUIRE(item != nullptr); + REQUIRE(item->enableDvar == R"("0" "1.5" "-2" )"s); + REQUIRE(item->dvarFlags == ITEM_DVAR_FLAG_FOCUS); + } + TEST_CASE("MenuParsingIW4IT: Can specify event handler multiple times", "[parsing][converting][menu][it]") { MenuParsingItHelper helper;