From fc285869404dc1ba799ee817a473712ce94d1703 Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Thu, 2 Apr 2026 13:02:35 +0200 Subject: [PATCH] - faltava propietat mirror - al fer clic es tanca la consola --- data/console/commands.yaml | 12 +++- source/game/editor/map_editor.cpp | 108 +++++++++++++++++++++++++++- source/game/editor/map_editor.hpp | 5 +- source/game/scenes/game.cpp | 6 ++ source/game/ui/console_commands.cpp | 17 +++++ 5 files changed, 143 insertions(+), 5 deletions(-) diff --git a/data/console/commands.yaml b/data/console/commands.yaml index 8afd701..ae7a7ac 100644 --- a/data/console/commands.yaml +++ b/data/console/commands.yaml @@ -219,14 +219,22 @@ categories: completions: EDIT: [ON, OFF, REVERT] + - keyword: ENEMY + handler: cmd_enemy + description: "Add, delete or duplicate enemy (editor)" + usage: "ENEMY " + completions: + ENEMY: [ADD, DELETE, DUPLICATE] + - keyword: SET handler: cmd_set description: "Set enemy property (editor, select enemy first)" - usage: "SET " + usage: "SET " dynamic_completions: true completions: - SET: [ANIMATION, COLOR, VX, VY, FLIP] + SET: [ANIMATION, COLOR, VX, VY, FLIP, MIRROR] SET FLIP: [ON, OFF] + SET MIRROR: [ON, OFF] - name: CHEATS commands: diff --git a/source/game/editor/map_editor.cpp b/source/game/editor/map_editor.cpp index 7e5a4e7..5a3f984 100644 --- a/source/game/editor/map_editor.cpp +++ b/source/game/editor/map_editor.cpp @@ -566,6 +566,7 @@ void MapEditor::updateStatusBarInfo() { sel_detail = e.color + " vx:" + std::to_string(static_cast(e.vx)) + " vy:" + std::to_string(static_cast(e.vy)); if (e.flip) { sel_detail += " flip"; } + if (e.mirror) { sel_detail += " mirror"; } } statusbar_->setSelectionInfo(sel_info); @@ -652,13 +653,116 @@ auto MapEditor::setEnemyProperty(const std::string& property, const std::string& if (property == "FLIP") { enemy.flip = (value == "ON" || value == "TRUE" || value == "1"); + if (enemy.flip) { enemy.mirror = false; } // Mutuamente excluyentes + + // Recrear el enemigo (flip/mirror se aplican en el constructor) + try { + auto* enemy_mgr = room_->getEnemyManager(); + enemy_mgr->getEnemy(selected_enemy_) = std::make_shared(enemy); + } catch (const std::exception& e) { + return std::string("Error: ") + e.what(); + } - room_->getEnemyManager()->getEnemy(selected_enemy_)->resetToInitialPosition(enemy); autosave(); return std::string("flip: ") + (enemy.flip ? "on" : "off"); } - return "Unknown property: " + property + " (use: animation, color, vx, vy, flip)"; + if (property == "MIRROR") { + enemy.mirror = (value == "ON" || value == "TRUE" || value == "1"); + if (enemy.mirror) { enemy.flip = false; } // Mutuamente excluyentes + + // Recrear el enemigo (flip/mirror se aplican en el constructor) + try { + auto* enemy_mgr = room_->getEnemyManager(); + enemy_mgr->getEnemy(selected_enemy_) = std::make_shared(enemy); + } catch (const std::exception& e) { + return std::string("Error: ") + e.what(); + } + + autosave(); + return std::string("mirror: ") + (enemy.mirror ? "on" : "off"); + } + + return "Unknown property: " + property + " (use: animation, color, vx, vy, flip, mirror)"; +} + +// Crea un nuevo enemigo con valores por defecto, centrado en la habitación +auto MapEditor::addEnemy() -> std::string { + if (!active_) { return "Editor not active"; } + + constexpr float CENTER_X = PlayArea::CENTER_X; + constexpr float CENTER_Y = PlayArea::CENTER_Y; + constexpr float ROUTE_HALF = 2.0F * Tile::SIZE; // 2 tiles a cada lado (5 tiles total con el centro) + + Enemy::Data new_enemy; + new_enemy.animation_path = "spider.yaml"; + new_enemy.x = CENTER_X; + new_enemy.y = CENTER_Y; + new_enemy.vx = 24.0F; + new_enemy.vy = 0.0F; + new_enemy.x1 = static_cast(CENTER_X - ROUTE_HALF); + new_enemy.y1 = static_cast(CENTER_Y); + new_enemy.x2 = static_cast(CENTER_X + ROUTE_HALF); + new_enemy.y2 = static_cast(CENTER_Y); + new_enemy.color = "white"; + new_enemy.flip = true; + new_enemy.frame = -1; + + // Añadir a los datos y crear el sprite vivo + room_data_.enemies.push_back(new_enemy); + room_->getEnemyManager()->addEnemy(std::make_shared(new_enemy)); + + // Seleccionar el nuevo enemigo + selected_enemy_ = static_cast(room_data_.enemies.size()) - 1; + + autosave(); + return "Added enemy " + std::to_string(selected_enemy_); +} + +// Elimina el enemigo seleccionado +auto MapEditor::deleteEnemy() -> std::string { + if (!active_) { return "Editor not active"; } + if (!hasSelectedEnemy()) { return "No enemy selected"; } + + const int IDX = selected_enemy_; + + // Eliminar de los datos + room_data_.enemies.erase(room_data_.enemies.begin() + IDX); + + // Recrear todos los enemigos vivos (los índices cambian al borrar) + auto* enemy_mgr = room_->getEnemyManager(); + enemy_mgr->clear(); + for (const auto& enemy_data : room_data_.enemies) { + enemy_mgr->addEnemy(std::make_shared(enemy_data)); + } + + selected_enemy_ = -1; + autosave(); + return "Deleted enemy " + std::to_string(IDX); +} + +// Duplica el enemigo seleccionado (lo pone un tile a la derecha) +auto MapEditor::duplicateEnemy() -> std::string { + if (!active_) { return "Editor not active"; } + if (!hasSelectedEnemy()) { return "No enemy selected"; } + + // Copiar datos del enemigo seleccionado + Enemy::Data copy = room_data_.enemies[selected_enemy_]; + + // Desplazar un tile a la derecha + copy.x += Tile::SIZE; + copy.x1 += Tile::SIZE; + copy.x2 += Tile::SIZE; + + // Añadir y crear sprite vivo + room_data_.enemies.push_back(copy); + room_->getEnemyManager()->addEnemy(std::make_shared(copy)); + + // Seleccionar el nuevo enemigo + selected_enemy_ = static_cast(room_data_.enemies.size()) - 1; + + autosave(); + return "Duplicated as enemy " + std::to_string(selected_enemy_); } #endif // _DEBUG diff --git a/source/game/editor/map_editor.hpp b/source/game/editor/map_editor.hpp index 564c230..46161aa 100644 --- a/source/game/editor/map_editor.hpp +++ b/source/game/editor/map_editor.hpp @@ -32,8 +32,11 @@ class MapEditor { void handleEvent(const SDL_Event& event); auto revert() -> std::string; - // Comandos SET para modificar el enemigo seleccionado (llamados desde console_commands) + // Comandos para enemigos (llamados desde console_commands) auto setEnemyProperty(const std::string& property, const std::string& value) -> std::string; + auto addEnemy() -> std::string; + auto deleteEnemy() -> std::string; + auto duplicateEnemy() -> std::string; [[nodiscard]] auto hasSelectedEnemy() const -> bool; private: diff --git a/source/game/scenes/game.cpp b/source/game/scenes/game.cpp index 44b1720..680d1a1 100644 --- a/source/game/scenes/game.cpp +++ b/source/game/scenes/game.cpp @@ -175,6 +175,12 @@ void Game::handleEvents() { while (SDL_PollEvent(&event)) { GlobalEvents::handle(event); #ifdef _DEBUG + // En modo editor: click del ratón cierra la consola + if (Console::get()->isActive() && MapEditor::get()->isActive() && + event.type == SDL_EVENT_MOUSE_BUTTON_DOWN) { + Console::get()->toggle(); + } + if (!Console::get()->isActive()) { // Tecla 9: toggle editor (funciona tanto dentro como fuera del editor) if (event.type == SDL_EVENT_KEY_DOWN && event.key.key == SDLK_9 && static_cast(event.key.repeat) == 0) { diff --git a/source/game/ui/console_commands.cpp b/source/game/ui/console_commands.cpp index d700122..895b894 100644 --- a/source/game/ui/console_commands.cpp +++ b/source/game/ui/console_commands.cpp @@ -712,6 +712,22 @@ static auto cmd_set(const std::vector& args) -> std::string { if (args.size() < 2) { return "usage: set "; } return MapEditor::get()->setEnemyProperty(args[0], args[1]); } + +// ENEMY [ADD|DELETE|DUPLICATE] +static auto cmd_enemy(const std::vector& args) -> std::string { + if (!MapEditor::get() || !MapEditor::get()->isActive()) { return "Editor not active"; } + if (args.empty()) { return "usage: enemy "; } + if (args[0] == "ADD") { return MapEditor::get()->addEnemy(); } + if (args[0] == "DELETE") { + if (!MapEditor::get()->hasSelectedEnemy()) { return "No enemy selected"; } + return MapEditor::get()->deleteEnemy(); + } + if (args[0] == "DUPLICATE") { + if (!MapEditor::get()->hasSelectedEnemy()) { return "No enemy selected"; } + return MapEditor::get()->duplicateEnemy(); + } + return "usage: enemy "; +} #endif // SHOW [INFO|NOTIFICATION|CHEEVO] @@ -914,6 +930,7 @@ void CommandRegistry::registerHandlers() { handlers_["cmd_scene"] = cmd_scene; handlers_["cmd_edit"] = cmd_edit; handlers_["cmd_set"] = cmd_set; + handlers_["cmd_enemy"] = cmd_enemy; #endif // HELP se registra en load() como lambda que captura this