diff --git a/soh/soh/Enhancements/randomizer/location_access.cpp b/soh/soh/Enhancements/randomizer/location_access.cpp index 8348a9f34..ba035c9c5 100644 --- a/soh/soh/Enhancements/randomizer/location_access.cpp +++ b/soh/soh/Enhancements/randomizer/location_access.cpp @@ -909,38 +909,48 @@ void RegionTable_Init() { } } -#if 0 // Print all conditions for debugging +#if 1 // Print all conditions for debugging // RANDOTODO: Remove before merging - std::ostringstream ss; + if (Rando::Context::GetInstance()->GetLogic()->mSaveContext != nullptr) { + std::function)> eval; + eval = [&eval](std::shared_ptr expression) { + expression->Evaluate(); + for (auto& child : expression->GetChildren()) { + eval(child); + } + }; - for (uint32_t i = RR_ROOT; i <= RR_GANONS_CASTLE; i++) { - for (EventAccess& eventAccess : areaTable[i].events) { - try { - LogicExpression::Parse(eventAccess.GetConditionStr()); + std::ostringstream ss; + + for (uint32_t i = RR_ROOT; i <= RR_GANONS_CASTLE; i++) { + for (EventAccess& eventAccess : areaTable[i].events) { + try { + eval(LogicExpression::Parse(eventAccess.GetConditionStr())); + } catch (std::exception& ex) { + ss << eventAccess.GetConditionStr() << std::endl; + ss << ex.what() << std::endl << std::endl; + } } - catch (std::exception& ex) { - ss << eventAccess.GetConditionStr() << std::endl; - } - } - for (LocationAccess& locPair : areaTable[i].locations) { - try { - LogicExpression::Parse(locPair.GetConditionStr()); - } - catch (std::exception& ex) { - ss << locPair.GetConditionStr() << std::endl; - } - } - for (Entrance& exit : areaTable[i].exits) { - try { - LogicExpression::Parse(exit.GetConditionStr()); - } - catch (std::exception& ex) { - ss << exit.GetConditionStr() << std::endl; + for (LocationAccess& locPair : areaTable[i].locations) { + try { + eval(LogicExpression::Parse(locPair.GetConditionStr())); + } catch (std::exception& ex) { + ss << locPair.GetConditionStr() << std::endl; + ss << ex.what() << std::endl << std::endl; + } + } + for (Entrance& exit : areaTable[i].exits) { + try { + eval(LogicExpression::Parse(exit.GetConditionStr())); + } catch (std::exception& ex) { + ss << exit.GetConditionStr() << std::endl; + ss << ex.what() << std::endl << std::endl; + } } } + + SPDLOG_INFO("Parse/Eval Failure Conditions:\n{}", ss.str()); } - - SPDLOG_INFO("Parse Failure Conditions:\n{}", ss.str()); #endif } diff --git a/soh/soh/Enhancements/randomizer/logic_expression.cpp b/soh/soh/Enhancements/randomizer/logic_expression.cpp index 58d512078..3830bcb41 100644 --- a/soh/soh/Enhancements/randomizer/logic_expression.cpp +++ b/soh/soh/Enhancements/randomizer/logic_expression.cpp @@ -429,6 +429,9 @@ std::string LogicExpression::Impl::GetExprErrorContext() const { #define REGISTER_FUNCTION(fn) \ { #fn, LogicExpression::Impl::RegisterFunction(#fn, fn) } +#define REGISTER_FUNCTION_WITH_DEFAULTS(fn, ...) \ + { #fn, LogicExpression::Impl::RegisterFunctionWithDefaults(#fn, fn, std::make_tuple(__VA_ARGS__)) } + #define REGISTER_LOGIC_FUNCTION(fn) \ { #fn, LogicExpression::Impl::RegisterLogicFunction(#fn, &Rando::Logic::fn) } @@ -482,9 +485,10 @@ std::unordered_map LogicExp void LogicExpression::Impl::PopulateFunctionAdapters() { functionAdapters = { REGISTER_FUNCTION(Here), - REGISTER_FUNCTION(MQSpiritSharedBrokenWallRoom), - REGISTER_FUNCTION(MQSpiritSharedStatueRoom), + REGISTER_FUNCTION_WITH_DEFAULTS(MQSpiritSharedBrokenWallRoom, RandomizerRegion{}, ConditionFn{}, false), + REGISTER_FUNCTION_WITH_DEFAULTS(MQSpiritSharedStatueRoom, RandomizerRegion{}, ConditionFn{}, false), REGISTER_FUNCTION(CanBuyAnother), + REGISTER_FUNCTION(CanBuyCheck), REGISTER_FUNCTION(GetOption), REGISTER_FUNCTION(GetTrickOption), REGISTER_FUNCTION(HasAccessTo), @@ -781,6 +785,11 @@ void LogicExpression::Impl::PopulateVariableAdapters() { REGISTER_LOGIC_VARIABLE(MQSpirit3SunsEnemies), REGISTER_LOGIC_VARIABLE(Spirit1FSilverRupees), REGISTER_LOGIC_VARIABLE(JabuRutoIn1F), + REGISTER_LOGIC_VARIABLE(THRescuedAllCarpenters), + REGISTER_LOGIC_VARIABLE(THCouldFree1TorchCarpenter), + REGISTER_LOGIC_VARIABLE(THCouldFreeDoubleCellCarpenter), + REGISTER_LOGIC_VARIABLE(TH_CouldFreeDeadEndCarpenter), + REGISTER_LOGIC_VARIABLE(THCouldRescueSlopeCarpenter), }; } diff --git a/soh/soh/Enhancements/randomizer/logic_expression.h b/soh/soh/Enhancements/randomizer/logic_expression.h index 88799703a..61672c0b4 100644 --- a/soh/soh/Enhancements/randomizer/logic_expression.h +++ b/soh/soh/Enhancements/randomizer/logic_expression.h @@ -220,6 +220,42 @@ class LogicExpression { }; } + // Helper to call member function with default parameters + // This function evaluates provided arguments and fills missing ones with defaults. + template + static ValueVariant + CallFunctionWithDefaultsImpl(const std::string& functionName, Function function, + const std::vector>& args, + const std::string& path, int depth, const EvaluationCallback& callback, + Tuple&& defaults, std::index_sequence) { + constexpr size_t expectedArgCount = sizeof...(Is); + + // Ensure the number of provided arguments does not exceed the expected count + if (args.size() > expectedArgCount) { + throw std::runtime_error("Function " + functionName + " expects up to " + + std::to_string(expectedArgCount) + " arguments, but got " + + std::to_string(args.size())); + } + + // Evaluate provided arguments and fill missing ones with defaults + return function((Is < args.size() ? EvaluateArg>>( + args[Is], path + "." + std::to_string(Is), depth, callback) + : std::get(defaults))...); + } + + // Wrapper for member functions with default parameters + template + static FunctionAdapter RegisterFunctionWithDefaults(const std::string& functionName, Function function, + std::tuple defaults) { + return [functionName, function, defaults](const std::vector>& args, + const std::string& path, int depth, + const EvaluationCallback& callback) -> ValueVariant { + constexpr size_t expectedArgCount = sizeof...(Args); + return CallFunctionWithDefaultsImpl(functionName, function, args, path, depth, callback, defaults, + std::make_index_sequence{}); + }; + } + // Helper to call pointer-to-member function on "logic" with extracted arguments. template static ValueVariant CallMemberFunctionImpl(const std::string& functionName, MemberFunction function, diff --git a/soh/soh/Enhancements/randomizer/randomizer_logic_tracker.cpp b/soh/soh/Enhancements/randomizer/randomizer_logic_tracker.cpp index 40ac19feb..1d7b979f3 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_logic_tracker.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer_logic_tracker.cpp @@ -111,8 +111,7 @@ static void PopulateConnectionExpression(LogicTrackerNode::Connection& connectio try { expression = LogicExpression::Parse(expressionStr); - } - catch (const std::exception& e) { + } catch (const std::exception& e) { connection.ExpressionTable.Root.ErrorMessage = std::string("Parse Error: ") + e.what(); connection.ExpressionTable.Root.Children.clear(); connection.ExpressionTable.CombineAll = true; diff --git a/soh/soh/Enhancements/randomizer/randomizer_types/randoOptions.h b/soh/soh/Enhancements/randomizer/randomizer_types/randoOptions.h index 411c654f1..6fad94ca3 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_types/randoOptions.h +++ b/soh/soh/Enhancements/randomizer/randomizer_types/randoOptions.h @@ -441,6 +441,8 @@ typedef enum { { "RO_ZF_OPEN", RO_ZF_OPEN }, { "RO_WATERFALL_CLOSED", RO_WATERFALL_CLOSED }, { "RO_WATERFALL_OPEN", RO_WATERFALL_OPEN }, +{ "RO_JABU_CLOSED", RO_JABU_CLOSED }, +{ "RO_JABU_OPEN", RO_JABU_OPEN }, { "RO_AGE_CHILD", RO_AGE_CHILD }, { "RO_AGE_ADULT", RO_AGE_ADULT }, { "RO_AGE_RANDOM", RO_AGE_RANDOM },