Skip to content

Commit

Permalink
Maniac Patch - CallCommand Update
Browse files Browse the repository at this point in the history
Changes to cover the new variations of Maniac's "call command"
  • Loading branch information
jetrotal committed Jan 10, 2025
1 parent 65478ef commit 30a7d58
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 13 deletions.
100 changes: 87 additions & 13 deletions src/game_interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5052,36 +5052,110 @@ bool Game_Interpreter::CommandManiacControlStrings(lcf::rpg::EventCommand const&
return true;
}

bool Game_Interpreter::CommandManiacCallCommand(lcf::rpg::EventCommand const& com) {
bool Game_Interpreter::CommandManiacCallCommand(const lcf::rpg::EventCommand& com) {
if (!Player::IsPatchManiac()) {
return true;
}

enum class ProcessingMode {
VariableSequence = 0,
VariableSequenceAlt = 1,
Dynamic = 3,
Expression = 4
};

struct CmdArrayData {
int start_index = 0;
int length = 0;
std::vector<int32_t> values;
int interpretation_bits = 0;
bool has_interpretation_bits = false;
};

constexpr int INTERPRETATION_MODE_SHIFT = 2;

// Create command with basic parameters
lcf::rpg::EventCommand cmd;
cmd.code = ValueOrVariableBitfield(com.parameters[0], 0, com.parameters[1]);

cmd.string = lcf::DBString(CommandStringOrVariableBitfield(com, 0, 3, 4));

int arr_begin = ValueOrVariableBitfield(com.parameters[0], 1, com.parameters[2]);
int arr_length = ValueOrVariableBitfield(com.parameters[0], 2, com.parameters[3]);
// Determine processing mode
auto processing_mode = static_cast<ProcessingMode>((com.parameters[0] >> 4) & 0b1111);
CmdArrayData arr_data;

// Helper to populate values based on start_index and length
auto populate_values = [&](auto get_value) {
arr_data.values.reserve(arr_data.length);
for (int i = 0; i < arr_data.length; ++i) {
arr_data.values.push_back(get_value(i));
}
};

switch (processing_mode) {
case ProcessingMode::VariableSequence:
case ProcessingMode::VariableSequenceAlt: {
arr_data.start_index = ValueOrVariable(static_cast<int>(processing_mode), com.parameters[2]);
arr_data.length = ValueOrVariableBitfield(com.parameters[0], 2, com.parameters[3]);

if (arr_data.length > 0) {
populate_values([&](int i) {
return Main_Data::game_variables->Get(arr_data.start_index + i);
});
}
break;
}
case ProcessingMode::Dynamic: {
arr_data.start_index = com.parameters[2];
arr_data.length = com.parameters[3];
populate_values([&](int i) { return com.parameters[5 + i]; });

int interpretation_index = 5 + arr_data.length;
if (interpretation_index < static_cast<int>(com.parameters.size())) {
arr_data.interpretation_bits = com.parameters[interpretation_index];
arr_data.has_interpretation_bits = true;

std::vector<int32_t> output_args;
if (arr_length > 0) {
output_args.reserve(arr_length);
for (int i = 0; i < arr_length; ++i) {
output_args.push_back(Main_Data::game_variables->Get(arr_begin + i));
for (int i = 0; i < arr_data.length; ++i) {
int mode = (arr_data.interpretation_bits >> (i * INTERPRETATION_MODE_SHIFT)) & 0x3;
arr_data.values[i] = ValueOrVariable<true, true>(mode, arr_data.values[i]);
}
}
break;
}
case ProcessingMode::Expression: {
auto values = ManiacPatch::ParseExpressions(
MakeSpan(com.parameters).subspan(5), *this);
arr_data.values.insert(arr_data.values.end(), values.begin(), values.end());
break;
}
default:
Output::Warning("Call Command - Unsupported Processing Mode: {}",
static_cast<int>(processing_mode));
return true;
}

// Finalize command parameters
cmd.parameters = lcf::DBArray<int32_t>(arr_data.values.begin(), arr_data.values.end());

cmd.parameters = lcf::DBArray<int32_t>(output_args.begin(), output_args.end());
// Debug output
auto debug_callcmd_output = [&]() {
Output::Warning("Processing mode: {}", static_cast<int>(processing_mode));
Output::Warning("Command code: {}", cmd.code);
Output::Warning("Command string: {}", cmd.string);
std::string params_str;
for (const auto& param : arr_data.values) {
params_str += " " + std::to_string(param);
}
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.
Push({ cmd }, GetCurrentEventId(), false); //FIXME: add some new flag, so the interpreter debug view (window_interpreter) can differentiate this frame from normal ones
debug_callcmd_output();

Push({ cmd }, GetCurrentEventId(), false);
return true;
}


bool Game_Interpreter::CommandEasyRpgSetInterpreterFlag(lcf::rpg::EventCommand const& com) {
if (!Player::HasEasyRpgExtensions()) {
return true;
Expand Down
30 changes: 30 additions & 0 deletions src/maniac_patch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,7 @@ int Process(std::vector<int32_t>::iterator& it, std::vector<int32_t>::iterator e
Output::Warning("Maniac: Expression actor args {} != 2", imm2);
return 0;
}
imm3 = Process(it, end, ip);
return ControlVariables::Actor(Process(it, end, ip), imm3);
case Fn::Party:
if (imm2 != 2) {
Expand Down Expand Up @@ -570,6 +571,35 @@ int32_t ManiacPatch::ParseExpression(Span<const int32_t> op_codes, const Game_Ba
return Process(beg, ops.end(), interpreter);
}

std::vector<int32_t> ManiacPatch::ParseExpressions(Span<const int32_t> op_codes, const Game_BaseInterpreterContext& interpreter) {
std::vector<int32_t> ops;
for (auto& o : op_codes) {
auto uo = static_cast<uint32_t>(o);
ops.push_back(static_cast<int32_t>(uo & 0x000000FF));
ops.push_back(static_cast<int32_t>((uo & 0x0000FF00) >> 8));
ops.push_back(static_cast<int32_t>((uo & 0x00FF0000) >> 16));
ops.push_back(static_cast<int32_t>((uo & 0xFF000000) >> 24));
}

if (ops.empty()) {
return {};
}

auto it = ops.begin();

std::vector<int32_t> results;

while (true) {
results.push_back(Process(it, ops.end(), interpreter));

if (it == ops.end() || static_cast<Op>(*it) == Op::Null) {
break;
}
}

return results;
}

std::array<bool, 50> ManiacPatch::GetKeyRange() {
std::array<Input::Keys::InputKey, 50> keys = {
Input::Keys::A,
Expand Down
3 changes: 3 additions & 0 deletions src/maniac_patch.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#include <array>
#include <cstdint>
#include <vector>
#include "span.h"

#include "game_strings.h"
Expand All @@ -29,6 +30,8 @@ class Game_BaseInterpreterContext;

namespace ManiacPatch {
int32_t ParseExpression(Span<const int32_t> op_codes, const Game_BaseInterpreterContext& interpreter);
std::vector<int32_t> ParseExpressions(Span<const int32_t> op_codes, const Game_BaseInterpreterContext& interpreter);


std::array<bool, 50> GetKeyRange();

Expand Down

0 comments on commit 30a7d58

Please sign in to comment.