Skip to content

Commit bbdb3c8

Browse files
authored
Merge pull request #3379 from florianessl/features/RuntimeFlags
Change EasyRPG's "SetInterpreterFlag" to make patch overrides temporary
2 parents b5c3413 + d0ebf24 commit bbdb3c8

9 files changed

Lines changed: 535 additions & 38 deletions

src/feature.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,19 @@
1818
// Headers
1919
#include "feature.h"
2020
#include "player.h"
21+
#include "game_interpreter_shared.h"
2122
#include <lcf/data.h>
2223

2324
bool Feature::HasRpg2kBattleSystem() {
2425
if (Player::IsRPG2k()) {
2526
return true;
2627
}
27-
28+
#ifdef ENABLE_DYNAMIC_INTERPRETER_CONFIG
29+
using Flags = lcf::rpg::SaveEventExecState::EasyRpgStateRuntime_Flags;
30+
if (auto f = Player::GetRuntimeFlag(&Flags::use_rpg2k_battle_system_on, &Flags::use_rpg2k_battle_system_off)) {
31+
return *f;
32+
}
33+
#endif
2834
return lcf::Data::system.easyrpg_use_rpg2k_battle_system;
2935
}
3036

src/game_interpreter.cpp

Lines changed: 129 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ bool Game_Interpreter::ReachedLoopLimit() const {
314314
int Game_Interpreter::GetThisEventId() const {
315315
auto event_id = GetCurrentEventId();
316316

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

385+
#ifdef ENABLE_DYNAMIC_INTERPRETER_CONFIG
386+
Player::active_interpreter_flags = &_state.easyrpg_runtime_flags;
387+
auto flags_guard = lcf::makeScopeGuard([]() {
388+
Player::active_interpreter_flags = &Player::interpreter_default_flags;
389+
});
390+
#endif
391+
385392
for (; loop_count < loop_limit; ++loop_count) {
386393
// 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.
387394
// RPG_RT compatible behavior.
@@ -829,6 +836,14 @@ bool Game_Interpreter::OnFinishStackFrame() {
829836
_state.stack.pop_back();
830837
}
831838

839+
if (is_base_frame) {
840+
#ifdef ENABLE_DYNAMIC_INTERPRETER_CONFIG
841+
// Individual runtime flags that may still be set will be cleared by
842+
// CommandEasyRpgSetInterpreterFlag if neccessary
843+
_state.easyrpg_runtime_flags.conf_override_active = false;
844+
#endif
845+
}
846+
832847
return !is_base_frame;
833848
}
834849

@@ -2006,17 +2021,17 @@ bool Game_Interpreter::CommandEndEventProcessing(lcf::rpg::EventCommand const& /
20062021
return true;
20072022
}
20082023

2009-
bool Game_Interpreter::CommandComment(const lcf::rpg::EventCommand &com) {
2024+
std::optional<bool> Game_Interpreter::HandleDynRpgScript(const lcf::rpg::EventCommand& com) {
20102025
if (Player::IsPatchDynRpg() || Player::HasEasyRpgExtensions()) {
20112026
if (com.string.empty() || com.string[0] != '@') {
20122027
// Not a DynRPG command
2013-
return true;
2028+
return std::nullopt;
20142029
}
20152030

20162031
if (!Player::IsPatchDynRpg() && Player::HasEasyRpgExtensions()) {
20172032
// Only accept commands starting with @easyrpg_
20182033
if (!StartsWith(com.string, "@easyrpg_")) {
2019-
return true;
2034+
return std::nullopt;
20202035
}
20212036
}
20222037

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

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

2058+
return {};
2059+
}
20422060

2061+
std::optional<bool> Game_Interpreter::HandleDestinyScript(const lcf::rpg::EventCommand& com) {
20432062
// DestinyScript
20442063
if (Player::IsPatchDestiny()) {
20452064
if (com.string.empty() || com.string[0] != '$') {
20462065
// Not a DestinyScript
2047-
return true;
2066+
return {};
20482067
}
20492068

20502069
return Main_Data::game_destiny->Main(GetFrame());
20512070
}
2071+
return {};
2072+
}
2073+
2074+
bool Game_Interpreter::CommandComment(const lcf::rpg::EventCommand &com) {
2075+
if (auto handled = HandleDynRpgScript(com); handled.has_value()) {
2076+
return handled.value();
2077+
}
2078+
if (auto handled = HandleDestinyScript(com); handled.has_value()) {
2079+
return handled.value();
2080+
}
20522081

20532082
return true;
20542083
}
@@ -2700,7 +2729,7 @@ namespace PicPointerPatch {
27002729

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

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

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

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

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

@@ -5363,25 +5392,102 @@ bool Game_Interpreter::CommandEasyRpgSetInterpreterFlag(lcf::rpg::EventCommand c
53635392
return true;
53645393
}
53655394

5366-
// FIXME: Store them as part of the interpreter state
5395+
#ifndef ENABLE_DYNAMIC_INTERPRETER_CONFIG
5396+
Output::Warning("CommandEasyRpgSetInterpreterFlag: Not supported on this platform");
5397+
return true;
5398+
#else
5399+
constexpr std::array<std::pair<const char*, int>, 9> config_names = {{
5400+
{ "destiny", 1 },
5401+
{ "dynrpg", 2 },
5402+
{ "maniac", 3 },
5403+
{ "common-this", 4 },
5404+
{ "pic-unlock", 5 },
5405+
{ "key-patch", 6 },
5406+
{ "rpg2k3-cmds", 7 },
5407+
{ "rpg2k3-commands", 7 },
5408+
{ "rpg2k-battle", 8 }
5409+
}};
53675410

53685411
std::string flag_name = Utils::LowerCase(ToString(com.string));
53695412
int flag_value = ValueOrVariable(com.parameters[0], com.parameters[1]);
5413+
int flag_id = 0;
5414+
5415+
if (flag_name.empty() && com.parameters.size() > 2) {
5416+
flag_id = com.parameters[2];
5417+
} else {
5418+
auto it = std::find_if(config_names.begin(), config_names.end(), [&flag_name](auto& p) { return p.first == flag_name; });
5419+
if (it != config_names.end()) {
5420+
flag_id = it->second;
5421+
}
5422+
}
53705423

5371-
if (flag_name == "dynrpg")
5372-
Player::game_config.patch_dynrpg.Set(flag_value);
5373-
if (flag_name == "maniac")
5374-
Player::game_config.patch_maniac.Set(flag_value);
5375-
if (flag_name == "common-this")
5376-
Player::game_config.patch_common_this_event.Set(flag_value);
5377-
if (flag_name == "pic-unlock")
5378-
Player::game_config.patch_unlock_pics.Set(flag_value);
5379-
if (flag_name == "key-patch")
5380-
Player::game_config.patch_key_patch.Set(flag_value);
5381-
if (flag_name == "rpg2k3-cmds" || flag_name == "rpg2k3-commands")
5382-
Player::game_config.patch_rpg2k3_commands.Set(flag_value);
5383-
if (flag_name == "rpg2k-battle")
5384-
lcf::Data::system.easyrpg_use_rpg2k_battle_system = flag_value;
5424+
// Clear any inactive flags that might be left over from a previous InterpreterFlag command
5425+
if (!_state.easyrpg_runtime_flags.conf_override_active) {
5426+
_state.easyrpg_runtime_flags.flags.fill(false);
5427+
}
5428+
5429+
switch (flag_id) {
5430+
case 1:
5431+
if (flag_value) {
5432+
_state.easyrpg_runtime_flags.patch_destiny_on = true;
5433+
} else {
5434+
_state.easyrpg_runtime_flags.patch_destiny_off = true;
5435+
}
5436+
break;
5437+
case 2:
5438+
if (flag_value) {
5439+
_state.easyrpg_runtime_flags.patch_dynrpg_on = true;
5440+
} else {
5441+
_state.easyrpg_runtime_flags.patch_dynrpg_off = true;
5442+
}
5443+
break;
5444+
case 3:
5445+
if (flag_value) {
5446+
_state.easyrpg_runtime_flags.patch_maniac_on = true;
5447+
} else {
5448+
_state.easyrpg_runtime_flags.patch_maniac_off = true;
5449+
}
5450+
break;
5451+
case 4:
5452+
if (flag_value) {
5453+
_state.easyrpg_runtime_flags.patch_common_this_event_on = true;
5454+
} else {
5455+
_state.easyrpg_runtime_flags.patch_common_this_event_off = true;
5456+
}
5457+
break;
5458+
case 5:
5459+
if (flag_value) {
5460+
_state.easyrpg_runtime_flags.patch_unlock_pics_on = true;
5461+
} else {
5462+
_state.easyrpg_runtime_flags.patch_unlock_pics_off = true;
5463+
}
5464+
break;
5465+
case 6:
5466+
if (flag_value) {
5467+
_state.easyrpg_runtime_flags.patch_keypatch_on = true;
5468+
} else {
5469+
_state.easyrpg_runtime_flags.patch_keypatch_off = true;
5470+
}
5471+
break;
5472+
case 7:
5473+
if (flag_value) {
5474+
_state.easyrpg_runtime_flags.patch_rpg2k3_cmds_on = true;
5475+
} else {
5476+
_state.easyrpg_runtime_flags.patch_rpg2k3_cmds_off = true;
5477+
}
5478+
break;
5479+
case 8:
5480+
if (flag_value) {
5481+
_state.easyrpg_runtime_flags.use_rpg2k_battle_system_on = true;
5482+
} else {
5483+
_state.easyrpg_runtime_flags.use_rpg2k_battle_system_off = true;
5484+
}
5485+
break;
5486+
default:
5487+
return true;
5488+
}
5489+
_state.easyrpg_runtime_flags.conf_override_active = true;
5490+
#endif
53855491

53865492
return true;
53875493
}

src/game_interpreter.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ class Game_Interpreter : public Game_BaseInterpreterContext
8585
* Returns the interpreters current state information.
8686
* For saving state into a save file, use GetSaveState instead.
8787
*/
88-
const lcf::rpg::SaveEventExecState& GetState() const;
88+
const lcf::rpg::SaveEventExecState& GetState() const override;
8989

9090
/**
9191
* Returns a SaveEventExecState needed for the savefile.
@@ -310,6 +310,9 @@ class Game_Interpreter : public Game_BaseInterpreterContext
310310
void ForegroundTextPush(PendingMessage pm);
311311
void EndEventProcessing();
312312

313+
std::optional<bool> HandleDynRpgScript(const lcf::rpg::EventCommand& com);
314+
std::optional<bool> HandleDestinyScript(const lcf::rpg::EventCommand& com);
315+
313316
FileRequestBinding request_id;
314317
enum class Keys {
315318
eDown,

src/game_interpreter_shared.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,24 @@ lcf::rpg::MoveCommand Game_Interpreter_Shared::DecodeMove(lcf::DBArray<int32_t>:
238238
return cmd;
239239
}
240240

241+
#ifdef ENABLE_DYNAMIC_INTERPRETER_CONFIG
242+
243+
std::optional<bool> Game_Interpreter_Shared::GetRuntimeFlag(lcf::rpg::SaveEventExecState const& state, StateRuntimeFlagRef const field_on, StateRuntimeFlagRef const field_off) {
244+
return GetRuntimeFlag(state.easyrpg_runtime_flags, field_on, field_off);
245+
}
246+
247+
std::optional<bool> Game_Interpreter_Shared::GetRuntimeFlag(lcf::rpg::SaveEventExecState::EasyRpgStateRuntime_Flags const& state_runtime_flags, StateRuntimeFlagRef const field_on, StateRuntimeFlagRef const field_off) {
248+
if (state_runtime_flags.conf_override_active) {
249+
if (state_runtime_flags.*field_on)
250+
return true;
251+
if (state_runtime_flags.*field_off)
252+
return false;
253+
}
254+
return std::nullopt;
255+
}
256+
257+
#endif
258+
241259
//explicit declarations for target evaluation logic shared between ControlSwitches/ControlVariables/ControlStrings
242260
template bool Game_Interpreter_Shared::DecodeTargetEvaluationMode<true, false, false, false, false>(lcf::rpg::EventCommand const&, int&, int&, Game_BaseInterpreterContext const&);
243261
template bool Game_Interpreter_Shared::DecodeTargetEvaluationMode<true, true, true, false, false>(lcf::rpg::EventCommand const&, int&, int&, Game_BaseInterpreterContext const&);

src/game_interpreter_shared.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,13 @@
2121

2222
#include <lcf/rpg/eventcommand.h>
2323
#include <lcf/rpg/movecommand.h>
24+
#include <lcf/rpg/saveeventexecstate.h>
2425
#include <lcf/rpg/saveeventexecframe.h>
2526
#include <string_view.h>
2627
#include "compiler.h"
28+
#include <optional>
29+
30+
#define ENABLE_DYNAMIC_INTERPRETER_CONFIG
2731

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

105109
bool ManiacCheckContinueLoop(int val, int val2, int type, int op);
110+
111+
#ifdef ENABLE_DYNAMIC_INTERPRETER_CONFIG
112+
using StateRuntimeFlagRef = bool lcf::rpg::SaveEventExecState::EasyRpgStateRuntime_Flags::*;
113+
114+
std::optional<bool> GetRuntimeFlag(lcf::rpg::SaveEventExecState const& state, StateRuntimeFlagRef const field_on, StateRuntimeFlagRef const field_off);
115+
116+
std::optional<bool> GetRuntimeFlag(lcf::rpg::SaveEventExecState::EasyRpgStateRuntime_Flags const& state_runtime_flags, StateRuntimeFlagRef const field_on, StateRuntimeFlagRef const field_off);
117+
#endif
106118
}
107119

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

148160
virtual int GetThisEventId() const = 0;
149161
virtual Game_Character* GetCharacter(int event_id, std::string_view origin) const = 0;
162+
163+
virtual const lcf::rpg::SaveEventExecState& GetState() const = 0;
150164
virtual const lcf::rpg::SaveEventExecFrame& GetFrame() const = 0;
151165

166+
#ifdef ENABLE_DYNAMIC_INTERPRETER_CONFIG
167+
inline std::optional<bool> GetRuntimeFlag(Game_Interpreter_Shared::StateRuntimeFlagRef const field_on, Game_Interpreter_Shared::StateRuntimeFlagRef const field_off) const {
168+
return Game_Interpreter_Shared::GetRuntimeFlag(GetState(), field_on, field_off);
169+
};
170+
#endif
171+
152172
protected:
153173
template<bool validate_patches, bool support_range_indirect, bool support_expressions, bool support_bitmask, bool support_scopes, bool support_named = false>
154174
inline bool DecodeTargetEvaluationMode(lcf::rpg::EventCommand const& com, int& id_0, int& id_1) const {

0 commit comments

Comments
 (0)