diff --git a/src/game_interpreter.cpp b/src/game_interpreter.cpp index be764c52e9..c260d30acc 100644 --- a/src/game_interpreter.cpp +++ b/src/game_interpreter.cpp @@ -1076,16 +1076,16 @@ bool Game_Interpreter::CommandControlSwitches(lcf::rpg::EventCommand const& com) int val = com.parameters[3]; if (start == end) { - if (val < 2) { + if (val == 0 || val == 1) { Main_Data::game_switches->Set(start, val == 0); - } else { + } else if (val == 2) { Main_Data::game_switches->Flip(start); } Game_Map::SetNeedRefreshForSwitchChange(start); } else { - if (val < 2) { + if (val == 0 || val == 1) { Main_Data::game_switches->SetRange(start, end, val == 0); - } else { + } else if (val == 2) { Main_Data::game_switches->FlipRange(start, end); } Game_Map::SetNeedRefresh(true); @@ -1545,19 +1545,20 @@ std::vector Game_Interpreter::GetActors(int mode, int id) { return actors; } -Game_Character* Game_Interpreter::GetCharacter(int event_id, std::string_view origin) const { +Game_Character* Game_Interpreter::GetCharacter(int event_id, std::string_view origin, bool silent) const { if (event_id == Game_Character::CharThisEvent) { event_id = GetThisEventId(); // Is a common event if (event_id == 0) { // With no map parent + // Still reported even when "silent" as this would hide a bug Output::Warning("{}: Can't use ThisEvent in common event: Not called from a map event", origin); return nullptr; } } Game_Character* ch = Game_Character::GetCharacter(event_id, event_id); - if (!ch) { + if (!ch && !silent) { Output::Warning("{}: Unknown event with id {}", origin, event_id); } return ch; @@ -3623,9 +3624,14 @@ bool Game_Interpreter::CommandConditionalBranch(lcf::rpg::EventCommand const& co chara_id = ValueOrVariable(com.parameters[3], chara_id); } - character = GetCharacter(chara_id, "ConditionalBranch"); - if (character != NULL) { - result = character->GetFacing() == com.parameters[2]; + if (Player::IsPatchManiac() && com.parameters[4] == 1) { + // Existance check + result = GetCharacter(chara_id, "ConditionalBranch", true) != nullptr; + } else { + character = GetCharacter(chara_id, "ConditionalBranch"); + if (character) { + result = character->GetFacing() == com.parameters[2]; + } } break; } @@ -4674,7 +4680,31 @@ bool Game_Interpreter::CommandManiacShowStringPicture(lcf::rpg::EventCommand con } params.system_name = components[2]; + uint32_t var_id = 0; + auto mode = delims[1] - 1; + if (mode > 0) { + if (!ManiacPatch::DecodeStringToInt(params.system_name, var_id)) { + Output::Warning("ShowStringPic: Bad system name arg (id={}, arg={})", pic_id, components[2]); + return true; + } + + params.system_name = Main_Data::game_strings->GetWithMode( + params.system_name, mode, var_id, *Main_Data::game_variables + ); + } + text.font_name = components[3]; + mode = delims[2] - 1; + if (mode > 0) { + if (!ManiacPatch::DecodeStringToInt(text.font_name, var_id)) { + Output::Warning("ShowStringPic: Bad font name arg (id={}, arg={})", pic_id, components[3]); + return true; + } + + text.font_name = Main_Data::game_strings->GetWithMode( + text.font_name, mode, var_id, *Main_Data::game_variables + ); + } params.texts = {text}; diff --git a/src/game_interpreter.h b/src/game_interpreter.h index 47671b2000..c66bff0c2d 100644 --- a/src/game_interpreter.h +++ b/src/game_interpreter.h @@ -104,7 +104,7 @@ class Game_Interpreter : public Game_BaseInterpreterContext lcf::rpg::SaveEventExecState GetSaveState(); /** @return Game_Character of the passed event_id */ - Game_Character* GetCharacter(int event_id, std::string_view origin) const override; + Game_Character* GetCharacter(int event_id, std::string_view origin, bool silent = false) const override; /** @return the event_id of the current frame */ int GetCurrentEventId() const; diff --git a/src/game_interpreter_shared.cpp b/src/game_interpreter_shared.cpp index 6d8f417419..c2bf508cd0 100644 --- a/src/game_interpreter_shared.cpp +++ b/src/game_interpreter_shared.cpp @@ -78,6 +78,10 @@ inline bool Game_Interpreter_Shared::DecodeTargetEvaluationMode(lcf::rpg::EventC return true; } break; + default: + id_0 = 0; + id_1 = 0; + break; } if constexpr (validate_patches) { diff --git a/src/game_interpreter_shared.h b/src/game_interpreter_shared.h index a033aaad18..61ba66ca99 100644 --- a/src/game_interpreter_shared.h +++ b/src/game_interpreter_shared.h @@ -252,7 +252,7 @@ class Game_BaseInterpreterContext { virtual ~Game_BaseInterpreterContext() {} virtual int GetThisEventId() const = 0; - virtual Game_Character* GetCharacter(int event_id, std::string_view origin) const = 0; + virtual Game_Character* GetCharacter(int event_id, std::string_view origin, bool silent = false) const = 0; virtual const lcf::rpg::SaveEventExecState& GetState() const = 0; virtual const lcf::rpg::SaveEventExecFrame& GetFrame() const = 0; diff --git a/src/game_strings.cpp b/src/game_strings.cpp index 63eb5d66c3..2dbd0f8c06 100644 --- a/src/game_strings.cpp +++ b/src/game_strings.cpp @@ -92,7 +92,7 @@ int Game_Strings::ToNum(Str_Params params, int var_id, Game_Variables& variables if (params.hex) num = static_cast(std::strtol(it->second.c_str(), nullptr, 16)); else - num = static_cast(std::strtol(it->second.c_str(), nullptr, 0)); + num = static_cast(std::strtol(it->second.c_str(), nullptr, 10)); variables.Set(var_id, num); diff --git a/src/maniac_patch.cpp b/src/maniac_patch.cpp index e672e97429..50cee3f2f4 100644 --- a/src/maniac_patch.cpp +++ b/src/maniac_patch.cpp @@ -834,6 +834,53 @@ std::string_view ManiacPatch::GetLcfDescription(int data_type, int id, bool is_d return {}; } +bool ManiacPatch::DecodeStringToInt(std::string_view str, uint32_t& out) { + /* + Is a custom 5 bit encoding: + + For the rightmost character c the value is: + c - A + 1 + + For all other characters c with index i the value is: + (c - a + 1) << (i * 5) + + Due to integer overflow the max string length is 6. + */ + + out = 0; + + if (!(str.size() > 0 && str.size() <= 6)) { + return false; + } + + auto in_range = [](int32_t value) { + return value >= 0 && value < 32; + }; + + int32_t result = (str.back() - 'A' + 1); + + if (!in_range(result)) { + return false; + } + + out = static_cast(result); + + str.remove_suffix(1); + + for (size_t i = 0; i < str.size(); ++i) { + result = (str[i] - 'a' + 1); + + if (!in_range(result)) { + return false; + } + + int chidx = str.size() - i; + out += static_cast(result << (chidx * 5)); + } + + return out; +} + bool ManiacPatch::GlobalSave::Load() { if (!Player::IsPatchManiac()) { return true; diff --git a/src/maniac_patch.h b/src/maniac_patch.h index cf62d453ca..15b89a0ec3 100644 --- a/src/maniac_patch.h +++ b/src/maniac_patch.h @@ -38,6 +38,17 @@ namespace ManiacPatch { std::string_view GetLcfName(int data_type, int id, bool is_dynamic); std::string_view GetLcfDescription(int data_type, int id, bool is_dynamic); + /** + * Decodes an encoded string as used by the ShowStringPicture to the number + * representation. + * + * @param str String to decode + * @param out The number represented by the string + * + * @return Whether the decoding was successful (this function will reject malformed strings) + */ + bool DecodeStringToInt(std::string_view str, uint32_t& out); + namespace GlobalSave { /** * Attempts to load Save.lgs from the save directory.