Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Maniac Patch - CallCommand Update #3319

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 60 additions & 8 deletions src/game_interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5246,23 +5246,75 @@ bool Game_Interpreter::CommandManiacCallCommand(lcf::rpg::EventCommand const& co
return true;
}

enum class ProcessingMode {
Constant = 0, // 0 and 1: Parameters read from variables
Variable = 1,
//VariableIndirect = 2, // Somehow not implemented by ManiacPatch
Inline = 3, // Parameters are directly provided by the command
Expression = 4 // Like 3, but the parameters are calculated from expressions
};

std::vector<int32_t> values;

// 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);

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));
switch (processing_mode) {
case ProcessingMode::Constant:
case ProcessingMode::Variable: {
int start_index = ValueOrVariable(static_cast<int>(processing_mode), com.parameters[2]);
int length = ValueOrVariableBitfield(com.parameters[0], 2, com.parameters[3]);

for (int i = 0; i < length; ++i) {
values.push_back(Main_Data::game_variables->Get(start_index + i));
}
break;
}
case ProcessingMode::Inline: {
int value_index = 5; // Start of the values
int mode_index = com.parameters[2]; // Mode of the values
int length = com.parameters[3];

for (int i = 0; i < length; ++i) {
// The mode is the typical 4 bit packing
// Always 4 modes (16 bit) are packing into one parameter
// Then the mode_index increments
if (i != 0 && i % 4 == 0) {
++mode_index;
}

cmd.parameters = lcf::DBArray<int32_t>(output_args.begin(), output_args.end());
values.push_back(ValueOrVariableBitfield(com, mode_index, i % 4, value_index + i));
}
break;
}
case ProcessingMode::Expression: {
values = ManiacPatch::ParseExpressions(MakeSpan(com.parameters).subspan(5), *this);
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>(values.begin(), values.end());

// Debug 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 : 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.
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
Loading