diff --git a/data/console/commands.yaml b/data/console/commands.yaml index c2900a5..dc8126b 100644 --- a/data/console/commands.yaml +++ b/data/console/commands.yaml @@ -14,9 +14,12 @@ # dynamic_completions - (optional) Completions generated at runtime (default: false) # completions - (optional) Static TAB completion tree # debug_extras - (optional) Overrides applied in debug builds +# scope - (optional) Visibility scope: global, game, editor, debug (default: global) +# Can be a string or a list. Categories can set a default scope for all commands. categories: - name: VIDEO + scope: game commands: - keyword: SS handler: cmd_ss @@ -86,6 +89,7 @@ categories: dynamic_completions: true - name: AUDIO + scope: game commands: - keyword: AUDIO handler: cmd_audio @@ -109,6 +113,7 @@ categories: SOUND: [ON, OFF, VOL] - name: GAME + scope: game commands: - keyword: PLAYER handler: cmd_player @@ -137,6 +142,7 @@ categories: description: Quit application usage: EXIT instant: true + scope: global - keyword: QUIT handler: cmd_quit @@ -144,8 +150,10 @@ categories: usage: QUIT instant: true help_hidden: true + scope: global - name: INFO + scope: global commands: - keyword: SHOW handler: cmd_show @@ -182,6 +190,7 @@ categories: - name: DEBUG debug_only: true + scope: debug commands: - keyword: DEBUG handler: cmd_debug @@ -202,6 +211,7 @@ categories: handler: cmd_room description: "Change to room number (GAME only)" usage: "ROOM <1-60>|NEXT|PREV|LEFT|RIGHT|UP|DOWN" + scope: [debug, editor] completions: ROOM: [NEXT, PREV, LEFT, RIGHT, UP, DOWN, NEW, DELETE] ROOM NEW: [LEFT, RIGHT, UP, DOWN] @@ -216,30 +226,35 @@ categories: - keyword: EDIT handler: cmd_edit description: "Map editor mode (GAME only)" - usage: "EDIT [ON|OFF|REVERT|SHOW|HIDE|MAPBG] [...]" + usage: "EDIT [ON|OFF|REVERT|SHOW|HIDE|MAPBG|MAPCONN] [...]" + scope: [debug, editor] dynamic_completions: true completions: EDIT: [ON, OFF, REVERT, SHOW, HIDE, MAPBG, MAPCONN] EDIT SHOW: [INFO, GRID] EDIT HIDE: [INFO, GRID] + - name: EDITOR + debug_only: true + scope: editor + commands: - keyword: ENEMY handler: cmd_enemy - description: "Add, delete or duplicate enemy (editor)" + description: "Add, delete or duplicate enemy" usage: "ENEMY " completions: ENEMY: [ADD, DELETE, DUPLICATE] - keyword: ITEM handler: cmd_item - description: "Add, delete or duplicate item (editor)" + description: "Add, delete or duplicate item" usage: "ITEM " completions: ITEM: [ADD, DELETE, DUPLICATE] - keyword: SET handler: cmd_set - description: "Set property (enemy or room, editor mode)" + description: "Set property (enemy, item or room)" usage: "SET " dynamic_completions: true completions: @@ -249,6 +264,7 @@ categories: SET CONVEYOR: [LEFT, NONE, RIGHT] - name: CHEATS + scope: [game, editor] commands: - keyword: CHEAT handler: cmd_cheat diff --git a/source/game/editor/map_editor.cpp b/source/game/editor/map_editor.cpp index 9e6d0ef..489b2ff 100644 --- a/source/game/editor/map_editor.cpp +++ b/source/game/editor/map_editor.cpp @@ -204,6 +204,9 @@ void MapEditor::enter(std::shared_ptr room, std::shared_ptr player RenderInfo::get()->toggle(); } + // Activar scope de la consola para el editor + Console::get()->setScope("editor"); + // Resetear enemigos a su posición inicial (pueden haberse movido durante el gameplay) room_->resetEnemyPositions(room_data_.enemies); @@ -237,9 +240,10 @@ void MapEditor::exit() { } } - // Restaurar prompt de la consola y limpiar estado + // Restaurar prompt y scope de la consola selected_enemy_ = -1; Console::get()->setPrompt("> "); + Console::get()->setScope(""); drag_ = {}; statusbar_.reset(); room_.reset(); diff --git a/source/game/scenes/game.cpp b/source/game/scenes/game.cpp index f77c1d8..573c45e 100644 --- a/source/game/scenes/game.cpp +++ b/source/game/scenes/game.cpp @@ -50,6 +50,20 @@ Game::Game(Mode mode) current_room_(Defaults::Game::Room::INITIAL), spawn_data_(Player::SpawnData(Defaults::Game::Player::SPAWN_X, Defaults::Game::Player::SPAWN_Y, 0, 0, 0, Player::State::ON_GROUND, Defaults::Game::Player::SPAWN_FLIP)) { #endif + +#ifdef _DEBUG + // Validar que la room de debug existe; si no, fallback a la default + if (Resource::List::get()->get(current_room_).empty()) { + SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Debug room %s not found, using default", current_room_.c_str()); + current_room_ = Defaults::Game::Room::INITIAL; + spawn_data_ = Player::SpawnData(Defaults::Game::Player::SPAWN_X, Defaults::Game::Player::SPAWN_Y, 0, 0, 0, Player::State::ON_GROUND, Defaults::Game::Player::SPAWN_FLIP); + auto ss = Debug::get()->getSpawnSettings(); + ss.room = current_room_; + Debug::get()->setSpawnSettings(ss); + Debug::get()->saveToFile(); + } +#endif + // Crea objetos e inicializa variables ItemTracker::init(); demoInit(); diff --git a/source/game/ui/console.cpp b/source/game/ui/console.cpp index 2712cf3..12e8784 100644 --- a/source/game/ui/console.cpp +++ b/source/game/ui/console.cpp @@ -444,3 +444,7 @@ auto Console::getVisibleHeight() -> int { if (status_ == Status::HIDDEN) { return 0; } return static_cast(y_ + height_); } + +// Scope de comandos +void Console::setScope(const std::string& scope) { registry_.setScope(scope); } +auto Console::getScope() const -> std::string { return registry_.getScope(); } diff --git a/source/game/ui/console.hpp b/source/game/ui/console.hpp index 234b8fa..e9415c0 100644 --- a/source/game/ui/console.hpp +++ b/source/game/ui/console.hpp @@ -35,6 +35,10 @@ class Console { // Prompt configurable (por defecto "> ") void setPrompt(const std::string& prompt) { prompt_ = prompt; } + // Scope de comandos (filtra help y tab completion) + void setScope(const std::string& scope); + [[nodiscard]] auto getScope() const -> std::string; + // Callback llamado al abrir (true) o cerrar (false) la consola std::function on_toggle; diff --git a/source/game/ui/console_commands.cpp b/source/game/ui/console_commands.cpp index 0776d1e..3d8ce51 100644 --- a/source/game/ui/console_commands.cpp +++ b/source/game/ui/console_commands.cpp @@ -1091,6 +1091,17 @@ void CommandRegistry::load(const std::string& yaml_path) { const std::string category = cat_node["name"].get_value(); const bool cat_debug_only = cat_node.contains("debug_only") && cat_node["debug_only"].get_value(); + // Scopes por defecto de la categoría + std::vector cat_scopes; + if (cat_node.contains("scope")) { + const auto& scope_node = cat_node["scope"]; + if (scope_node.is_sequence()) { + for (const auto& s : scope_node) { cat_scopes.push_back(s.get_value()); } + } else { + cat_scopes.push_back(scope_node.get_value()); + } + } + if (!cat_node.contains("commands")) { continue; } for (const auto& cmd_node : cat_node["commands"]) { @@ -1106,6 +1117,20 @@ void CommandRegistry::load(const std::string& yaml_path) { def.help_hidden = cmd_node.contains("help_hidden") && cmd_node["help_hidden"].get_value(); def.dynamic_completions = cmd_node.contains("dynamic_completions") && cmd_node["dynamic_completions"].get_value(); + // Scopes: del comando, o hereda de la categoría, o "global" por defecto + if (cmd_node.contains("scope")) { + const auto& scope_node = cmd_node["scope"]; + if (scope_node.is_sequence()) { + for (const auto& s : scope_node) { def.scopes.push_back(s.get_value()); } + } else { + def.scopes.push_back(scope_node.get_value()); + } + } else if (!cat_scopes.empty()) { + def.scopes = cat_scopes; + } else { + def.scopes.push_back("global"); + } + // Completions estáticas if (cmd_node.contains("completions")) { auto completions_node = cmd_node["completions"]; @@ -1208,13 +1233,40 @@ auto CommandRegistry::generateTerminalHelp() const -> std::string { } auto CommandRegistry::generateConsoleHelp() const -> std::string { + if (!active_scope_.empty()) { + // Con scope activo: listar solo los comandos de ese scope + global + std::string cmds; + std::string shortcuts; + + for (const auto& cmd : commands_) { + if (cmd.help_hidden) { continue; } + if (!isCommandVisible(cmd)) { continue; } + + std::string kw_lower = cmd.keyword; + std::ranges::transform(kw_lower, kw_lower.begin(), ::tolower); + + if (!cmds.empty()) { cmds += ", "; } + cmds += kw_lower; + } + + std::string result = active_scope_ + " commands:\n" + cmds + "\n"; + + // Atajos de teclado del editor + if (active_scope_ == "editor") { + result += "\nkeys: 9=editor 8=grid e=eraser m=map"; + } + + result += "\n-- more info on the terminal"; + return result; + } + + // Sin scope: formato original (release + debug) std::string release_cmds; std::string debug_cmds; for (const auto& cmd : commands_) { if (cmd.help_hidden) { continue; } - // Convertir keyword a minúsculas para la lista std::string kw_lower = cmd.keyword; std::ranges::transform(kw_lower, kw_lower.begin(), ::tolower); @@ -1247,10 +1299,22 @@ auto CommandRegistry::getCompletions(const std::string& path) const -> std::vect return {}; } +// Comprueba si un comando es visible en el scope activo +auto CommandRegistry::isCommandVisible(const CommandDef& cmd) const -> bool { + if (cmd.hidden) { return false; } + if (active_scope_.empty()) { return true; } // Sin filtro, todo visible + + // Un comando es visible si pertenece al scope activo o al scope "global" + for (const auto& s : cmd.scopes) { + if (s == active_scope_ || s == "global") { return true; } + } + return false; +} + auto CommandRegistry::getVisibleKeywords() const -> std::vector { std::vector result; for (const auto& cmd : commands_) { - if (!cmd.hidden) { + if (isCommandVisible(cmd)) { result.push_back(cmd.keyword); } } diff --git a/source/game/ui/console_commands.hpp b/source/game/ui/console_commands.hpp index 6b23276..b775402 100644 --- a/source/game/ui/console_commands.hpp +++ b/source/game/ui/console_commands.hpp @@ -17,6 +17,7 @@ struct CommandDef { bool debug_only{false}; bool help_hidden{false}; bool dynamic_completions{false}; + std::vector scopes; // Ámbitos: "global", "game", "editor", "debug" std::unordered_map> completions; }; @@ -40,9 +41,11 @@ class CommandRegistry { [[nodiscard]] auto generateTerminalHelp() const -> std::string; [[nodiscard]] auto generateConsoleHelp() const -> std::string; + // Scope activo (filtra comandos visibles en help y tab completion) + void setScope(const std::string& scope) { active_scope_ = scope; } + [[nodiscard]] auto getScope() const -> const std::string& { return active_scope_; } + // TAB completion - // Devuelve las opciones de completado para un path dado (ej: "SHADER", "SHADER PRESET") - // Combina completions estáticas del YAML con dinámicas registradas en C++ [[nodiscard]] auto getCompletions(const std::string& path) const -> std::vector; [[nodiscard]] auto getVisibleKeywords() const -> std::vector; @@ -51,6 +54,8 @@ class CommandRegistry { std::unordered_map handlers_; std::unordered_map> completions_map_; std::unordered_map dynamic_providers_; + std::string active_scope_; // Scope activo ("" = sin filtro, muestra todo) void registerHandlers(); + [[nodiscard]] auto isCommandVisible(const CommandDef& cmd) const -> bool; };