Skip to content

Commit

Permalink
Merge pull request #3233 from florianessl/InterpreterRefactor
Browse files Browse the repository at this point in the history
Interpreter Refactor
  • Loading branch information
Ghabry authored Sep 2, 2024
2 parents f83c0fa + 99838d3 commit 5d20c6d
Show file tree
Hide file tree
Showing 15 changed files with 570 additions and 305 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ add_library(${PROJECT_NAME} OBJECT
src/game_interpreter.h
src/game_interpreter_map.cpp
src/game_interpreter_map.h
src/game_interpreter_shared.cpp
src/game_interpreter_shared.h
src/game_map.cpp
src/game_map.h
src/game_message.cpp
Expand Down
2 changes: 2 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ libeasyrpg_player_a_SOURCES = \
src/game_interpreter_control_variables.h \
src/game_interpreter_map.cpp \
src/game_interpreter_map.h \
src/game_interpreter_shared.cpp \
src/game_interpreter_shared.h \
src/game_map.cpp \
src/game_map.h \
src/game_message.cpp \
Expand Down
30 changes: 3 additions & 27 deletions src/game_event.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,33 +256,9 @@ bool Game_Event::AreConditionsMet(const lcf::rpg::EventPage& page) {
return false;
}
} else {
if (page.condition.flags.variable) {
switch (page.condition.compare_operator) {
case 0: // ==
if (!(Main_Data::game_variables->Get(page.condition.variable_id) == page.condition.variable_value))
return false;
break;
case 1: // >=
if (!(Main_Data::game_variables->Get(page.condition.variable_id) >= page.condition.variable_value))
return false;
break;
case 2: // <=
if (!(Main_Data::game_variables->Get(page.condition.variable_id) <= page.condition.variable_value))
return false;
break;
case 3: // >
if (!(Main_Data::game_variables->Get(page.condition.variable_id) > page.condition.variable_value))
return false;
break;
case 4: // <
if (!(Main_Data::game_variables->Get(page.condition.variable_id) < page.condition.variable_value))
return false;
break;
case 5: // !=
if (!(Main_Data::game_variables->Get(page.condition.variable_id) != page.condition.variable_value))
return false;
break;
}
if (page.condition.flags.variable && page.condition.compare_operator >= 0 && page.condition.compare_operator <= 5) {
if (!Game_Interpreter_Shared::CheckOperator(Main_Data::game_variables->Get(page.condition.variable_id), page.condition.variable_value, page.condition.compare_operator))
return false;
}
}

Expand Down
240 changes: 31 additions & 209 deletions src/game_interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@
#include "algo.h"
#include "rand.h"

using namespace Game_Interpreter_Shared;

enum BranchSubcommand {
eOptionBranchElse = 1
};
Expand Down Expand Up @@ -571,56 +573,6 @@ void Game_Interpreter::SkipToNextConditional(std::initializer_list<Cmd> codes, i
}
}

int Game_Interpreter::DecodeInt(lcf::DBArray<int32_t>::const_iterator& it) {
int value = 0;

for (;;) {
int x = *it++;
value <<= 7;
value |= x & 0x7F;
if (!(x & 0x80))
break;
}

return value;
}

const std::string Game_Interpreter::DecodeString(lcf::DBArray<int32_t>::const_iterator& it) {
std::ostringstream out;
int len = DecodeInt(it);

for (int i = 0; i < len; i++)
out << (char)*it++;

std::string result = lcf::ReaderUtil::Recode(out.str(), Player::encoding);

return result;
}

lcf::rpg::MoveCommand Game_Interpreter::DecodeMove(lcf::DBArray<int32_t>::const_iterator& it) {
lcf::rpg::MoveCommand cmd;
cmd.command_id = *it++;

switch (cmd.command_id) {
case 32: // Switch ON
case 33: // Switch OFF
cmd.parameter_a = DecodeInt(it);
break;
case 34: // Change Graphic
cmd.parameter_string = lcf::DBString(DecodeString(it));
cmd.parameter_a = DecodeInt(it);
break;
case 35: // Play Sound Effect
cmd.parameter_string = lcf::DBString(DecodeString(it));
cmd.parameter_a = DecodeInt(it);
cmd.parameter_b = DecodeInt(it);
cmd.parameter_c = DecodeInt(it);
break;
}

return cmd;
}

