Compare commits

...

2 Commits

Author SHA1 Message Date
acaf434e5c reorganitzada la status bar del editor 2026-04-02 14:13:05 +02:00
5f25562d52 editar les propietats de la habitacio 2026-04-02 14:06:35 +02:00
9 changed files with 232 additions and 69 deletions

View File

@@ -228,13 +228,14 @@ categories:
- keyword: SET
handler: cmd_set
description: "Set enemy property (editor, select enemy first)"
usage: "SET <ANIMATION|COLOR|VX|VY|FLIP|MIRROR> <value>"
description: "Set property (enemy or room, editor mode)"
usage: "SET <property> <value>"
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:

View File

@@ -10,7 +10,7 @@
#include "core/resources/resource_cache.hpp" // Para Resource::Cache
#include "game/options.hpp" // Para Options::game
#include "utils/defines.hpp" // Para Tile::SIZE
#include "utils/utils.hpp" // Para stringToColor
#include "utils/utils.hpp" // Para stringToColor, toLower
// Constructor
EditorStatusBar::EditorStatusBar(const std::string& room_number, const std::string& room_name)
@@ -33,21 +33,15 @@ void EditorStatusBar::update([[maybe_unused]] float delta_time) {
fillTexture();
}
// Establece las coordenadas del ratón en tiles
void EditorStatusBar::setMouseTile(int tile_x, int tile_y) {
mouse_tile_x_ = tile_x;
mouse_tile_y_ = tile_y;
}
// Establece la información de la entidad seleccionada
void EditorStatusBar::setSelectionInfo(const std::string& info) {
selection_info_ = info;
}
// Establece el detalle adicional
void EditorStatusBar::setSelectionDetail(const std::string& detail) {
selection_detail_ = detail;
}
void EditorStatusBar::setLine2(const std::string& text) { line2_ = text; }
void EditorStatusBar::setLine3(const std::string& text) { line3_ = text; }
void EditorStatusBar::setLine4(const std::string& text) { line4_ = text; }
void EditorStatusBar::setLine5(const std::string& text) { line5_ = text; }
// Dibuja los elementos en la surface
void EditorStatusBar::fillTexture() {
@@ -59,28 +53,34 @@ void EditorStatusBar::fillTexture() {
auto text = Resource::Cache::get()->getText("8bithud");
const Uint8 LABEL_COLOR = stringToColor("bright_cyan");
const Uint8 VALUE_COLOR = stringToColor("white");
const Uint8 DETAIL_COLOR = stringToColor("bright_yellow");
// Línea 1: Número y nombre de la habitación
const std::string ROOM_TEXT = toLower(room_number_ + " " + room_name_);
text->writeColored(LEFT_X, LINE1_Y, ROOM_TEXT, LABEL_COLOR);
// Línea 1: Nombre de la habitación
text->writeColored(LEFT_X, LINE1_Y, toLower(room_number_ + " " + room_name_), LABEL_COLOR);
// Línea 2: Coordenadas del ratón en tiles
// Línea 2: Propiedades de room o info de enemigo
if (!line2_.empty()) {
text->writeColored(LEFT_X, LINE2_Y, toLower(line2_), DETAIL_COLOR);
}
// Línea 3: Conexiones+items o propiedades del enemigo
if (!line3_.empty()) {
text->writeColored(LEFT_X, LINE3_Y, toLower(line3_), VALUE_COLOR);
}
// Línea 4: Extra
if (!line4_.empty()) {
text->writeColored(LEFT_X, LINE4_Y, toLower(line4_), DETAIL_COLOR);
}
// Línea 5: Tile coords + drag info
const std::string TILE_X_STR = (mouse_tile_x_ < 10 ? "0" : "") + std::to_string(mouse_tile_x_);
const std::string TILE_Y_STR = (mouse_tile_y_ < 10 ? "0" : "") + std::to_string(mouse_tile_y_);
text->writeColored(LEFT_X, LINE2_Y, toLower("tile:"), LABEL_COLOR);
text->writeColored(LEFT_X + 30, LINE2_Y, TILE_X_STR + "," + TILE_Y_STR, VALUE_COLOR);
// Línea 2 (continuación): info de selección o indicador de modo editor
if (!selection_info_.empty()) {
text->writeColored(LEFT_X + 60, LINE2_Y, toLower(selection_info_), stringToColor("bright_yellow"));
} else {
text->writeColored(176, LINE2_Y, toLower("editor"), stringToColor("bright_green"));
}
// Línea 3: detalle de la selección (propiedades del enemigo)
if (!selection_detail_.empty()) {
text->writeColored(LEFT_X, LINE3_Y, toLower(selection_detail_), stringToColor("bright_white"));
std::string line5 = "tile:" + TILE_X_STR + "," + TILE_Y_STR;
if (!line5_.empty()) {
line5 += " " + line5_;
}
text->writeColored(LEFT_X, LINE5_Y, toLower(line5), stringToColor("bright_green"));
Screen::get()->setRendererSurface(previous_renderer);
}

View File

@@ -17,16 +17,21 @@ class EditorStatusBar {
void render();
void update(float delta_time);
void setMouseTile(int tile_x, int tile_y);
void setSelectionInfo(const std::string& info);
void setSelectionDetail(const std::string& detail);
void setLine2(const std::string& text);
void setLine3(const std::string& text);
void setLine4(const std::string& text);
void setLine5(const std::string& text);
private:
void fillTexture(); // Dibuja los elementos en la surface
// Constantes de posición (en pixels dentro de la surface de 256x48)
static constexpr int LINE1_Y = 4; // Nombre de la habitación
static constexpr int LINE2_Y = 14; // Coordenadas del ratón + selección
static constexpr int LINE3_Y = 24; // Línea extra disponible
// Font 8bithud lowercase = 6px alto → 5 líneas con 8px de separación
static constexpr int LINE1_Y = 2; // Nombre de la habitación
static constexpr int LINE2_Y = 10; // Propiedades de room / enemy info
static constexpr int LINE3_Y = 18; // Conexiones+items / enemy detail
static constexpr int LINE4_Y = 26; // Extra
static constexpr int LINE5_Y = 34; // Tile coords + drag info
static constexpr int LEFT_X = 4; // Margen izquierdo
// Objetos
@@ -34,12 +39,14 @@ class EditorStatusBar {
SDL_FRect surface_dest_{}; // Rectángulo destino en pantalla
// Variables
std::string room_number_; // Número de la habitación
std::string room_name_; // Nombre de la habitación
int mouse_tile_x_{0}; // Coordenada X del ratón en tiles
int mouse_tile_y_{0}; // Coordenada Y del ratón en tiles
std::string selection_info_; // Información de la entidad seleccionada (línea 2)
std::string selection_detail_; // Detalle adicional (línea 3)
std::string room_number_; // Número de la habitación
std::string room_name_; // Nombre de la habitación
int mouse_tile_x_{0}; // Coordenada X del ratón en tiles
int mouse_tile_y_{0}; // Coordenada Y del ratón en tiles
std::string line2_; // Contenido de la línea 2
std::string line3_; // Contenido de la línea 3
std::string line4_; // Contenido de la línea 4
std::string line5_; // Contenido de la línea 5
};
#endif // _DEBUG

View File

@@ -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<int>(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";
}
@@ -540,43 +546,63 @@ void MapEditor::updateStatusBarInfo() {
statusbar_->setMouseTile(mouse_tile_x_, mouse_tile_y_);
std::string sel_info;
std::string sel_detail;
std::string line2;
std::string line3;
std::string line5;
// Info de drag activo (prioridad)
// Helper para conexiones compactas
auto conn = [](const std::string& r) -> std::string {
if (r == "0" || r.empty()) { return "-"; }
return r.substr(0, r.find('.'));
};
// Info de drag activo (línea 5, junto a tile coords)
if (drag_.target != DragTarget::NONE && drag_.moved) {
switch (drag_.target) {
case DragTarget::PLAYER: sel_info = "player"; break;
case DragTarget::ENEMY_INITIAL: sel_info = "enemy " + std::to_string(drag_.index); break;
case DragTarget::ENEMY_BOUND1: sel_info = "e" + std::to_string(drag_.index) + " bound1"; break;
case DragTarget::ENEMY_BOUND2: sel_info = "e" + std::to_string(drag_.index) + " bound2"; break;
case DragTarget::ITEM: sel_info = "item " + std::to_string(drag_.index); break;
case DragTarget::PLAYER: line5 = "dragging: player"; break;
case DragTarget::ENEMY_INITIAL: line5 = "dragging: enemy " + std::to_string(drag_.index); break;
case DragTarget::ENEMY_BOUND1: line5 = "dragging: e" + std::to_string(drag_.index) + " bound1"; break;
case DragTarget::ENEMY_BOUND2: line5 = "dragging: e" + std::to_string(drag_.index) + " bound2"; break;
case DragTarget::ITEM: line5 = "dragging: item " + std::to_string(drag_.index); break;
case DragTarget::NONE: break;
}
}
// Info de enemigo seleccionado (persistente)
else if (selected_enemy_ >= 0 && selected_enemy_ < static_cast<int>(room_data_.enemies.size())) {
// Líneas 2-3 según selección
if (selected_enemy_ >= 0 && selected_enemy_ < static_cast<int>(room_data_.enemies.size())) {
// Enemigo seleccionado
const auto& e = room_data_.enemies[selected_enemy_];
// Extraer nombre corto de la animación (sin .yaml)
std::string anim = e.animation_path;
auto dot = anim.rfind('.');
if (dot != std::string::npos) { anim = anim.substr(0, dot); }
sel_info = "enemy " + std::to_string(selected_enemy_) + ": " + anim;
sel_detail = e.color + " vx:" + std::to_string(static_cast<int>(e.vx)) +
" vy:" + std::to_string(static_cast<int>(e.vy));
if (e.flip) { sel_detail += " flip"; }
if (e.mirror) { sel_detail += " mirror"; }
line2 = "enemy " + std::to_string(selected_enemy_) + ": " + anim + " " + e.color;
line3 = "vx:" + std::to_string(static_cast<int>(e.vx)) +
" vy:" + std::to_string(static_cast<int>(e.vy));
if (e.flip) { line3 += " flip"; }
if (e.mirror) { line3 += " mirror"; }
} else {
// Propiedades de la habitación
std::string conv = "none";
if (room_data_.conveyor_belt_direction < 0) { conv = "left"; }
else if (room_data_.conveyor_belt_direction > 0) { conv = "right"; }
line2 = "bg:" + room_data_.bg_color + " brd:" + room_data_.border_color + " conv:" + conv;
line3 = "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);
statusbar_->setLine2(line2);
statusbar_->setLine3(line3);
statusbar_->setLine4(""); // Disponible para uso futuro
statusbar_->setLine5(line5);
// Actualizar el prompt de la consola según la selección
if (selected_enemy_ >= 0) {
Console::get()->setPrompt("enemy " + std::to_string(selected_enemy_) + "> ");
} else {
Console::get()->setPrompt("> ");
Console::get()->setPrompt("room> ");
}
}
@@ -765,4 +791,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

View File

@@ -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

View File

@@ -133,6 +133,25 @@ void Room::updateEditorMode(float delta_time) {
void Room::resetEnemyPositions(const std::vector<Enemy::Data>& 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<int>(item_mgr->getCount()); ++i) {
item_mgr->getItem(i)->setColors(c1, c2);
}
}
#endif
// Actualiza las variables y objetos de la habitación

View File

@@ -74,6 +74,8 @@ class Room {
void resetEnemyPositions(const std::vector<Enemy::Data>& 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

View File

@@ -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
/**

View File

@@ -705,12 +705,18 @@ static auto cmd_edit(const std::vector<std::string>& args) -> std::string {
return "usage: edit [on|off|revert]";
}
// SET <property> <value> — modifica propiedad del enemigo seleccionado en el editor
// SET <property> <value> — modifica propiedad del enemigo seleccionado o de la habitación
static auto cmd_set(const std::vector<std::string>& 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 <animation|color|vx|vy|flip> <value>"; }
return MapEditor::get()->setEnemyProperty(args[0], args[1]);
if (args.size() < 2) { return "usage: set <property> <value>"; }
// 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<std::string> {
// Colores de la paleta (compartido por SET COLOR, BGCOLOR, BORDER, ITEMCOLOR1, ITEMCOLOR2)
auto color_provider = []() -> std::vector<std::string> {
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<std::string> {
@@ -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::string> {
std::vector<std::string> 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
}