From f03f5cbeb7eeab3f3bf8858503a39282a832dc62 Mon Sep 17 00:00:00 2001 From: Mauro Junior <45118493+jetrotal@users.noreply.github.com> Date: Thu, 9 Jan 2025 14:05:05 -0300 Subject: [PATCH] Maniac Patch/CallCommand Update - Support Expressions --- src/game_interpreter.cpp | 28 ++++------------------------ src/maniac_patch.cpp | 29 +++++++++++++++++++++++++++++ src/maniac_patch.h | 3 +++ 3 files changed, 36 insertions(+), 24 deletions(-) diff --git a/src/game_interpreter.cpp b/src/game_interpreter.cpp index f949b71204..3a4ae98ff0 100644 --- a/src/game_interpreter.cpp +++ b/src/game_interpreter.cpp @@ -5123,31 +5123,11 @@ bool Game_Interpreter::CommandManiacCallCommand(lcf::rpg::EventCommand const& co case 4: { // Expression mode - interprets its own parameters as Maniac Expressions - //TODO - LEARN HOW THIS ACTUALLY WORKS - break; - - auto expression_params = MakeSpan(com.parameters).subspan(5); - - // Based on the encoding pattern, each expression seems to be encoded separately - // and the parameters are already split into the format ParseExpression expects - output_args.reserve(5); // Reserve space for typical expression array elements + auto values = ManiacPatch::ParseExpressions(MakeSpan(com.parameters).subspan(5), *this); - // Find end of expressions (when encountering a value that breaks the pattern) - size_t param_count = expression_params.size(); - size_t current_param = 0; + output_args.reserve(values.size()); + output_args.insert(output_args.end(), values.begin(), values.end()); - while (current_param < param_count) { - // Try to get all bytes until we hit the end or an invalid expression marker - auto remaining_params = MakeSpan(expression_params).subspan(current_param); - - // ParseExpression will handle breaking down each parameter into bytes - int32_t result = ManiacPatch::ParseExpression(remaining_params, *this); - output_args.push_back(result); - - // Move to next expression based on the pattern of bytes used - // Need to figure out exact number of parameters used by ParseExpression - current_param += 1; // This needs to be adjusted based on how many parameters each expression consumes - } break; } @@ -5168,7 +5148,7 @@ bool Game_Interpreter::CommandManiacCallCommand(lcf::rpg::EventCommand const& co for (int i = 0; i < cmd.parameters.size(); i++) params_str += " " + std::to_string(output_args[i]); Output::Warning("Command parameters: {}", params_str); Output::Info("--------------------\n"); - */ + //*/ // Our implementation pushes a new frame containing the command instead of invoking it directly. // This is incompatible to Maniacs but has a better compatibility with our code. diff --git a/src/maniac_patch.cpp b/src/maniac_patch.cpp index 0ed805adf9..2548776e0d 100644 --- a/src/maniac_patch.cpp +++ b/src/maniac_patch.cpp @@ -570,6 +570,35 @@ int32_t ManiacPatch::ParseExpression(Span op_codes, const Game_Ba return Process(beg, ops.end(), interpreter); } +std::vector ManiacPatch::ParseExpressions(Span op_codes, const Game_BaseInterpreterContext& interpreter) { + std::vector ops; + for (auto& o : op_codes) { + auto uo = static_cast(o); + ops.push_back(static_cast(uo & 0x000000FF)); + ops.push_back(static_cast((uo & 0x0000FF00) >> 8)); + ops.push_back(static_cast((uo & 0x00FF0000) >> 16)); + ops.push_back(static_cast((uo & 0xFF000000) >> 24)); + } + + if (ops.empty()) { + return {}; + } + + auto it = ops.begin(); + + std::vector results; + + while (true) { + results.push_back(Process(it, ops.end(), interpreter)); + + if (it != ops.end() && static_cast(*it) == Op::Null) { + break; + } + } + + return results; +} + std::array ManiacPatch::GetKeyRange() { std::array keys = { Input::Keys::A, diff --git a/src/maniac_patch.h b/src/maniac_patch.h index 789834fcf9..2b5c2c4edd 100644 --- a/src/maniac_patch.h +++ b/src/maniac_patch.h @@ -21,6 +21,7 @@ #include #include +#include #include "span.h" #include "game_strings.h" @@ -29,6 +30,8 @@ class Game_BaseInterpreterContext; namespace ManiacPatch { int32_t ParseExpression(Span op_codes, const Game_BaseInterpreterContext& interpreter); + std::vector ParseExpressions(Span op_codes, const Game_BaseInterpreterContext& interpreter); + std::array GetKeyRange();