// Execute Command.
bool Game_Interpreter::ExecuteCommand() {
auto& frame = GetFrame();
Expand Down Expand Up @@ -1062,12 +1014,20 @@ bool Game_Interpreter::CommandInputNumber(lcf::rpg::EventCommand const& com) { /
}

bool Game_Interpreter::CommandControlSwitches(lcf::rpg::EventCommand const& com) { // code 10210
if (com.parameters[0] >= 0 && com.parameters[0] <= 2) {
// Param0: 0: Single, 1: Range, 2: Indirect
// For Range set end to param 2, otherwise to start, this way the loop runs exactly once
{
int start, end;
bool target_eval_result = DecodeTargetEvaluationMode<
/* validate_patches */ true,
/* support_range_indirect */ false,
/* support_expressions */ false,
/* support_bitmask */ false,
/* support_scopes */ false
>(com, start, end);
if (!target_eval_result) {
Output::Warning("ControlSwitches: Unsupported target evaluation mode {}", com.parameters[0]);
return true;
}

int start = com.parameters[0] == 2 ? Main_Data::game_variables->Get(com.parameters[1]) : com.parameters[1];
int end = com.parameters[0] == 1 ? com.parameters[2] : start;
int val = com.parameters[3];

if (start == end) {
Expand All @@ -1086,7 +1046,6 @@ bool Game_Interpreter::CommandControlSwitches(lcf::rpg::EventCommand const& com)
Game_Map::SetNeedRefresh(true);
}
}

return true;
}

Expand Down Expand Up @@ -1270,41 +1229,20 @@ bool Game_Interpreter::CommandControlVariables(lcf::rpg::EventCommand const& com
return true;
}

int target = com.parameters[0];
if (target >= 0 && target <= 4) {
// For Range set end to param 2, otherwise to start, this way the loop runs exactly once

int start, end;
if (target == 0) {
// Single
start = com.parameters[1];
end = start;
} else if (target == 1) {
// Range
start = com.parameters[1];
end = com.parameters[2];
} else if (target == 2) {
// Indirect
start = Main_Data::game_variables->Get(com.parameters[1]);
end = start;
} else if (target == 3 && Player::IsPatchManiac()) {
// Range Indirect (Maniac)
start = Main_Data::game_variables->Get(com.parameters[1]);
end = Main_Data::game_variables->Get(com.parameters[2]);
} else if (target == 4 && Player::IsPatchManiac()) {
// Expression (Maniac)
int idx = com.parameters[1];
start = ManiacPatch::ParseExpression(MakeSpan(com.parameters).subspan(idx + 1, com.parameters[idx]), *this);
end = start;
} else {
return true;
}

if (Player::IsPatchManiac() && end < start) {
// Vanilla does not support end..start, Maniac does
std::swap(start, end);
}
int start, end;
bool target_eval_result = DecodeTargetEvaluationMode<
/* validate_patches */ true,
/* support_range_indirect */ true,
/* support_expressions */ true,
/* support_bitmask */ false,
/* support_scopes */ false
>(com, start, end);
if (!target_eval_result) {
Output::Warning("ControlVariables: Unsupported target evaluation mode {}", com.parameters[0]);
return true;
}

{
int operation = com.parameters[3];
if (EP_UNLIKELY(operation >= 6 && !Player::IsPatchManiac())) {
Output::Warning("ControlVariables: Unsupported operation {}", operation);
Expand Down Expand Up @@ -1749,77 +1687,6 @@ bool Game_Interpreter::CommandChangeLevel(lcf::rpg::EventCommand const& com) { /
return true;
}

int Game_Interpreter::ValueOrVariable(int mode, int val) {
if (mode == 0) {
return val;
} else if (mode == 1) {
return Main_Data::game_variables->Get(val);
} else if (Player::IsPatchManiac()) {
// Maniac Patch does not implement all modes for all commands
// For simplicity it is enabled for all here
if (mode == 2) {
// Variable indirect
return Main_Data::game_variables->GetIndirect(val);
} else if (mode == 3) {
// Switch (F = 0, T = 1)
return Main_Data::game_switches->GetInt(val);
} else if (mode == 4) {
// Switch through Variable (F = 0, T = 1)
return Main_Data::game_switches->GetInt(Main_Data::game_variables->Get(val));
}
}
return -1;
}

int Game_Interpreter::ValueOrVariableBitfield(int mode, int shift, int val) {
return ValueOrVariable((mode & (0xF << shift * 4)) >> shift * 4, val);
}

int Game_Interpreter::ValueOrVariableBitfield(lcf::rpg::EventCommand const& com, int mode_idx, int shift, int val_idx) {
assert(static_cast<int>(com.parameters.size()) > val_idx);

if (!Player::IsPatchManiac()) {
return com.parameters[val_idx];
}

assert(mode_idx != val_idx);

if (static_cast<int>(com.parameters.size()) > std::max(mode_idx, val_idx)) {
return ValueOrVariableBitfield(com.parameters[mode_idx], shift, com.parameters[val_idx]);
}

return com.parameters[val_idx];
}

StringView Game_Interpreter::CommandStringOrVariable(lcf::rpg::EventCommand const& com, int mode_idx, int val_idx) {
if (!Player::IsPatchManiac()) {
return com.string;
}

assert(mode_idx != val_idx);

if (static_cast<int>(com.parameters.size()) > std::max(mode_idx, val_idx)) {
return Main_Data::game_strings->GetWithMode(ToString(com.string), com.parameters[mode_idx], com.parameters[val_idx], *Main_Data::game_variables);
}

return com.string;
}

StringView Game_Interpreter::CommandStringOrVariableBitfield(lcf::rpg::EventCommand const& com, int mode_idx, int shift, int val_idx) {
if (!Player::IsPatchManiac()) {
return com.string;
}

assert(mode_idx != val_idx);

if (static_cast<int>(com.parameters.size()) >= std::max(mode_idx, val_idx) + 1) {
int mode = com.parameters[mode_idx];
return Main_Data::game_strings->GetWithMode(ToString(com.string), (mode & (0xF << shift * 4)) >> shift * 4, com.parameters[val_idx], *Main_Data::game_variables);
}

return com.string;
}

bool Game_Interpreter::CommandChangeParameters(lcf::rpg::EventCommand const& com) { // Code 10430
int value = OperateValue(
com.parameters[2],
Expand Down Expand Up @@ -4819,18 +4686,9 @@ bool Game_Interpreter::CommandManiacControlStrings(lcf::rpg::EventCommand const&
// Flags, such as: extract, hex... There is also an edge case where the last argument of exRep is here
//
//*parameters 4..n - arguments
int string_mode = com.parameters[0] & 15;
int string_id_0 = com.parameters[1];
int string_id_1 = com.parameters[2]; //for ranges

int is_range = string_mode & 1;

if (string_mode >= 2) {
string_id_0 = Main_Data::game_variables->Get(string_id_0);
}
if (string_mode == 3) {
string_id_1 = Main_Data::game_variables->Get(string_id_1);
}
bool is_range = com.parameters[0] & 1;
int string_id_0, string_id_1;
DecodeTargetEvaluationMode<false, true, false, true, false>(com, string_id_0, string_id_1);

int op = (com.parameters[3] >> 0) & 255;
int fn = (com.parameters[3] >> 8) & 255;
Expand Down Expand Up @@ -5163,42 +5021,6 @@ bool Game_Interpreter::IsWaitingForWaitCommand() const {
return (_state.wait_time > 0) || _state.wait_key_enter;
}

bool Game_Interpreter::CheckOperator(int val, int val2, int op) const {
switch (op) {
case 0:
return val == val2;
case 1:
return val >= val2;
case 2:
return val <= val2;
case 3:
return val > val2;
case 4:
return val < val2;
case 5:
return val != val2;
default:
return false;
}
}

bool Game_Interpreter::ManiacCheckContinueLoop(int val, int val2, int type, int op) const {
switch (type) {
case 0: // Infinite loop
return true;
case 1: // X times
case 2: // Count up
return val <= val2;
case 3: // Count down
return val >= val2;
case 4: // While
case 5: // Do While
return CheckOperator(val, val2, op);
default:
return false;
}
}

int Game_Interpreter::ManiacBitmask(int value, int mask) const {
if (Player::IsPatchManiac()) {
return value & mask;
Expand Down
Loading

0 comments on commit 5d20c6d

Please sign in to comment.