diff --git a/src/game_config_game.cpp b/src/game_config_game.cpp index 359158a33e..cb23653170 100644 --- a/src/game_config_game.cpp +++ b/src/game_config_game.cpp @@ -87,6 +87,7 @@ void Game_ConfigGame::LoadFromArgs(CmdlineParser& cp) { patch_common_this_event.Lock(false); patch_key_patch.Lock(false); patch_rpg2k3_commands.Lock(false); + patch_direct_menu.Lock(false); patch_override = true; continue; } @@ -105,6 +106,8 @@ void Game_ConfigGame::LoadFromArgs(CmdlineParser& cp) { patch_key_patch.Set(true); } else if (v == "rpg2k3-cmds" || v == "rpg2k3-commands") { patch_rpg2k3_commands.Set(true); + } else if (v == "direct-menu") { + patch_direct_menu.Set(true); } } patch_override = true; @@ -151,4 +154,8 @@ void Game_ConfigGame::LoadFromStream(Filesystem_Stream::InputStream& is) { if (patch_rpg2k3_commands.FromIni(ini)) { patch_override = true; } + + if (patch_direct_menu.FromIni(ini)) { + patch_override = true; + } } diff --git a/src/game_config_game.h b/src/game_config_game.h index 3064a2d3cb..504b68c6c7 100644 --- a/src/game_config_game.h +++ b/src/game_config_game.h @@ -44,6 +44,7 @@ struct Game_ConfigGame { BoolConfigParam patch_unlock_pics{ "Unlock Pictures", "Allow picture commands while a message is shown", "Patch", "PicUnlock", false }; BoolConfigParam patch_key_patch{ "Ineluki Key Patch", "Support \"Ineluki Key Patch\"", "Patch", "KeyPatch", false }; BoolConfigParam patch_rpg2k3_commands{ "RPG2k3 Event Commands", "Enable support for RPG2k3 event commands", "Patch", "RPG2k3Commands", false }; + ConfigParam patch_direct_menu{ "Direct Menu", " Allows direct access to subscreens of the default menu", "Patch", "DirectMenu", 0 }; // Command line only BoolConfigParam patch_support{ "Support patches", "When OFF all patch support is disabled", "", "", true }; diff --git a/src/game_interpreter_map.cpp b/src/game_interpreter_map.cpp index 8d6a26537a..60587a8bfa 100644 --- a/src/game_interpreter_map.cpp +++ b/src/game_interpreter_map.cpp @@ -23,6 +23,7 @@ #include #include #include "audio.h" +#include "feature.h" #include "game_map.h" #include "game_battle.h" #include "game_event.h" @@ -38,8 +39,13 @@ #include "sprite_character.h" #include "scene_map.h" #include "scene_battle.h" +#include "scene_equip.h" +#include "scene_item.h" #include "scene_menu.h" +#include "scene_order.h" #include "scene_save.h" +#include "scene_status.h" +#include "scene_skill.h" #include "scene_load.h" #include "scene_name.h" #include "scene_shop.h" @@ -83,6 +89,82 @@ void Game_Interpreter_Map::OnMapChange() { } } +bool Game_Interpreter_Map::RequestMainMenuScene(int subscreen_id, int actor_index, bool is_db_actor) { + + if (Player::game_config.patch_direct_menu.Get() && subscreen_id == -1) { + subscreen_id = Main_Data::game_variables->Get(Player::game_config.patch_direct_menu.Get()); + actor_index = Main_Data::game_variables->Get(Player::game_config.patch_direct_menu.Get() + 1); + is_db_actor = (actor_index < 0); + actor_index = std::abs(actor_index); + } + + switch (subscreen_id) + { + case 1: // Inventory + Scene::instance->SetRequestedScene(std::make_shared()); + return true; + case 2: // Skills + case 3: // Equipment + case 4: // Status + if (!is_db_actor) { + if (actor_index == 0 || actor_index > 4) { + actor_index = 1; + } + actor_index--; + } + + if (is_db_actor && !Main_Data::game_actors->GetActor(actor_index)) { + Output::Warning("Invalid actor ID {}", actor_index); + return false; + } + + if (subscreen_id == 2) { + Scene::instance->SetRequestedScene(std::make_shared(actor_index, 0, is_db_actor)); + } + else if (subscreen_id == 3) { + Game_Actor* actor; + if (!is_db_actor) { + actor = Main_Data::game_party->GetActors()[actor_index]; + } + else { + actor = Main_Data::game_actors->GetActor(actor_index); + } + Scene::instance->SetRequestedScene(std::make_shared(*actor)); + } + else if (subscreen_id == 4) { + Scene::instance->SetRequestedScene(std::make_shared(actor_index, is_db_actor)); + } + return true; + case 5: // Order + if (!Feature::HasRow()) { + break; + } + + if (Main_Data::game_party->GetActors().size() <= 1) { + Output::Warning("Party size must exceed '1' for 'Order' subscreen to be opened"); + return false; + } + else { + Scene::instance->SetRequestedScene(std::make_shared()); + return true; + } + /* + case 6: // Settings + Scene::instance->SetRequestedScene(std::make_shared()); + return true; + case 7: // Language + Scene::instance->SetRequestedScene(std::make_shared()); + return true; + case 8: // Debug + Scene::instance->SetRequestedScene(std::make_shared()); + return true; + */ + } + + Scene::instance->SetRequestedScene(std::make_shared()); + return true; +} + /** * Execute Command. */ @@ -636,7 +718,7 @@ bool Game_Interpreter_Map::CommandOpenSaveMenu(lcf::rpg::EventCommand const& /* return false; } -bool Game_Interpreter_Map::CommandOpenMainMenu(lcf::rpg::EventCommand const& /* com */) { // code 11950 +bool Game_Interpreter_Map::CommandOpenMainMenu(lcf::rpg::EventCommand const& com) { // code 11950 auto& frame = GetFrame(); auto& index = frame.current_command; @@ -644,9 +726,25 @@ bool Game_Interpreter_Map::CommandOpenMainMenu(lcf::rpg::EventCommand const& /* return false; } - Scene::instance->SetRequestedScene(std::make_shared()); - ++index; - return false; + int subscreen_id = -1, actor_index = 0; + bool is_db_actor = false; + + if (com.parameters.size() > 0) { + subscreen_id = com.parameters[0]; + + if (com.parameters.size() > 1) { + actor_index = com.parameters[1]; + } + if (com.parameters.size() > 2 && com.parameters[2]) { + is_db_actor = true; + } + } + + if (RequestMainMenuScene(subscreen_id, actor_index, is_db_actor)) { + ++index; + return false; + } + return true; } bool Game_Interpreter_Map::CommandOpenLoadMenu(lcf::rpg::EventCommand const& /* com */) { diff --git a/src/game_interpreter_map.h b/src/game_interpreter_map.h index 5dd41139eb..fc31a37a2b 100644 --- a/src/game_interpreter_map.h +++ b/src/game_interpreter_map.h @@ -51,6 +51,8 @@ class Game_Interpreter_Map : public Game_Interpreter */ void OnMapChange(); + bool RequestMainMenuScene(int subscreen_id = -1, int actor_index = 0, bool is_db_actor = false); + bool ExecuteCommand(lcf::rpg::EventCommand const& com) override; private: diff --git a/src/game_player.cpp b/src/game_player.cpp index 33085d61dc..99c07b0364 100644 --- a/src/game_player.cpp +++ b/src/game_player.cpp @@ -295,7 +295,7 @@ void Game_Player::UpdateNextMovementAction() { ResetAnimation(); Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Decision)); - Scene::instance->SetRequestedScene(std::make_shared()); + Game_Map::GetInterpreter().RequestMainMenuScene(); return; } diff --git a/src/player.cpp b/src/player.cpp index 2279b02d49..02260f498b 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -825,8 +825,8 @@ void Player::CreateGameObjects() { } } - Output::Debug("Patch configuration: dynrpg={} maniac={} key-patch={} common-this={} pic-unlock={} 2k3-commands={}", - Player::IsPatchDynRpg(), Player::IsPatchManiac(), Player::IsPatchKeyPatch(), game_config.patch_common_this_event.Get(), game_config.patch_unlock_pics.Get(), game_config.patch_rpg2k3_commands.Get()); + Output::Debug("Patch configuration: dynrpg={} maniac={} key-patch={} common-this={} pic-unlock={} 2k3-commands={} direct-menu={}", + Player::IsPatchDynRpg(), Player::IsPatchManiac(), Player::IsPatchKeyPatch(), game_config.patch_common_this_event.Get(), game_config.patch_unlock_pics.Get(), game_config.patch_rpg2k3_commands.Get(), game_config.patch_direct_menu.Get()); ResetGameObjects(); @@ -1403,6 +1403,7 @@ Engine options: pic-unlock - Pictures are not blocked by messages rpg2k3-cmds - Support all RPG Maker 2003 event commands in any version of the engine + direct-menu - Directly access subscreens of default menu --no-patch Disable all engine patches. --project-path PATH Instead of using the working directory, the game in PATH is used. diff --git a/src/scene_equip.cpp b/src/scene_equip.cpp index 6dc13f8d2f..e258207615 100644 --- a/src/scene_equip.cpp +++ b/src/scene_equip.cpp @@ -179,13 +179,17 @@ void Scene_Equip::UpdateEquipSelection() { } else if (Main_Data::game_party->GetActors().size() > 1 && Input::IsTriggered(Input::RIGHT)) { Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Cursor)); int actor_index = Main_Data::game_party->GetActorPositionInParty(actor.GetId()); - actor_index = (actor_index + 1) % Main_Data::game_party->GetActors().size(); - Scene::Push(std::make_shared((*Main_Data::game_party)[actor_index], equip_window->GetIndex()), true); + if (actor_index != -1) { + actor_index = (actor_index + 1) % Main_Data::game_party->GetActors().size(); + Scene::Push(std::make_shared((*Main_Data::game_party)[actor_index], equip_window->GetIndex()), true); + } } else if (Main_Data::game_party->GetActors().size() > 1 && Input::IsTriggered(Input::LEFT)) { Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Cursor)); int actor_index = Main_Data::game_party->GetActorPositionInParty(actor.GetId()); - actor_index = (actor_index + Main_Data::game_party->GetActors().size() - 1) % Main_Data::game_party->GetActors().size(); - Scene::Push(std::make_shared((*Main_Data::game_party)[actor_index], equip_window->GetIndex()), true); + if (actor_index != -1) { + actor_index = (actor_index + Main_Data::game_party->GetActors().size() - 1) % Main_Data::game_party->GetActors().size(); + Scene::Push(std::make_shared((*Main_Data::game_party)[actor_index], equip_window->GetIndex()), true); + } } } diff --git a/src/scene_skill.cpp b/src/scene_skill.cpp index 21e9bcb1fa..1066fcb19e 100644 --- a/src/scene_skill.cpp +++ b/src/scene_skill.cpp @@ -18,6 +18,7 @@ // Headers #include "scene_skill.h" #include "algo.h" +#include "game_actors.h" #include "game_map.h" #include "game_party.h" #include "game_player.h" @@ -28,8 +29,8 @@ #include "scene_teleport.h" #include "transition.h" -Scene_Skill::Scene_Skill(int actor_index, int skill_index) : - actor_index(actor_index), skill_index(skill_index) { +Scene_Skill::Scene_Skill(int actor_index, int skill_index, bool is_db_actor) : + actor_index(actor_index), skill_index(skill_index), is_db_actor(is_db_actor) { Scene::type = Scene::Skill; } @@ -41,9 +42,16 @@ void Scene_Skill::Start() { skillstatus_window.reset(new Window_SkillStatus(Player::menu_offset_x, Player::menu_offset_y + window_help_height, MENU_WIDTH, window_skillstatus_height)); skill_window.reset(new Window_Skill(Player::menu_offset_x, Player::menu_offset_y + window_help_height + window_skillstatus_height, MENU_WIDTH, MENU_HEIGHT - (window_help_height + window_skillstatus_height))); + Game_Actor* actor; + if (!is_db_actor) { + actor = Main_Data::game_party->GetActors()[actor_index]; + } + else { + actor = Main_Data::game_actors->GetActor(actor_index); + } // Assign actors and help to windows - skill_window->SetActor(Main_Data::game_party->GetActors()[actor_index]->GetId()); - skillstatus_window->SetActor(Main_Data::game_party->GetActors()[actor_index]->GetId()); + skill_window->SetActor(actor->GetId()); + skillstatus_window->SetActor(actor->GetId()); skill_window->SetIndex(skill_index); skill_window->SetHelpWindow(help_window.get()); } @@ -65,7 +73,13 @@ void Scene_Skill::vUpdate() { const lcf::rpg::Skill* skill = skill_window->GetSkill(); int skill_id = skill ? skill->ID : 0; - Game_Actor* actor = Main_Data::game_party->GetActors()[actor_index]; + Game_Actor* actor; + if (!is_db_actor) { + actor = Main_Data::game_party->GetActors()[actor_index]; + } + else { + actor = Main_Data::game_actors->GetActor(actor_index); + } if (skill && skill_window->CheckEnable(skill_id)) { if (skill->type == lcf::rpg::Skill::Type_switch) { @@ -74,6 +88,10 @@ void Scene_Skill::vUpdate() { Scene::PopUntil(Scene::Map); Game_Map::SetNeedRefresh(true); } else if (Algo::IsNormalOrSubskill(*skill)) { + int actor_target_index = actor_index; + if (is_db_actor) { + actor_index = 0; + } Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Decision)); Scene::Push(std::make_shared(skill_id, actor_index)); skill_index = skill_window->GetIndex(); diff --git a/src/scene_skill.h b/src/scene_skill.h index 8fc921eff9..81ce93ba5b 100644 --- a/src/scene_skill.h +++ b/src/scene_skill.h @@ -33,7 +33,7 @@ class Scene_Skill : public Scene { /** * Constructor. */ - Scene_Skill(int actor_index, int skill_index = 0); + Scene_Skill(int actor_index, int skill_index = 0, bool is_db_actor = false); void Start() override; void Continue(SceneType prev_scene) override; @@ -45,6 +45,8 @@ class Scene_Skill : public Scene { int actor_index; /** Skill to select at startup. */ int skill_index; + /** Given actor index refers to a database actor instead of a party member index. */ + bool is_db_actor; /** Displays available skills. */ std::unique_ptr skill_window; /** Displays information about the actor. */ diff --git a/src/scene_status.cpp b/src/scene_status.cpp index bc6d529da0..2bcfdac0dc 100644 --- a/src/scene_status.cpp +++ b/src/scene_status.cpp @@ -19,13 +19,14 @@ #include #include #include "scene_status.h" +#include "game_actors.h" #include "game_party.h" #include "game_system.h" #include "input.h" #include -Scene_Status::Scene_Status(int actor_index) : - actor_index(actor_index) { +Scene_Status::Scene_Status(int actor_index, bool is_db_actor) : + actor_index(actor_index), is_db_actor(is_db_actor) { type = Scene::Status; } @@ -41,8 +42,14 @@ void Scene_Status::Start() { int window_equip_width = 196; int window_equip_height = 96; - int actor = Main_Data::game_party->GetActors()[actor_index]->GetId(); + int actor; + if (!is_db_actor) { + actor = Main_Data::game_party->GetActors()[actor_index]->GetId(); + } + else { + actor = Main_Data::game_actors->GetActor(actor_index)->GetId(); + } actorinfo_window.reset(new Window_ActorInfo(Player::menu_offset_x, Player::menu_offset_y, window_actor_info_width, window_actor_info_height, actor)); gold_window.reset(new Window_Gold(Player::menu_offset_x, Player::menu_offset_y + window_actor_info_height, window_gold_width, window_gold_height)); actorstatus_window.reset(new Window_ActorStatus(Player::menu_offset_x + window_actor_info_width, Player::menu_offset_y, window_actor_status_width, window_actor_status_height, actor)); @@ -63,11 +70,11 @@ void Scene_Status::vUpdate() { if (Input::IsTriggered(Input::CANCEL)) { Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Cancel)); Scene::Pop(); - } else if (Main_Data::game_party->GetActors().size() > 1 && Input::IsTriggered(Input::RIGHT)) { + } else if (!is_db_actor && Main_Data::game_party->GetActors().size() > 1 && Input::IsTriggered(Input::RIGHT)) { Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Cursor)); actor_index = (actor_index + 1) % Main_Data::game_party->GetActors().size(); Scene::Push(std::make_shared(actor_index), true); - } else if (Main_Data::game_party->GetActors().size() > 1 && Input::IsTriggered(Input::LEFT)) { + } else if (!is_db_actor && Main_Data::game_party->GetActors().size() > 1 && Input::IsTriggered(Input::LEFT)) { Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Cursor)); actor_index = (actor_index + Main_Data::game_party->GetActors().size() - 1) % Main_Data::game_party->GetActors().size(); Scene::Push(std::make_shared(actor_index), true); diff --git a/src/scene_status.h b/src/scene_status.h index 4db7ce8a6e..2f9260d4b6 100644 --- a/src/scene_status.h +++ b/src/scene_status.h @@ -37,13 +37,15 @@ class Scene_Status : public Scene { * * @param actor_index party index of the actor. */ - Scene_Status(int actor_index); + Scene_Status(int actor_index, bool is_db_actor = false); void Start() override; void vUpdate() override; private: int actor_index; + /** Given actor index refers to a database actor instead of a party member index. */ + bool is_db_actor; std::unique_ptr actorinfo_window; std::unique_ptr actorstatus_window;