diff --git a/data/console/commands.yaml b/data/console/commands.yaml index ae7a7ac..255f6df 100644 --- a/data/console/commands.yaml +++ b/data/console/commands.yaml @@ -228,13 +228,14 @@ categories: - keyword: SET handler: cmd_set - description: "Set enemy property (editor, select enemy first)" - usage: "SET " + description: "Set property (enemy or room, editor mode)" + usage: "SET " dynamic_completions: true completions: - SET: [ANIMATION, COLOR, VX, VY, FLIP, MIRROR] + SET: [ANIMATION, COLOR, VX, VY, FLIP, MIRROR, BGCOLOR, BORDER, ITEMCOLOR1, ITEMCOLOR2, CONVEYOR, TILESET, UP, DOWN, LEFT, RIGHT] SET FLIP: [ON, OFF] SET MIRROR: [ON, OFF] + SET CONVEYOR: [LEFT, NONE, RIGHT] - name: CHEATS commands: diff --git a/source/game/editor/map_editor.cpp b/source/game/editor/map_editor.cpp index 5a3f984..c9b497c 100644 --- a/source/game/editor/map_editor.cpp +++ b/source/game/editor/map_editor.cpp @@ -121,15 +121,21 @@ auto MapEditor::revert() -> std::string { } RoomSaver::saveYAML(file_path_, yaml_, room_data_); - // Resetear los sprites vivos a las posiciones originales + // Resetear enemigos a posiciones originales room_->resetEnemyPositions(room_data_.enemies); - // Resetear items (recargar posiciones) + // Resetear items (posiciones y colores) auto* item_mgr = room_->getItemManager(); for (int i = 0; i < item_mgr->getCount() && i < static_cast(room_data_.items.size()); ++i) { item_mgr->getItem(i)->setPosition(room_data_.items[i].x, room_data_.items[i].y); } + room_->setItemColors(room_data_.item_color1, room_data_.item_color2); + // Refrescar visuales de la habitación + room_->setBgColor(room_data_.bg_color); + Screen::get()->setBorderColor(stringToColor(room_data_.border_color)); + + selected_enemy_ = -1; return "Reverted to original"; } @@ -568,6 +574,18 @@ void MapEditor::updateStatusBarInfo() { if (e.flip) { sel_detail += " flip"; } if (e.mirror) { sel_detail += " mirror"; } } + // Info de la habitación (cuando no hay nada seleccionado) + else { + // Conexiones compactas + auto conn = [](const std::string& r) -> std::string { + if (r == "0" || r.empty()) { return "-"; } + return r.substr(0, r.find('.')); + }; + sel_info = "bg:" + room_data_.bg_color + " brd:" + room_data_.border_color; + sel_detail = "u:" + conn(room_data_.upper_room) + " d:" + conn(room_data_.lower_room) + + " l:" + conn(room_data_.left_room) + " r:" + conn(room_data_.right_room) + + " itm:" + room_data_.item_color1 + "/" + room_data_.item_color2; + } statusbar_->setSelectionInfo(sel_info); statusbar_->setSelectionDetail(sel_detail); @@ -576,7 +594,7 @@ void MapEditor::updateStatusBarInfo() { if (selected_enemy_ >= 0) { Console::get()->setPrompt("enemy " + std::to_string(selected_enemy_) + "> "); } else { - Console::get()->setPrompt("> "); + Console::get()->setPrompt("room> "); } } @@ -765,4 +783,83 @@ auto MapEditor::duplicateEnemy() -> std::string { return "Duplicated as enemy " + std::to_string(selected_enemy_); } +// Modifica una propiedad de la habitación +auto MapEditor::setRoomProperty(const std::string& property, const std::string& value) -> std::string { + if (!active_) { return "Editor not active"; } + + std::string val = toLower(value); + + if (property == "BGCOLOR") { + room_data_.bg_color = val; + room_->setBgColor(val); + autosave(); + return "bgcolor: " + val; + } + + if (property == "BORDER") { + room_data_.border_color = val; + Screen::get()->setBorderColor(stringToColor(val)); + autosave(); + return "border: " + val; + } + + if (property == "ITEMCOLOR1") { + room_data_.item_color1 = val; + room_->setItemColors(room_data_.item_color1, room_data_.item_color2); + autosave(); + return "itemcolor1: " + val; + } + + if (property == "ITEMCOLOR2") { + room_data_.item_color2 = val; + room_->setItemColors(room_data_.item_color1, room_data_.item_color2); + autosave(); + return "itemcolor2: " + val; + } + + if (property == "CONVEYOR") { + if (val == "left") { room_data_.conveyor_belt_direction = -1; } + else if (val == "right") { room_data_.conveyor_belt_direction = 1; } + else { room_data_.conveyor_belt_direction = 0; val = "none"; } + autosave(); + return "conveyor: " + val; + } + + if (property == "TILESET") { + std::string tileset = val; + if (tileset.find('.') == std::string::npos) { tileset += ".gif"; } + room_data_.tile_set_file = tileset; + autosave(); + return "tileset: " + tileset; + } + + // Conexiones: UP, DOWN, LEFT, RIGHT + if (property == "UP" || property == "DOWN" || property == "LEFT" || property == "RIGHT") { + std::string connection = "0"; + if (val != "0" && val != "null" && val != "none") { + // Convertir número a fichero: "6" → "06.yaml" + try { + int num = std::stoi(val); + char buf[16]; + std::snprintf(buf, sizeof(buf), "%02d.yaml", num); + connection = buf; + } catch (...) { + // Si no es número, asumir que es un nombre de fichero + connection = val; + if (connection.find('.') == std::string::npos) { connection += ".yaml"; } + } + } + + if (property == "UP") { room_data_.upper_room = connection; } + else if (property == "DOWN") { room_data_.lower_room = connection; } + else if (property == "LEFT") { room_data_.left_room = connection; } + else { room_data_.right_room = connection; } + + autosave(); + return toLower(property) + ": " + connection; + } + + return "Unknown property: " + property + " (use: bgcolor, border, itemcolor1, itemcolor2, conveyor, tileset, up, down, left, right)"; +} + #endif // _DEBUG diff --git a/source/game/editor/map_editor.hpp b/source/game/editor/map_editor.hpp index 46161aa..22af2ef 100644 --- a/source/game/editor/map_editor.hpp +++ b/source/game/editor/map_editor.hpp @@ -39,6 +39,9 @@ class MapEditor { auto duplicateEnemy() -> std::string; [[nodiscard]] auto hasSelectedEnemy() const -> bool; + // Comandos para propiedades de la habitación + auto setRoomProperty(const std::string& property, const std::string& value) -> std::string; + private: static MapEditor* instance_; // [SINGLETON] Objeto privado diff --git a/source/game/gameplay/room.cpp b/source/game/gameplay/room.cpp index a1fa827..7d990a2 100644 --- a/source/game/gameplay/room.cpp +++ b/source/game/gameplay/room.cpp @@ -133,6 +133,25 @@ void Room::updateEditorMode(float delta_time) { void Room::resetEnemyPositions(const std::vector& enemy_data) { enemy_manager_->resetPositions(enemy_data); } + +// Cambia color de fondo y redibuja el mapa (para editor) +void Room::setBgColor(const std::string& color) { + bg_color_ = color; + tilemap_renderer_->setBgColor(color); + tilemap_renderer_->redrawMap(collision_map_.get()); +} + +// Cambia colores de items en vivo (para editor) +void Room::setItemColors(const std::string& color1, const std::string& color2) { + item_color1_ = color1; + item_color2_ = color2; + Uint8 c1 = stringToColor(color1); + Uint8 c2 = stringToColor(color2); + auto* item_mgr = item_manager_.get(); + for (int i = 0; i < static_cast(item_mgr->getCount()); ++i) { + item_mgr->getItem(i)->setColors(c1, c2); + } +} #endif // Actualiza las variables y objetos de la habitación diff --git a/source/game/gameplay/room.hpp b/source/game/gameplay/room.hpp index 06531ac..d598a6a 100644 --- a/source/game/gameplay/room.hpp +++ b/source/game/gameplay/room.hpp @@ -74,6 +74,8 @@ class Room { void resetEnemyPositions(const std::vector& enemy_data); // Resetea enemigos a posiciones iniciales auto getEnemyManager() -> EnemyManager* { return enemy_manager_.get(); } // Acceso al gestor de enemigos (para editor) auto getItemManager() -> ItemManager* { return item_manager_.get(); } // Acceso al gestor de items (para editor) + void setBgColor(const std::string& color); // Cambia color de fondo y redibuja (para editor) + void setItemColors(const std::string& color1, const std::string& color2); // Cambia colores de items (para editor) #endif void update(float delta_time); // Actualiza las variables y objetos de la habitación auto getRoom(Border border) -> std::string; // Devuelve la cadena del fichero de la habitación contigua segun el borde diff --git a/source/game/gameplay/tilemap_renderer.hpp b/source/game/gameplay/tilemap_renderer.hpp index bfddd73..52b8070 100644 --- a/source/game/gameplay/tilemap_renderer.hpp +++ b/source/game/gameplay/tilemap_renderer.hpp @@ -69,6 +69,7 @@ class TilemapRenderer { * Llamado cuando se activa/desactiva el modo debug para actualizar la visualización */ void redrawMap(const CollisionMap* collision_map); + void setBgColor(const std::string& color) { bg_color_ = color; } #endif /** diff --git a/source/game/ui/console_commands.cpp b/source/game/ui/console_commands.cpp index 895b894..3afb794 100644 --- a/source/game/ui/console_commands.cpp +++ b/source/game/ui/console_commands.cpp @@ -705,12 +705,18 @@ static auto cmd_edit(const std::vector& args) -> std::string { return "usage: edit [on|off|revert]"; } -// SET — modifica propiedad del enemigo seleccionado en el editor +// SET — modifica propiedad del enemigo seleccionado o de la habitación static auto cmd_set(const std::vector& args) -> std::string { if (!MapEditor::get() || !MapEditor::get()->isActive()) { return "Editor not active"; } - if (!MapEditor::get()->hasSelectedEnemy()) { return "No enemy selected"; } - if (args.size() < 2) { return "usage: set "; } - return MapEditor::get()->setEnemyProperty(args[0], args[1]); + if (args.size() < 2) { return "usage: set "; } + + // Si hay enemigo seleccionado, aplicar a enemigo + if (MapEditor::get()->hasSelectedEnemy()) { + return MapEditor::get()->setEnemyProperty(args[0], args[1]); + } + + // Si no, aplicar a la habitación + return MapEditor::get()->setRoomProperty(args[0], args[1]); } // ENEMY [ADD|DELETE|DUPLICATE] @@ -959,12 +965,17 @@ void CommandRegistry::registerHandlers() { }; #ifdef _DEBUG - // SET COLOR: colores de la paleta (UPPERCASE, sin .yaml) - dynamic_providers_["SET COLOR"] = []() -> std::vector { + // Colores de la paleta (compartido por SET COLOR, BGCOLOR, BORDER, ITEMCOLOR1, ITEMCOLOR2) + auto color_provider = []() -> std::vector { return {"BLACK", "BRIGHT_BLACK", "BLUE", "BRIGHT_BLUE", "RED", "BRIGHT_RED", "MAGENTA", "BRIGHT_MAGENTA", "GREEN", "BRIGHT_GREEN", "CYAN", "BRIGHT_CYAN", "YELLOW", "BRIGHT_YELLOW", "WHITE", "BRIGHT_WHITE"}; }; + dynamic_providers_["SET COLOR"] = color_provider; + dynamic_providers_["SET BGCOLOR"] = color_provider; + dynamic_providers_["SET BORDER"] = color_provider; + dynamic_providers_["SET ITEMCOLOR1"] = color_provider; + dynamic_providers_["SET ITEMCOLOR2"] = color_provider; // SET ANIMATION: animaciones de enemigos (nombres sin extensión, UPPERCASE) dynamic_providers_["SET ANIMATION"] = []() -> std::vector { @@ -979,6 +990,20 @@ void CommandRegistry::registerHandlers() { } return result; }; + + // SET TILESET: tilesets disponibles (nombres sin extensión, UPPERCASE) + dynamic_providers_["SET TILESET"] = []() -> std::vector { + std::vector result; + auto list = Resource::List::get()->getListByType(Resource::List::Type::BITMAP); + for (const auto& path : list) { + if (path.find("tilesets") == std::string::npos) { continue; } + std::string name = getFileName(path); + auto dot = name.rfind('.'); + if (dot != std::string::npos) { name = name.substr(0, dot); } + result.push_back(toUpper(name)); + } + return result; + }; #endif }