From ee4c3b8eb8eb5d35ac626274784cb3ce86e853b2 Mon Sep 17 00:00:00 2001 From: Ghabry Date: Wed, 8 Mar 2023 10:12:51 +0100 Subject: [PATCH 1/3] Maniac: Support indirection for BGM and SE command --- .gitignore | 2 ++ src/game_interpreter.cpp | 37 ++++++++++++++++++++++++++++++------- src/game_interpreter.h | 1 + 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index fe5f798435..83a7e2b742 100644 --- a/.gitignore +++ b/.gitignore @@ -61,6 +61,8 @@ install_manifest.txt *.ilk *.pdb /resources/player.rc +.vs/ +vcpkg/ # ninja .ninja_* diff --git a/src/game_interpreter.cpp b/src/game_interpreter.cpp index 2c327386db..da9712fd54 100644 --- a/src/game_interpreter.cpp +++ b/src/game_interpreter.cpp @@ -1736,6 +1736,10 @@ int Game_Interpreter::ValueOrVariable(int mode, int val) { return -1; } +int Game_Interpreter::ValueOrVariableBitfield(int mode, int shift, int val) { + return ValueOrVariable((mode & (0xF << shift * 4)) >> shift * 4, val); +} + bool Game_Interpreter::CommandChangeParameters(lcf::rpg::EventCommand const& com) { // Code 10430 int value = OperateValue( com.parameters[2], @@ -1990,10 +1994,20 @@ bool Game_Interpreter::CommandWait(lcf::rpg::EventCommand const& com) { // code bool Game_Interpreter::CommandPlayBGM(lcf::rpg::EventCommand const& com) { // code 11510 lcf::rpg::Music music; music.name = ToString(com.string); - music.fadein = com.parameters[0]; - music.volume = com.parameters[1]; - music.tempo = com.parameters[2]; - music.balance = com.parameters[3]; + + if (Player::IsPatchManiac() && com.parameters.size() >= 5) { + int mode = com.parameters[4]; + music.fadein = ValueOrVariableBitfield(mode, 1, com.parameters[0]); + music.volume = ValueOrVariableBitfield(mode, 2, com.parameters[1]); + music.tempo = ValueOrVariableBitfield(mode, 3, com.parameters[2]); + music.balance = ValueOrVariableBitfield(mode, 4, com.parameters[3]); + } else { + music.fadein = com.parameters[0]; + music.volume = com.parameters[1]; + music.tempo = com.parameters[2]; + music.balance = com.parameters[3]; + } + Main_Data::game_system->BgmPlay(music); return true; } @@ -2007,9 +2021,18 @@ bool Game_Interpreter::CommandFadeOutBGM(lcf::rpg::EventCommand const& com) { // bool Game_Interpreter::CommandPlaySound(lcf::rpg::EventCommand const& com) { // code 11550 lcf::rpg::Sound sound; sound.name = ToString(com.string); - sound.volume = com.parameters[0]; - sound.tempo = com.parameters[1]; - sound.balance = com.parameters[2]; + + if (Player::IsPatchManiac() && com.parameters.size() >= 4) { + int mode = com.parameters[3]; + sound.volume = ValueOrVariableBitfield(mode, 1, com.parameters[0]); + sound.tempo = ValueOrVariableBitfield(mode, 2, com.parameters[1]); + sound.balance = ValueOrVariableBitfield(mode, 3, com.parameters[2]); + } else { + sound.volume = com.parameters[0]; + sound.tempo = com.parameters[1]; + sound.balance = com.parameters[2]; + } + Main_Data::game_system->SePlay(sound, true); return true; } diff --git a/src/game_interpreter.h b/src/game_interpreter.h index d42bbc9298..d510060237 100644 --- a/src/game_interpreter.h +++ b/src/game_interpreter.h @@ -163,6 +163,7 @@ class Game_Interpreter */ static std::vector GetActors(int mode, int id); static int ValueOrVariable(int mode, int val); + static int ValueOrVariableBitfield(int mode, int shift, int val); /** * When current frame finishes executing we pop the stack From 01fbeab6de6049794f336a117f53ce32fe24a079 Mon Sep 17 00:00:00 2001 From: Ghabry Date: Wed, 8 Mar 2023 10:23:03 +0100 Subject: [PATCH 2/3] Use new ValueOrVariableBitfield function where applicable Maniac Patch uses this pattern alot --- src/game_interpreter.cpp | 75 +++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 39 deletions(-) diff --git a/src/game_interpreter.cpp b/src/game_interpreter.cpp index da9712fd54..392ef97f79 100644 --- a/src/game_interpreter.cpp +++ b/src/game_interpreter.cpp @@ -1146,79 +1146,79 @@ bool Game_Interpreter::CommandControlVariables(lcf::rpg::EventCommand const& com } case 11: { // Pow (Maniac) - int arg1 = ValueOrVariable(com.parameters[7] & 0xF, com.parameters[5]); - int arg2 = ValueOrVariable((com.parameters[7] >> 4) & 0xF, com.parameters[6]); + int arg1 = ValueOrVariableBitfield(com.parameters[7], 0, com.parameters[5]); + int arg2 = ValueOrVariableBitfield(com.parameters[7], 1, com.parameters[6]); value = ControlVariables::Pow(arg1, arg2); break; } case 12: { // Sqrt (Maniac) - int arg = ValueOrVariable(com.parameters[7] & 0xF, com.parameters[5]); + int arg = ValueOrVariableBitfield(com.parameters[7], 0, com.parameters[5]); int mul = com.parameters[6]; value = ControlVariables::Sqrt(arg, mul); break; } case 13: { // Sin (Maniac) - int arg1 = ValueOrVariable(com.parameters[7] & 0xF, com.parameters[5]); - int arg2 = ValueOrVariable((com.parameters[7] >> 4) & 0xF, com.parameters[8]); + int arg1 = ValueOrVariableBitfield(com.parameters[7], 0, com.parameters[5]); + int arg2 = ValueOrVariableBitfield(com.parameters[7], 1, com.parameters[8]); float mul = static_cast(com.parameters[6]); value = ControlVariables::Sin(arg1, arg2, mul); break; } case 14: { // Cos (Maniac) - int arg1 = ValueOrVariable(com.parameters[7] & 0xF, com.parameters[5]); - int arg2 = ValueOrVariable((com.parameters[7] >> 4) & 0xF, com.parameters[8]); + int arg1 = ValueOrVariableBitfield(com.parameters[7], 0, com.parameters[5]); + int arg2 = ValueOrVariableBitfield(com.parameters[7], 1, com.parameters[8]); int mul = com.parameters[6]; value = ControlVariables::Cos(arg1, arg2, mul); break; } case 15: { // Atan2 (Maniac) - int arg1 = ValueOrVariable(com.parameters[8] & 0xF, com.parameters[5]); - int arg2 = ValueOrVariable((com.parameters[8] >> 4) & 0xF, com.parameters[6]); + int arg1 = ValueOrVariableBitfield(com.parameters[8], 0, com.parameters[5]); + int arg2 = ValueOrVariableBitfield(com.parameters[8], 1, com.parameters[6]); int mul = com.parameters[7]; value = ControlVariables::Atan2(arg1, arg2, mul); break; } case 16: { // Min (Maniac) - int arg1 = ValueOrVariable(com.parameters[7] & 0xF, com.parameters[5]); - int arg2 = ValueOrVariable((com.parameters[7] >> 4) & 0xF, com.parameters[6]); + int arg1 = ValueOrVariableBitfield(com.parameters[7], 0, com.parameters[5]); + int arg2 = ValueOrVariableBitfield(com.parameters[7], 1, com.parameters[6]); value = ControlVariables::Min(arg1, arg2); break; } case 17: { // Max (Maniac) - int arg1 = ValueOrVariable(com.parameters[7] & 0xF, com.parameters[5]); - int arg2 = ValueOrVariable((com.parameters[7] >> 4) & 0xF, com.parameters[6]); + int arg1 = ValueOrVariableBitfield(com.parameters[7], 0, com.parameters[5]); + int arg2 = ValueOrVariableBitfield(com.parameters[7], 1, com.parameters[6]); value = ControlVariables::Max(arg1, arg2); break; } case 18: { // Abs (Maniac) - int arg = ValueOrVariable(com.parameters[6] & 0xF, com.parameters[5]); + int arg = ValueOrVariableBitfield(com.parameters[6], 0, com.parameters[5]); value = ControlVariables::Abs(arg); break; } case 19: { // Binary (Maniac) - int arg1 = ValueOrVariable(com.parameters[8] & 0xF, com.parameters[6]); - int arg2 = ValueOrVariable((com.parameters[8] >> 4) & 0xF, com.parameters[7]); + int arg1 = ValueOrVariableBitfield(com.parameters[8], 0, com.parameters[6]); + int arg2 = ValueOrVariableBitfield(com.parameters[8], 1, com.parameters[7]); value = ControlVariables::Binary(com.parameters[5], arg1, arg2); break; } case 20: { // Ternary (Maniac) int mode = com.parameters[10]; - int arg1 = ValueOrVariable(mode & 0xF, com.parameters[6]); - int arg2 = ValueOrVariable((mode >> 4) & 0xF, com.parameters[7]); + int arg1 = ValueOrVariableBitfield(mode, 0, com.parameters[6]); + int arg2 = ValueOrVariableBitfield(mode, 1, com.parameters[7]); int op = com.parameters[5]; if (CheckOperator(arg1, arg2, op)) { - value = ValueOrVariable((mode >> 8) & 0xF, com.parameters[8]); + value = ValueOrVariableBitfield(mode, 2, com.parameters[8]); } else { - value = ValueOrVariable((mode >> 12) & 0xF, com.parameters[9]); + value = ValueOrVariableBitfield(mode, 3, com.parameters[9]); } break; } @@ -2768,8 +2768,8 @@ bool Game_Interpreter::CommandShowPicture(lcf::rpg::EventCommand const& com) { / params.origin = com.parameters[1] >> 8; if (params.effect_mode == lcf::rpg::SavePicture::Effect_maniac_fixed_angle) { - params.effect_power = ValueOrVariable(com.parameters[16] & 0xF, params.effect_power); - int divisor = ValueOrVariable((com.parameters[16] & 0xF0) >> 4, com.parameters[15]); + params.effect_power = ValueOrVariableBitfield(com.parameters[16], 0, params.effect_power); + int divisor = ValueOrVariableBitfield(com.parameters[16], 1, com.parameters[15]); if (divisor == 0) { divisor = 1; } @@ -2860,8 +2860,8 @@ bool Game_Interpreter::CommandMovePicture(lcf::rpg::EventCommand const& com) { / params.origin = com.parameters[1] >> 8; if (params.effect_mode == lcf::rpg::SavePicture::Effect_maniac_fixed_angle) { - params.effect_power = ValueOrVariable(com.parameters[16] & 0xF, params.effect_power); - int divisor = ValueOrVariable((com.parameters[16] & 0xF0) >> 4, com.parameters[15]); + params.effect_power = ValueOrVariableBitfield(com.parameters[16], 0, params.effect_power); + int divisor = ValueOrVariableBitfield(com.parameters[16], 1, com.parameters[15]); if (divisor == 0) { divisor = 1; } @@ -3607,8 +3607,8 @@ bool Game_Interpreter::CommandLoop(lcf::rpg::EventCommand const& com) { // code begin_loop_val = 0; end_loop_val = 0; - int begin_arg = ValueOrVariable(com.parameters[1] & 0xF, com.parameters[2]); - int end_arg = ValueOrVariable((com.parameters[1] >> 4) & 0xF, com.parameters[3]); + int begin_arg = ValueOrVariableBitfield(com.parameters[1], 0, com.parameters[2]); + int end_arg = ValueOrVariableBitfield(com.parameters[1], 1, com.parameters[3]); int op = com.parameters[1] >> 8; switch (type) { @@ -3632,8 +3632,8 @@ bool Game_Interpreter::CommandLoop(lcf::rpg::EventCommand const& com) { // code int check_beg = begin_loop_val; int check_end = end_loop_val; if (type == 4) { // While - check_beg = ValueOrVariable(com.parameters[1] & 0xF, com.parameters[2]); - check_end = ValueOrVariable((com.parameters[1] >> 4) & 0xF, com.parameters[3]); + check_beg = ValueOrVariableBitfield(com.parameters[1], 0, com.parameters[2]); + check_end = ValueOrVariableBitfield(com.parameters[1], 1, com.parameters[3]); } // Do While (5) always runs the loop at least once @@ -3717,8 +3717,8 @@ bool Game_Interpreter::CommandEndLoop(lcf::rpg::EventCommand const& com) { // co if (type >= 4) { // While (4) and Do While (5) fetch variables each loop // For the others it is constant - check_cur = ValueOrVariable(com.parameters[1] & 0xF, com.parameters[2]); - check_end = ValueOrVariable((com.parameters[1] >> 4) & 0xF, com.parameters[3]); + check_cur = ValueOrVariableBitfield(com.parameters[1], 0, com.parameters[2]); + check_end = ValueOrVariableBitfield(com.parameters[1], 1, com.parameters[3]); } int op = com.parameters[1] >> 8; if (!ManiacCheckContinueLoop(check_cur, check_end, type, op)) { @@ -4170,13 +4170,10 @@ bool Game_Interpreter::CommandManiacControlVarArray(lcf::rpg::EventCommand const int op = com.parameters[0]; int mode = com.parameters[1]; - int mode_a = mode & 0xF; - int mode_size = (mode >> 4) & 0xF; - int mode_b = (mode >> 8) & 0xF; - int target_a = ValueOrVariable(mode_a, com.parameters[2]); - int length = ValueOrVariable(mode_size, com.parameters[3]); - int target_b = ValueOrVariable(mode_b, com.parameters[4]); + int target_a = ValueOrVariableBitfield(mode, 0, com.parameters[2]); + int length = ValueOrVariableBitfield(mode, 1, com.parameters[3]); + int target_b = ValueOrVariableBitfield(mode, 2, com.parameters[4]); int last_target_a = target_a + length - 1; if (target_a < 1 || length <= 0) { @@ -4384,9 +4381,9 @@ bool Game_Interpreter::CommandManiacControlGlobalSave(lcf::rpg::EventCommand con writer.Write(Main_Data::game_variables_global->GetData()); } else if (operation == 4 || operation == 5) { int type = com.parameters[2]; - int game_state_idx = ValueOrVariable(com.parameters[1] & 0xF, com.parameters[3]); - int global_save_idx = ValueOrVariable((com.parameters[1] >> 4) & 0xF, com.parameters[4]); - int length = ValueOrVariable((com.parameters[1] >> 8) & 0xF, com.parameters[5]); + int game_state_idx = ValueOrVariableBitfield(com.parameters[1], 0, com.parameters[3]); + int global_save_idx = ValueOrVariableBitfield(com.parameters[1], 1, com.parameters[4]); + int length = ValueOrVariableBitfield(com.parameters[1], 2, com.parameters[5]); if (operation == 4) { // Copy from global save to game state From 9728d7db9af9671791be30da87857aa10f041d9e Mon Sep 17 00:00:00 2001 From: Ghabry Date: Wed, 8 Mar 2023 11:03:52 +0100 Subject: [PATCH 3/3] Maniac: Wait: Support indirection and waiting by frames --- src/game_interpreter.cpp | 34 +++++++++++++++++++++++++++++++++- src/game_interpreter.h | 5 +++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/game_interpreter.cpp b/src/game_interpreter.cpp index 392ef97f79..4043c92e07 100644 --- a/src/game_interpreter.cpp +++ b/src/game_interpreter.cpp @@ -287,6 +287,15 @@ void Game_Interpreter::SetupWait(int duration) { } } +void Game_Interpreter::SetupWaitFrames(int duration) { + if (duration == 0) { + // 0.0 waits 1 frame + _state.wait_time = 1; + } else { + _state.wait_time = duration; + } +} + bool Game_Interpreter::ReachedLoopLimit() const { return loop_count >= loop_limit; } @@ -1972,13 +1981,34 @@ bool Game_Interpreter::CommandSimulatedAttack(lcf::rpg::EventCommand const& com) bool Game_Interpreter::CommandWait(lcf::rpg::EventCommand const& com) { // code 11410 auto& index = GetFrame().current_command; + bool maniac = Player::IsPatchManiac(); + // Wait a given time if (com.parameters.size() <= 1 || - (com.parameters.size() > 1 && com.parameters[1] == 0)) { + (!maniac && com.parameters.size() > 1 && com.parameters[1] == 0)) { SetupWait(com.parameters[0]); return true; } + if (maniac && com.parameters.size() > 1) { + int wait_type = com.parameters[1]; + int mode = 0; + + if (com.parameters.size() > 2) { + mode = com.parameters[2]; + } + + int duration = ValueOrVariable(mode, com.parameters[0]); + + if (wait_type == 256) { + SetupWaitFrames(duration); + } else { + SetupWait(duration); + } + + return true; + } + if (Game_Message::IsMessageActive()) { return false; } @@ -2033,6 +2063,8 @@ bool Game_Interpreter::CommandPlaySound(lcf::rpg::EventCommand const& com) { // sound.balance = com.parameters[2]; } + Output::Debug("SE {} {} {} {}", sound.name, sound.volume, sound.tempo, sound.balance); + Main_Data::game_system->SePlay(sound, true); return true; } diff --git a/src/game_interpreter.h b/src/game_interpreter.h index d510060237..eecd396667 100644 --- a/src/game_interpreter.h +++ b/src/game_interpreter.h @@ -155,6 +155,11 @@ class Game_Interpreter */ void SetupWait(int duration); + /** + * Sets up a wait using frames (and closes the message box) + */ + void SetupWaitFrames(int duration); + /** * Calculates list of actors. *