Skip to content
Merged
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
8 changes: 7 additions & 1 deletion src/feature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,19 @@
// Headers
#include "feature.h"
#include "player.h"
#include "game_interpreter_shared.h"
#include <lcf/data.h>

bool Feature::HasRpg2kBattleSystem() {
if (Player::IsRPG2k()) {
return true;
}

#ifdef ENABLE_DYNAMIC_INTERPRETER_CONFIG
using Flags = lcf::rpg::SaveEventExecState::EasyRpgStateRuntime_Flags;
if (auto f = Player::GetRuntimeFlag(&Flags::use_rpg2k_battle_system_on, &Flags::use_rpg2k_battle_system_off)) {
return *f;
}
#endif
return lcf::Data::system.easyrpg_use_rpg2k_battle_system;
}

Expand Down
152 changes: 129 additions & 23 deletions src/game_interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ bool Game_Interpreter::ReachedLoopLimit() const {
int Game_Interpreter::GetThisEventId() const {
auto event_id = GetCurrentEventId();

if (event_id == 0 && (Player::IsRPG2k3E() || Player::game_config.patch_common_this_event.Get())) {
if (event_id == 0 && (Player::IsRPG2k3E() || Player::IsPatchCommonThisEvent())) {
// RM2k3E allows "ThisEvent" commands to run from called
// common events. It operates on the last map event in
// the call stack.
Expand Down Expand Up @@ -382,6 +382,13 @@ void Game_Interpreter::Update(bool reset_loop_count) {
return;
}

#ifdef ENABLE_DYNAMIC_INTERPRETER_CONFIG
Player::active_interpreter_flags = &_state.easyrpg_runtime_flags;
auto flags_guard = lcf::makeScopeGuard([]() {
Player::active_interpreter_flags = &Player::interpreter_default_flags;
});
#endif

for (; loop_count < loop_limit; ++loop_count) {
// If something is calling a menu, we're allowed to execute only 1 command per interpreter. So we pass through if loop_count == 0, and stop at 1 or greater.
// RPG_RT compatible behavior.
Expand Down Expand Up @@ -829,6 +836,14 @@ bool Game_Interpreter::OnFinishStackFrame() {
_state.stack.pop_back();
}

if (is_base_frame) {
#ifdef ENABLE_DYNAMIC_INTERPRETER_CONFIG
// Individual runtime flags that may still be set will be cleared by
// CommandEasyRpgSetInterpreterFlag if neccessary
_state.easyrpg_runtime_flags.conf_override_active = false;
#endif
}

return !is_base_frame;
}

Expand Down Expand Up @@ -2006,17 +2021,17 @@ bool Game_Interpreter::CommandEndEventProcessing(lcf::rpg::EventCommand const& /
return true;
}

bool Game_Interpreter::CommandComment(const lcf::rpg::EventCommand &com) {
std::optional<bool> Game_Interpreter::HandleDynRpgScript(const lcf::rpg::EventCommand& com) {
if (Player::IsPatchDynRpg() || Player::HasEasyRpgExtensions()) {
if (com.string.empty() || com.string[0] != '@') {
// Not a DynRPG command
return true;
return std::nullopt;
}

if (!Player::IsPatchDynRpg() && Player::HasEasyRpgExtensions()) {
// Only accept commands starting with @easyrpg_
if (!StartsWith(com.string, "@easyrpg_")) {
return true;
return std::nullopt;
}
}

Expand All @@ -2025,6 +2040,7 @@ bool Game_Interpreter::CommandComment(const lcf::rpg::EventCommand &com) {
auto& index = frame.current_command;

std::string command = ToString(com.string);

// Concat everything that is not another command or a new comment block
for (size_t i = index + 1; i < list.size(); ++i) {
const auto& cmd = list[i];
Expand All @@ -2039,16 +2055,29 @@ bool Game_Interpreter::CommandComment(const lcf::rpg::EventCommand &com) {
return Main_Data::game_dynrpg->Invoke(command, this);
}

return {};
}

std::optional<bool> Game_Interpreter::HandleDestinyScript(const lcf::rpg::EventCommand& com) {
// DestinyScript
if (Player::IsPatchDestiny()) {
if (com.string.empty() || com.string[0] != '$') {
// Not a DestinyScript
return true;
return {};
}

return Main_Data::game_destiny->Main(GetFrame());
}
return {};
}

bool Game_Interpreter::CommandComment(const lcf::rpg::EventCommand &com) {
if (auto handled = HandleDynRpgScript(com); handled.has_value()) {
return handled.value();
}
if (auto handled = HandleDestinyScript(com); handled.has_value()) {
return handled.value();
}

return true;
}
Expand Down Expand Up @@ -2700,7 +2729,7 @@ namespace PicPointerPatch {

bool Game_Interpreter::CommandShowPicture(lcf::rpg::EventCommand const& com) { // code 11110
// Older versions of RPG_RT block pictures when message active.
if (!Player::IsEnglish() && !Player::game_config.patch_unlock_pics.Get() && Game_Message::IsMessageActive()) {
if (!Player::IsEnglish() && !Player::IsPatchUnlockPics() && Game_Message::IsMessageActive()) {
return false;
}

Expand Down Expand Up @@ -2850,7 +2879,7 @@ bool Game_Interpreter::CommandShowPicture(lcf::rpg::EventCommand const& com) { /

bool Game_Interpreter::CommandMovePicture(lcf::rpg::EventCommand const& com) { // code 11120
// Older versions of RPG_RT block pictures when message active.
if (!Player::IsEnglish() && !Player::game_config.patch_unlock_pics.Get() && Game_Message::IsMessageActive()) {
if (!Player::IsEnglish() && !Player::IsPatchUnlockPics() && Game_Message::IsMessageActive()) {
return false;
}

Expand Down Expand Up @@ -3005,7 +3034,7 @@ bool Game_Interpreter::CommandMovePicture(lcf::rpg::EventCommand const& com) { /

bool Game_Interpreter::CommandErasePicture(lcf::rpg::EventCommand const& com) { // code 11130
// Older versions of RPG_RT block pictures when message active.
if (!Player::IsEnglish() && !Player::game_config.patch_unlock_pics.Get() && Game_Message::IsMessageActive()) {
if (!Player::IsEnglish() && !Player::IsPatchUnlockPics() && Game_Message::IsMessageActive()) {
return false;
}

Expand Down Expand Up @@ -5363,25 +5392,102 @@ bool Game_Interpreter::CommandEasyRpgSetInterpreterFlag(lcf::rpg::EventCommand c
return true;
}

// FIXME: Store them as part of the interpreter state
#ifndef ENABLE_DYNAMIC_INTERPRETER_CONFIG
Output::Warning("CommandEasyRpgSetInterpreterFlag: Not supported on this platform");
return true;
#else
constexpr std::array<std::pair<const char*, int>, 9> config_names = {{
{ "destiny", 1 },
{ "dynrpg", 2 },
{ "maniac", 3 },
{ "common-this", 4 },
{ "pic-unlock", 5 },
{ "key-patch", 6 },
{ "rpg2k3-cmds", 7 },
{ "rpg2k3-commands", 7 },
{ "rpg2k-battle", 8 }
}};

std::string flag_name = Utils::LowerCase(ToString(com.string));
int flag_value = ValueOrVariable(com.parameters[0], com.parameters[1]);
int flag_id = 0;

if (flag_name.empty() && com.parameters.size() > 2) {
flag_id = com.parameters[2];
} else {
auto it = std::find_if(config_names.begin(), config_names.end(), [&flag_name](auto& p) { return p.first == flag_name; });
if (it != config_names.end()) {
flag_id = it->second;
}
}

if (flag_name == "dynrpg")
Player::game_config.patch_dynrpg.Set(flag_value);
if (flag_name == "maniac")
Player::game_config.patch_maniac.Set(flag_value);
if (flag_name == "common-this")
Player::game_config.patch_common_this_event.Set(flag_value);
if (flag_name == "pic-unlock")
Player::game_config.patch_unlock_pics.Set(flag_value);
if (flag_name == "key-patch")
Player::game_config.patch_key_patch.Set(flag_value);
if (flag_name == "rpg2k3-cmds" || flag_name == "rpg2k3-commands")
Player::game_config.patch_rpg2k3_commands.Set(flag_value);
if (flag_name == "rpg2k-battle")
lcf::Data::system.easyrpg_use_rpg2k_battle_system = flag_value;
// Clear any inactive flags that might be left over from a previous InterpreterFlag command
if (!_state.easyrpg_runtime_flags.conf_override_active) {
_state.easyrpg_runtime_flags.flags.fill(false);
}

switch (flag_id) {
case 1:
if (flag_value) {
_state.easyrpg_runtime_flags.patch_destiny_on = true;
} else {
_state.easyrpg_runtime_flags.patch_destiny_off = true;
}
break;
case 2:
if (flag_value) {
_state.easyrpg_runtime_flags.patch_dynrpg_on = true;
} else {
_state.easyrpg_runtime_flags.patch_dynrpg_off = true;
}
break;
case 3:
if (flag_value) {
_state.easyrpg_runtime_flags.patch_maniac_on = true;
} else {
_state.easyrpg_runtime_flags.patch_maniac_off = true;
}
break;
case 4:
if (flag_value) {
_state.easyrpg_runtime_flags.patch_common_this_event_on = true;
} else {
_state.easyrpg_runtime_flags.patch_common_this_event_off = true;
}
break;
case 5:
if (flag_value) {
_state.easyrpg_runtime_flags.patch_unlock_pics_on = true;
} else {
_state.easyrpg_runtime_flags.patch_unlock_pics_off = true;
}
break;
case 6:
if (flag_value) {
_state.easyrpg_runtime_flags.patch_keypatch_on = true;
} else {
_state.easyrpg_runtime_flags.patch_keypatch_off = true;
}
break;
case 7:
if (flag_value) {
_state.easyrpg_runtime_flags.patch_rpg2k3_cmds_on = true;
} else {
_state.easyrpg_runtime_flags.patch_rpg2k3_cmds_off = true;
}
break;
case 8:
if (flag_value) {
_state.easyrpg_runtime_flags.use_rpg2k_battle_system_on = true;
} else {
_state.easyrpg_runtime_flags.use_rpg2k_battle_system_off = true;
}
break;
default:
return true;
}
_state.easyrpg_runtime_flags.conf_override_active = true;
#endif

return true;
}
Expand Down
5 changes: 4 additions & 1 deletion src/game_interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class Game_Interpreter : public Game_BaseInterpreterContext
* Returns the interpreters current state information.
* For saving state into a save file, use GetSaveState instead.
*/
const lcf::rpg::SaveEventExecState& GetState() const;
const lcf::rpg::SaveEventExecState& GetState() const override;

/**
* Returns a SaveEventExecState needed for the savefile.
Expand Down Expand Up @@ -310,6 +310,9 @@ class Game_Interpreter : public Game_BaseInterpreterContext
void ForegroundTextPush(PendingMessage pm);
void EndEventProcessing();

std::optional<bool> HandleDynRpgScript(const lcf::rpg::EventCommand& com);
std::optional<bool> HandleDestinyScript(const lcf::rpg::EventCommand& com);

FileRequestBinding request_id;
enum class Keys {
eDown,
Expand Down
18 changes: 18 additions & 0 deletions src/game_interpreter_shared.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,24 @@ lcf::rpg::MoveCommand Game_Interpreter_Shared::DecodeMove(lcf::DBArray<int32_t>:
return cmd;
}

#ifdef ENABLE_DYNAMIC_INTERPRETER_CONFIG

std::optional<bool> Game_Interpreter_Shared::GetRuntimeFlag(lcf::rpg::SaveEventExecState const& state, StateRuntimeFlagRef const field_on, StateRuntimeFlagRef const field_off) {
return GetRuntimeFlag(state.easyrpg_runtime_flags, field_on, field_off);
}

std::optional<bool> Game_Interpreter_Shared::GetRuntimeFlag(lcf::rpg::SaveEventExecState::EasyRpgStateRuntime_Flags const& state_runtime_flags, StateRuntimeFlagRef const field_on, StateRuntimeFlagRef const field_off) {
if (state_runtime_flags.conf_override_active) {
if (state_runtime_flags.*field_on)
return true;
if (state_runtime_flags.*field_off)
return false;
}
return std::nullopt;
}

#endif

//explicit declarations for target evaluation logic shared between ControlSwitches/ControlVariables/ControlStrings
template bool Game_Interpreter_Shared::DecodeTargetEvaluationMode<true, false, false, false, false>(lcf::rpg::EventCommand const&, int&, int&, Game_BaseInterpreterContext const&);
template bool Game_Interpreter_Shared::DecodeTargetEvaluationMode<true, true, true, false, false>(lcf::rpg::EventCommand const&, int&, int&, Game_BaseInterpreterContext const&);
Expand Down
20 changes: 20 additions & 0 deletions src/game_interpreter_shared.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,13 @@

#include <lcf/rpg/eventcommand.h>
#include <lcf/rpg/movecommand.h>
#include <lcf/rpg/saveeventexecstate.h>
#include <lcf/rpg/saveeventexecframe.h>
#include <string_view.h>
#include "compiler.h"
#include <optional>

#define ENABLE_DYNAMIC_INTERPRETER_CONFIG

class Game_Character;
class Game_BaseInterpreterContext;
Expand Down Expand Up @@ -103,6 +107,14 @@ namespace Game_Interpreter_Shared {
lcf::rpg::MoveCommand DecodeMove(lcf::DBArray<int32_t>::const_iterator& it);

bool ManiacCheckContinueLoop(int val, int val2, int type, int op);

#ifdef ENABLE_DYNAMIC_INTERPRETER_CONFIG
using StateRuntimeFlagRef = bool lcf::rpg::SaveEventExecState::EasyRpgStateRuntime_Flags::*;

std::optional<bool> GetRuntimeFlag(lcf::rpg::SaveEventExecState const& state, StateRuntimeFlagRef const field_on, StateRuntimeFlagRef const field_off);

std::optional<bool> GetRuntimeFlag(lcf::rpg::SaveEventExecState::EasyRpgStateRuntime_Flags const& state_runtime_flags, StateRuntimeFlagRef const field_on, StateRuntimeFlagRef const field_off);
#endif
}

inline bool Game_Interpreter_Shared::CheckOperator(int val, int val2, int op) {
Expand Down Expand Up @@ -147,8 +159,16 @@ class Game_BaseInterpreterContext {

virtual int GetThisEventId() const = 0;
virtual Game_Character* GetCharacter(int event_id, std::string_view origin) const = 0;

virtual const lcf::rpg::SaveEventExecState& GetState() const = 0;
virtual const lcf::rpg::SaveEventExecFrame& GetFrame() const = 0;

#ifdef ENABLE_DYNAMIC_INTERPRETER_CONFIG
inline std::optional<bool> GetRuntimeFlag(Game_Interpreter_Shared::StateRuntimeFlagRef const field_on, Game_Interpreter_Shared::StateRuntimeFlagRef const field_off) const {
return Game_Interpreter_Shared::GetRuntimeFlag(GetState(), field_on, field_off);
};
#endif

protected:
template<bool validate_patches, bool support_range_indirect, bool support_expressions, bool support_bitmask, bool support_scopes, bool support_named = false>
inline bool DecodeTargetEvaluationMode(lcf::rpg::EventCommand const& com, int& id_0, int& id_1) const {
Expand Down
Loading
Loading