linters
This commit is contained in:
@@ -14,13 +14,9 @@
|
||||
|
||||
// Constructor
|
||||
EditorStatusBar::EditorStatusBar(std::string room_number)
|
||||
: room_number_(std::move(room_number)) {
|
||||
const float SURFACE_WIDTH = Options::game.width;
|
||||
constexpr float SURFACE_HEIGHT = 24.0F; // 3 líneas de 8px
|
||||
|
||||
surface_ = std::make_shared<Surface>(SURFACE_WIDTH, SURFACE_HEIGHT);
|
||||
surface_dest_ = {.x = 0, .y = Options::game.height - SURFACE_HEIGHT, .w = SURFACE_WIDTH, .h = SURFACE_HEIGHT};
|
||||
}
|
||||
: surface_(std::make_shared<Surface>(Options::game.width, SURFACE_HEIGHT)),
|
||||
surface_dest_{.x = 0, .y = Options::game.height - SURFACE_HEIGHT, .w = Options::game.width, .h = SURFACE_HEIGHT},
|
||||
room_number_(std::move(room_number)) {}
|
||||
|
||||
// Pinta la barra de estado en pantalla
|
||||
void EditorStatusBar::render() {
|
||||
|
||||
@@ -27,10 +27,11 @@ class EditorStatusBar {
|
||||
|
||||
// Constantes de posición (en pixels dentro de la surface de 256x24)
|
||||
// Font 8bithud lowercase = 6px alto → 3 líneas con 8px de separación
|
||||
static constexpr int LINE1_Y = 1; // Room number + tile coords + extra
|
||||
static constexpr int LINE2_Y = 9; // Propiedades de room / enemy info
|
||||
static constexpr int LINE3_Y = 17; // Conexiones+items / enemy detail
|
||||
static constexpr int LEFT_X = 4; // Margen izquierdo
|
||||
static constexpr float SURFACE_HEIGHT = 24.0F; // 3 líneas de 8px
|
||||
static constexpr int LINE1_Y = 1; // Room number + tile coords + extra
|
||||
static constexpr int LINE2_Y = 9; // Propiedades de room / enemy info
|
||||
static constexpr int LINE3_Y = 17; // Conexiones+items / enemy detail
|
||||
static constexpr int LEFT_X = 4; // Margen izquierdo
|
||||
|
||||
// Objetos
|
||||
std::shared_ptr<Surface> surface_; // Surface donde dibujar la barra
|
||||
|
||||
@@ -92,7 +92,7 @@ void MapEditor::loadSettings() {
|
||||
}
|
||||
}
|
||||
} catch (...) {
|
||||
// Fichero corrupto o vacío, usar defaults
|
||||
// @INTENTIONAL: fichero corrupto o vacío → usar defaults
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,8 +231,8 @@ void MapEditor::enter(std::shared_ptr<Room> room, std::shared_ptr<Player> player
|
||||
painting_ = false; // Siempre dejar de pintar al cambiar de room
|
||||
|
||||
// Asegurar que collision_tile_map tiene el tamaño correcto
|
||||
if (room_data_.collision_tile_map.size() != static_cast<size_t>(Map::WIDTH * Map::HEIGHT)) {
|
||||
room_data_.collision_tile_map.resize(Map::WIDTH * Map::HEIGHT, 0);
|
||||
if (room_data_.collision_tile_map.size() != static_cast<size_t>(Map::WIDTH) * static_cast<size_t>(Map::HEIGHT)) {
|
||||
room_data_.collision_tile_map.resize(static_cast<size_t>(Map::WIDTH) * static_cast<size_t>(Map::HEIGHT), 0);
|
||||
}
|
||||
|
||||
active_ = true;
|
||||
@@ -361,30 +361,31 @@ void MapEditor::update(float delta_time) {
|
||||
}
|
||||
|
||||
// Renderiza el editor
|
||||
void MapEditor::renderCollisionOverlay() const {
|
||||
auto collision_surface = Resource::Cache::get()->getSurface("collision.gif");
|
||||
if (!collision_surface) { return; }
|
||||
const int TILE_W = Tile::SIZE;
|
||||
for (int y = 0; y < Map::HEIGHT; ++y) {
|
||||
for (int x = 0; x < Map::WIDTH; ++x) {
|
||||
int index = (y * Map::WIDTH) + x;
|
||||
if (index >= static_cast<int>(room_data_.collision_tile_map.size())) { continue; }
|
||||
int tile = room_data_.collision_tile_map[index];
|
||||
if (tile <= 0) { continue; } // 0 = vacío, no dibujar
|
||||
SDL_FRect clip = {
|
||||
.x = static_cast<float>(tile * TILE_W),
|
||||
.y = 0,
|
||||
.w = static_cast<float>(TILE_W),
|
||||
.h = static_cast<float>(TILE_W)};
|
||||
collision_surface->render(x * TILE_W, y * TILE_W, &clip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MapEditor::render() {
|
||||
// El tilemap ya ha sido renderizado por Game::renderPlaying() antes de llamar aquí
|
||||
|
||||
// Si estamos editando colisiones, superponer el mapa de colisiones
|
||||
if (editing_collision_) {
|
||||
auto collision_surface = Resource::Cache::get()->getSurface("collision.gif");
|
||||
if (collision_surface) {
|
||||
const int TILE_W = Tile::SIZE;
|
||||
for (int y = 0; y < Map::HEIGHT; ++y) {
|
||||
for (int x = 0; x < Map::WIDTH; ++x) {
|
||||
int index = (y * Map::WIDTH) + x;
|
||||
if (index >= static_cast<int>(room_data_.collision_tile_map.size())) { continue; }
|
||||
int tile = room_data_.collision_tile_map[index];
|
||||
if (tile <= 0) { continue; } // 0 = vacío, no dibujar
|
||||
SDL_FRect clip = {
|
||||
.x = static_cast<float>(tile * TILE_W),
|
||||
.y = 0,
|
||||
.w = static_cast<float>(TILE_W),
|
||||
.h = static_cast<float>(TILE_W)};
|
||||
collision_surface->render(x * TILE_W, y * TILE_W, &clip);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (editing_collision_) { renderCollisionOverlay(); }
|
||||
|
||||
// Grid (debajo de todo)
|
||||
if (settings_.grid) {
|
||||
@@ -526,7 +527,7 @@ void MapEditor::handleEvent(const SDL_Event& event) { // NOLINT(readability-fun
|
||||
// Deseleccionar entidades
|
||||
selection_.clear();
|
||||
|
||||
const std::string tileset_name = editing_collision_ ? "collision.gif" : room_->getTileSetFile();
|
||||
const std::string TILESET_NAME = editing_collision_ ? "collision.gif" : room_->getTileSetFile();
|
||||
int tile_index = (mouse_tile_y_ * 32) + mouse_tile_x_;
|
||||
int current = 0;
|
||||
if (editing_collision_) {
|
||||
@@ -539,10 +540,10 @@ void MapEditor::handleEvent(const SDL_Event& event) { // NOLINT(readability-fun
|
||||
: -1;
|
||||
}
|
||||
|
||||
tile_picker_.on_select = [this, tileset_name](int col, int row, int width, int height) {
|
||||
brush_ = buildPatternFromTileset(tileset_name, col, row, width, height);
|
||||
tile_picker_.on_select = [this, TILESET_NAME](int col, int row, int width, int height) {
|
||||
brush_ = buildPatternFromTileset(TILESET_NAME, col, row, width, height);
|
||||
};
|
||||
tile_picker_.open(tileset_name, current, 0, -1, -1, 0, 1, true);
|
||||
tile_picker_.open(TILESET_NAME, current, 0, -1, -1, 0, 1, true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -664,7 +665,7 @@ void MapEditor::handleMouseUp() {
|
||||
if (selection_.is(drag_.entity_type) && selection_.index == drag_.index) {
|
||||
selection_.clear(); // deselect
|
||||
} else {
|
||||
selection_ = {drag_.entity_type, drag_.index}; // select
|
||||
selection_ = {.type = drag_.entity_type, .index = drag_.index}; // select
|
||||
}
|
||||
} else {
|
||||
selection_.clear();
|
||||
@@ -696,7 +697,8 @@ void MapEditor::handleMouseUp() {
|
||||
drag_ = {};
|
||||
}
|
||||
|
||||
// Commit de un drag de entidad (initial, bound1, bound2) para cualquier EntityType
|
||||
// Commit de un drag de entidad (initial, bound1, bound2) para cualquier EntityType.
|
||||
// NOLINTNEXTLINE(readability-function-cognitive-complexity) -- switch sobre EntityType con una rama por tipo; refactor a visitor requiere cambio de diseño.
|
||||
auto MapEditor::commitEntityDrag() -> bool {
|
||||
const int IDX = drag_.index;
|
||||
const int SNAP_X = static_cast<int>(drag_.snap_x);
|
||||
@@ -710,14 +712,14 @@ auto MapEditor::commitEntityDrag() -> bool {
|
||||
room_data_.enemies[IDX].x = drag_.snap_x;
|
||||
room_data_.enemies[IDX].y = drag_.snap_y;
|
||||
room_->getEnemyManager()->getEnemy(IDX)->resetToInitialPosition(room_data_.enemies[IDX]);
|
||||
selection_ = {EntityType::ENEMY, IDX};
|
||||
selection_ = {.type = EntityType::ENEMY, .index = IDX};
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case EntityType::ITEM:
|
||||
if (IDX >= 0 && IDX < room_->getItemManager()->getCount()) {
|
||||
room_->getItemManager()->getItem(IDX)->setPosition(drag_.snap_x, drag_.snap_y);
|
||||
selection_ = {EntityType::ITEM, IDX};
|
||||
selection_ = {.type = EntityType::ITEM, .index = IDX};
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
@@ -733,7 +735,7 @@ auto MapEditor::commitEntityDrag() -> bool {
|
||||
}
|
||||
}
|
||||
room_->getPlatformManager()->getPlatform(IDX)->resetToInitialPosition(plat);
|
||||
selection_ = {EntityType::PLATFORM, IDX};
|
||||
selection_ = {.type = EntityType::PLATFORM, .index = IDX};
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
@@ -744,7 +746,7 @@ auto MapEditor::commitEntityDrag() -> bool {
|
||||
// sprite→data igual que con items.
|
||||
room_data_.keys[IDX].x = drag_.snap_x;
|
||||
room_data_.keys[IDX].y = drag_.snap_y;
|
||||
selection_ = {EntityType::KEY, IDX};
|
||||
selection_ = {.type = EntityType::KEY, .index = IDX};
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
@@ -756,7 +758,7 @@ auto MapEditor::commitEntityDrag() -> bool {
|
||||
room_data_.doors[IDX].x = drag_.snap_x;
|
||||
room_data_.doors[IDX].y = drag_.snap_y;
|
||||
room_->getDoorManager()->moveDoor(IDX, drag_.snap_x, drag_.snap_y);
|
||||
selection_ = {EntityType::DOOR, IDX};
|
||||
selection_ = {.type = EntityType::DOOR, .index = IDX};
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
@@ -772,7 +774,7 @@ auto MapEditor::commitEntityDrag() -> bool {
|
||||
room_data_.enemies[IDX].x1 = SNAP_X;
|
||||
room_data_.enemies[IDX].y1 = SNAP_Y;
|
||||
room_->getEnemyManager()->getEnemy(IDX)->resetToInitialPosition(room_data_.enemies[IDX]);
|
||||
selection_ = {EntityType::ENEMY, IDX};
|
||||
selection_ = {.type = EntityType::ENEMY, .index = IDX};
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
@@ -788,7 +790,7 @@ auto MapEditor::commitEntityDrag() -> bool {
|
||||
room_data_.enemies[IDX].x2 = SNAP_X;
|
||||
room_data_.enemies[IDX].y2 = SNAP_Y;
|
||||
room_->getEnemyManager()->getEnemy(IDX)->resetToInitialPosition(room_data_.enemies[IDX]);
|
||||
selection_ = {EntityType::ENEMY, IDX};
|
||||
selection_ = {.type = EntityType::ENEMY, .index = IDX};
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
@@ -803,7 +805,8 @@ auto MapEditor::commitEntityDrag() -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Mueve visualmente la entidad arrastrada a la posición snapped
|
||||
// Mueve visualmente la entidad arrastrada a la posición snapped.
|
||||
// NOLINTNEXTLINE(readability-function-cognitive-complexity) -- switch sobre EntityType con cases paralelos para cada tipo.
|
||||
void MapEditor::moveEntityVisual() {
|
||||
switch (drag_.target) {
|
||||
case DragTarget::ENTITY_INITIAL:
|
||||
@@ -857,8 +860,6 @@ void MapEditor::moveEntityVisual() {
|
||||
case DragTarget::ENTITY_BOUND1:
|
||||
case DragTarget::ENTITY_BOUND2:
|
||||
// Los boundaries se actualizan visualmente en renderEntityBoundaries() via drag_.snap
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -946,7 +947,8 @@ void MapEditor::renderSelectionHighlight() {
|
||||
game_surface->drawRectBorder(&border, DRAG_COLOR);
|
||||
}
|
||||
|
||||
// Estampa el patrón del brush en la posición indicada (anclaje top-left)
|
||||
// Estampa el patrón del brush en la posición indicada (anclaje top-left).
|
||||
// NOLINTNEXTLINE(readability-function-cognitive-complexity) -- nested loops + casos TRANSPARENT/ERASE/tile normal y ramas collision vs normal.
|
||||
void MapEditor::stampBrushAt(int tile_x, int tile_y) {
|
||||
if (brush_.isEmpty()) { return; }
|
||||
for (int dy = 0; dy < brush_.height; ++dy) {
|
||||
@@ -997,7 +999,7 @@ auto MapEditor::sampleBrush(int x1, int y1, int x2, int y2) const -> BrushPatter
|
||||
BrushPattern p;
|
||||
p.width = (x2 - x1) + 1;
|
||||
p.height = (y2 - y1) + 1;
|
||||
p.tiles.reserve(static_cast<size_t>(p.width * p.height));
|
||||
p.tiles.reserve(static_cast<size_t>(p.width) * static_cast<size_t>(p.height));
|
||||
const auto& src = editing_collision_ ? room_data_.collision_tile_map : room_data_.tile_map;
|
||||
for (int y = y1; y <= y2; ++y) {
|
||||
for (int x = x1; x <= x2; ++x) {
|
||||
@@ -1012,7 +1014,7 @@ auto MapEditor::sampleBrush(int x1, int y1, int x2, int y2) const -> BrushPatter
|
||||
|
||||
// Construye un BrushPattern leyendo tiles consecutivos de un tileset.
|
||||
// Usado por el TilePicker cuando se hace selección rectangular.
|
||||
auto MapEditor::buildPatternFromTileset(const std::string& tileset_name, int col, int row, int width, int height) const -> BrushPattern {
|
||||
auto MapEditor::buildPatternFromTileset(const std::string& tileset_name, int col, int row, int width, int height) -> BrushPattern {
|
||||
BrushPattern p;
|
||||
auto surface = Resource::Cache::get()->getSurface(tileset_name);
|
||||
if (!surface || width <= 0 || height <= 0) { return p; }
|
||||
@@ -1020,7 +1022,7 @@ auto MapEditor::buildPatternFromTileset(const std::string& tileset_name, int col
|
||||
if (cols <= 0) { return p; }
|
||||
p.width = width;
|
||||
p.height = height;
|
||||
p.tiles.reserve(static_cast<size_t>(width * height));
|
||||
p.tiles.reserve(static_cast<size_t>(width) * static_cast<size_t>(height));
|
||||
for (int dy = 0; dy < height; ++dy) {
|
||||
for (int dx = 0; dx < width; ++dx) {
|
||||
int tile = ((row + dy) * cols) + (col + dx);
|
||||
@@ -1036,8 +1038,8 @@ void MapEditor::renderBrushPreview() {
|
||||
auto game_surface = Screen::get()->getRendererSurface();
|
||||
if (!game_surface) { return; }
|
||||
|
||||
const std::string tileset_name = editing_collision_ ? std::string("collision.gif") : room_->getTileSetFile();
|
||||
auto tileset = Resource::Cache::get()->getSurface(tileset_name);
|
||||
const std::string TILESET_NAME = editing_collision_ ? std::string("collision.gif") : room_->getTileSetFile();
|
||||
auto tileset = Resource::Cache::get()->getSurface(TILESET_NAME);
|
||||
int cols = (tileset) ? (static_cast<int>(tileset->getWidth()) / Tile::SIZE) : 0;
|
||||
|
||||
constexpr auto TS = static_cast<float>(Tile::SIZE);
|
||||
@@ -1052,7 +1054,7 @@ void MapEditor::renderBrushPreview() {
|
||||
float dst_y = static_cast<float>(ty) * TS;
|
||||
if (value == BrushPattern::ERASE) {
|
||||
SDL_FRect erase_cell = {.x = dst_x, .y = dst_y, .w = TS, .h = TS};
|
||||
game_surface->fillRect(&erase_cell, static_cast<Uint8>(room_data_.bg_color));
|
||||
game_surface->fillRect(&erase_cell, room_data_.bg_color);
|
||||
} else if (tileset && cols > 0) {
|
||||
SDL_FRect src = {
|
||||
.x = static_cast<float>(value % cols) * TS,
|
||||
@@ -1077,7 +1079,7 @@ void MapEditor::renderBrushPreview() {
|
||||
}
|
||||
|
||||
// Renderiza el rectángulo del eyedropper en progreso (cyan brillante)
|
||||
void MapEditor::renderEyedropperRect() {
|
||||
void MapEditor::renderEyedropperRect() const {
|
||||
auto game_surface = Screen::get()->getRendererSurface();
|
||||
if (!game_surface) { return; }
|
||||
int x1 = std::clamp(eyedropper_.start_tile_x, 0, Map::WIDTH - 1);
|
||||
@@ -1152,7 +1154,7 @@ auto MapEditor::entityBoundaries(EntityType type, int index) const -> BoundaryDa
|
||||
switch (type) {
|
||||
case EntityType::ENEMY: {
|
||||
const auto& e = room_data_.enemies[index];
|
||||
return {e.x1, e.y1, e.x2, e.y2};
|
||||
return {.x1 = e.x1, .y1 = e.y1, .x2 = e.x2, .y2 = e.y2};
|
||||
}
|
||||
default:
|
||||
return {};
|
||||
@@ -1212,7 +1214,8 @@ auto MapEditor::entityLabel(EntityType type) -> const char* {
|
||||
}
|
||||
}
|
||||
|
||||
// Dibuja marcadores de boundaries y líneas de ruta para enemigos y plataformas
|
||||
// Dibuja marcadores de boundaries y líneas de ruta para enemigos y plataformas.
|
||||
// NOLINTNEXTLINE(readability-function-cognitive-complexity) -- switch sobre EntityType con ramas de enemigo patrullante vs plataforma con waypoints.
|
||||
void MapEditor::renderEntityBoundaries() {
|
||||
auto game_surface = Screen::get()->getRendererSurface();
|
||||
if (!game_surface) { return; }
|
||||
@@ -1395,7 +1398,7 @@ void MapEditor::updateStatusBarInfo() { // NOLINT(readability-function-cognitiv
|
||||
const auto& e = room_data_.enemies[selection_.index];
|
||||
std::string anim = e.animation_path;
|
||||
auto dot = anim.rfind('.');
|
||||
if (dot != std::string::npos) { anim = anim.substr(0, dot); }
|
||||
if (dot != std::string::npos) { anim.resize(dot); }
|
||||
|
||||
line2 = "enemy " + std::to_string(selection_.index) + ": " + anim;
|
||||
line3 = "vx:" + std::to_string(static_cast<int>(e.vx)) +
|
||||
@@ -1420,7 +1423,7 @@ void MapEditor::updateStatusBarInfo() { // NOLINT(readability-function-cognitiv
|
||||
if (selection_.index < static_cast<int>(room_data_.platforms.size())) {
|
||||
const auto& p = room_data_.platforms[selection_.index];
|
||||
std::string anim = p.animation_path;
|
||||
if (anim.size() > 5 && anim.substr(anim.size() - 5) == ".yaml") { anim = anim.substr(0, anim.size() - 5); }
|
||||
if (anim.ends_with(".yaml")) { anim.resize(anim.size() - 5); }
|
||||
line2 = "platform " + std::to_string(selection_.index) + ": " + anim;
|
||||
line3 = "speed:" + std::to_string(static_cast<int>(p.speed)) + " " + (p.loop == LoopMode::CIRCULAR ? "circular" : "pingpong");
|
||||
if (p.easing != "linear") { line3 += " " + p.easing; }
|
||||
@@ -1432,7 +1435,7 @@ void MapEditor::updateStatusBarInfo() { // NOLINT(readability-function-cognitiv
|
||||
const auto& k = room_data_.keys[selection_.index];
|
||||
std::string anim = k.animation_path;
|
||||
auto dot = anim.rfind('.');
|
||||
if (dot != std::string::npos) { anim = anim.substr(0, dot); }
|
||||
if (dot != std::string::npos) { anim.resize(dot); }
|
||||
line2 = "key " + std::to_string(selection_.index) + ": " + anim;
|
||||
line3 = "id: " + k.id;
|
||||
}
|
||||
@@ -1443,7 +1446,7 @@ void MapEditor::updateStatusBarInfo() { // NOLINT(readability-function-cognitiv
|
||||
const auto& d = room_data_.doors[selection_.index];
|
||||
std::string anim = d.animation_path;
|
||||
auto dot = anim.rfind('.');
|
||||
if (dot != std::string::npos) { anim = anim.substr(0, dot); }
|
||||
if (dot != std::string::npos) { anim.resize(dot); }
|
||||
line2 = "door " + std::to_string(selection_.index) + ": " + anim;
|
||||
line3 = "id: " + d.id;
|
||||
}
|
||||
@@ -1495,7 +1498,6 @@ auto MapEditor::getSetCompletions() const -> std::vector<std::string> {
|
||||
case EntityType::PLATFORM:
|
||||
return {"ANIMATION", "SPEED", "LOOP", "EASING"};
|
||||
case EntityType::KEY:
|
||||
return {"ID", "ANIMATION"};
|
||||
case EntityType::DOOR:
|
||||
return {"ID", "ANIMATION"};
|
||||
default:
|
||||
@@ -1534,7 +1536,7 @@ auto MapEditor::getAnimationCompletions() const -> std::vector<std::string> {
|
||||
if (path.extension() != ".yaml") { continue; }
|
||||
result.push_back(toUpper(path.stem().string()));
|
||||
}
|
||||
std::sort(result.begin(), result.end());
|
||||
std::ranges::sort(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1652,7 +1654,7 @@ auto MapEditor::addEnemy() -> std::string {
|
||||
|
||||
// Seleccionar el nuevo enemigo
|
||||
int new_index = static_cast<int>(room_data_.enemies.size()) - 1;
|
||||
selection_ = {EntityType::ENEMY, new_index};
|
||||
selection_ = {.type = EntityType::ENEMY, .index = new_index};
|
||||
|
||||
autosave();
|
||||
return "Added enemy " + std::to_string(new_index);
|
||||
@@ -1699,7 +1701,7 @@ auto MapEditor::duplicateEnemy() -> std::string {
|
||||
|
||||
// Seleccionar el nuevo enemigo
|
||||
int new_index = static_cast<int>(room_data_.enemies.size()) - 1;
|
||||
selection_ = {EntityType::ENEMY, new_index};
|
||||
selection_ = {.type = EntityType::ENEMY, .index = new_index};
|
||||
|
||||
autosave();
|
||||
return "Duplicated as enemy " + std::to_string(new_index);
|
||||
@@ -1907,7 +1909,7 @@ auto MapEditor::createNewRoom(const std::string& direction) -> std::string { //
|
||||
|
||||
// Comprobar que no hay ya una room en esa dirección
|
||||
if (!direction.empty()) {
|
||||
std::string* existing = nullptr;
|
||||
const std::string* existing = nullptr;
|
||||
if (direction == "UP") {
|
||||
existing = &room_data_.upper_room;
|
||||
} else if (direction == "DOWN") {
|
||||
@@ -1923,12 +1925,14 @@ auto MapEditor::createNewRoom(const std::string& direction) -> std::string { //
|
||||
}
|
||||
|
||||
// Encontrar el primer número libre (reutiliza huecos)
|
||||
auto& rooms = Resource::Cache::get()->getRooms();
|
||||
const auto& rooms = Resource::Cache::get()->getRooms();
|
||||
std::set<int> used;
|
||||
for (const auto& r : rooms) {
|
||||
try {
|
||||
used.insert(std::stoi(r.name.substr(0, r.name.find('.'))));
|
||||
} catch (...) {}
|
||||
} catch (...) {
|
||||
// @INTENTIONAL: nombre de room no es numérico → saltar
|
||||
}
|
||||
}
|
||||
int new_num = 1;
|
||||
while (used.contains(new_num)) { ++new_num; }
|
||||
@@ -1970,7 +1974,7 @@ auto MapEditor::createNewRoom(const std::string& direction) -> std::string { //
|
||||
|
||||
// Persistir vía la autoridad del formato (no más std::ofstream a pelo)
|
||||
auto save_result = RoomFormat::saveYAML(new_path, new_room);
|
||||
if (save_result.find("Error") == 0) { return save_result; }
|
||||
if (save_result.starts_with("Error")) { return save_result; }
|
||||
|
||||
// Registrar en Resource::List (mapa + assets.yaml) y cache
|
||||
Resource::List::get()->addAsset(new_path, Resource::List::Type::ROOM);
|
||||
@@ -2212,7 +2216,7 @@ auto MapEditor::addItem() -> std::string {
|
||||
room_->getItemManager()->addItem(std::make_shared<Item>(new_item));
|
||||
|
||||
int new_index = static_cast<int>(room_data_.items.size()) - 1;
|
||||
selection_ = {EntityType::ITEM, new_index};
|
||||
selection_ = {.type = EntityType::ITEM, .index = new_index};
|
||||
|
||||
autosave();
|
||||
return "Added item " + std::to_string(new_index);
|
||||
@@ -2250,7 +2254,7 @@ auto MapEditor::duplicateItem() -> std::string {
|
||||
room_->getItemManager()->addItem(std::make_shared<Item>(copy));
|
||||
|
||||
int new_index = static_cast<int>(room_data_.items.size()) - 1;
|
||||
selection_ = {EntityType::ITEM, new_index};
|
||||
selection_ = {.type = EntityType::ITEM, .index = new_index};
|
||||
|
||||
autosave();
|
||||
return "Duplicated as item " + std::to_string(new_index);
|
||||
@@ -2328,14 +2332,14 @@ auto MapEditor::addPlatform() -> std::string {
|
||||
constexpr float CENTER_Y = PlayArea::CENTER_Y;
|
||||
constexpr float ROUTE_HALF = 2.0F * Tile::SIZE;
|
||||
new_platform.path = {
|
||||
{CENTER_X - ROUTE_HALF, CENTER_Y, 0.0F},
|
||||
{CENTER_X + ROUTE_HALF, CENTER_Y, 0.0F}};
|
||||
{.x = CENTER_X - ROUTE_HALF, .y = CENTER_Y, .wait = 0.0F},
|
||||
{.x = CENTER_X + ROUTE_HALF, .y = CENTER_Y, .wait = 0.0F}};
|
||||
|
||||
room_data_.platforms.push_back(new_platform);
|
||||
room_->getPlatformManager()->addPlatform(std::make_shared<MovingPlatform>(new_platform));
|
||||
|
||||
int new_index = static_cast<int>(room_data_.platforms.size()) - 1;
|
||||
selection_ = {EntityType::PLATFORM, new_index};
|
||||
selection_ = {.type = EntityType::PLATFORM, .index = new_index};
|
||||
|
||||
autosave();
|
||||
return "Added platform " + std::to_string(new_index);
|
||||
@@ -2375,7 +2379,7 @@ auto MapEditor::duplicatePlatform() -> std::string {
|
||||
room_->getPlatformManager()->addPlatform(std::make_shared<MovingPlatform>(copy));
|
||||
|
||||
int new_index = static_cast<int>(room_data_.platforms.size()) - 1;
|
||||
selection_ = {EntityType::PLATFORM, new_index};
|
||||
selection_ = {.type = EntityType::PLATFORM, .index = new_index};
|
||||
|
||||
autosave();
|
||||
return "Duplicated as platform " + std::to_string(new_index);
|
||||
@@ -2441,7 +2445,7 @@ auto MapEditor::addKey() -> std::string {
|
||||
}
|
||||
|
||||
int new_index = static_cast<int>(room_data_.keys.size()) - 1;
|
||||
selection_ = {EntityType::KEY, new_index};
|
||||
selection_ = {.type = EntityType::KEY, .index = new_index};
|
||||
|
||||
autosave();
|
||||
return "Added key " + std::to_string(new_index);
|
||||
@@ -2484,7 +2488,7 @@ auto MapEditor::duplicateKey() -> std::string {
|
||||
}
|
||||
|
||||
int new_index = static_cast<int>(room_data_.keys.size()) - 1;
|
||||
selection_ = {EntityType::KEY, new_index};
|
||||
selection_ = {.type = EntityType::KEY, .index = new_index};
|
||||
|
||||
autosave();
|
||||
return "Duplicated as key " + std::to_string(new_index);
|
||||
@@ -2568,7 +2572,7 @@ auto MapEditor::addDoor() -> std::string {
|
||||
}
|
||||
|
||||
int new_index = static_cast<int>(room_data_.doors.size()) - 1;
|
||||
selection_ = {EntityType::DOOR, new_index};
|
||||
selection_ = {.type = EntityType::DOOR, .index = new_index};
|
||||
|
||||
autosave();
|
||||
return "Added door " + std::to_string(new_index);
|
||||
@@ -2608,7 +2612,7 @@ auto MapEditor::duplicateDoor() -> std::string {
|
||||
}
|
||||
|
||||
int new_index = static_cast<int>(room_data_.doors.size()) - 1;
|
||||
selection_ = {EntityType::DOOR, new_index};
|
||||
selection_ = {.type = EntityType::DOOR, .index = new_index};
|
||||
|
||||
autosave();
|
||||
return "Duplicated as door " + std::to_string(new_index);
|
||||
@@ -2629,7 +2633,7 @@ static auto pickGridColor(Uint8 bg, const std::shared_ptr<Surface>& surface) ->
|
||||
}
|
||||
|
||||
// Dibuja la cuadrícula de tiles (líneas de puntos, 1 pixel sí / 1 no)
|
||||
void MapEditor::renderGrid() const {
|
||||
void MapEditor::renderGrid() {
|
||||
auto game_surface = Screen::get()->getRendererSurface();
|
||||
if (!game_surface) { return; }
|
||||
|
||||
|
||||
@@ -4,9 +4,10 @@
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <memory> // Para shared_ptr, unique_ptr
|
||||
#include <string> // Para string
|
||||
#include <vector> // Para vector
|
||||
#include <cstdint> // Para uint8_t
|
||||
#include <memory> // Para shared_ptr, unique_ptr
|
||||
#include <string> // Para string
|
||||
#include <vector> // Para vector
|
||||
|
||||
#include "game/editor/mini_map.hpp" // Para MiniMap
|
||||
#include "game/editor/tile_picker.hpp" // Para TilePicker
|
||||
@@ -23,7 +24,7 @@
|
||||
class EditorStatusBar;
|
||||
|
||||
// Tipo de entidad editable en el editor
|
||||
enum class EntityType { NONE,
|
||||
enum class EntityType : std::uint8_t { NONE,
|
||||
ENEMY,
|
||||
ITEM,
|
||||
PLATFORM,
|
||||
@@ -106,7 +107,7 @@ class MapEditor {
|
||||
auto deleteRoom() -> std::string;
|
||||
|
||||
// Opciones del editor (llamados desde console_commands / teclas)
|
||||
auto showInfo(bool show) -> std::string;
|
||||
static auto showInfo(bool show) -> std::string;
|
||||
auto showGrid(bool show) -> std::string;
|
||||
auto setEditingCollision(bool collision) -> std::string;
|
||||
[[nodiscard]] auto isGridEnabled() const -> bool { return settings_.grid; }
|
||||
@@ -164,7 +165,7 @@ class MapEditor {
|
||||
void saveSettings() const;
|
||||
|
||||
// Tipos para drag & drop
|
||||
enum class DragTarget { NONE,
|
||||
enum class DragTarget : std::uint8_t { NONE,
|
||||
PLAYER,
|
||||
ENTITY_INITIAL,
|
||||
ENTITY_BOUND1,
|
||||
@@ -183,18 +184,19 @@ class MapEditor {
|
||||
|
||||
// Métodos internos
|
||||
void updateMousePosition();
|
||||
void renderCollisionOverlay() const;
|
||||
void renderEntityBoundaries();
|
||||
static void renderBoundaryMarker(float x, float y, Uint8 color);
|
||||
void renderSelectionHighlight();
|
||||
void renderBrushPreview();
|
||||
void renderEyedropperRect();
|
||||
void renderGrid() const;
|
||||
void renderEyedropperRect() const;
|
||||
static void renderGrid();
|
||||
void handleMouseDown(float game_x, float game_y);
|
||||
void handleMouseUp();
|
||||
void stampBrushAt(int tile_x, int tile_y);
|
||||
void commitEyedropper();
|
||||
[[nodiscard]] auto sampleBrush(int x1, int y1, int x2, int y2) const -> BrushPattern;
|
||||
[[nodiscard]] auto buildPatternFromTileset(const std::string& tileset_name, int col, int row, int width, int height) const -> BrushPattern;
|
||||
[[nodiscard]] static auto buildPatternFromTileset(const std::string& tileset_name, int col, int row, int width, int height) -> BrushPattern;
|
||||
|
||||
// Reconstruye todas las puertas vivas desde room_data_, limpiando primero
|
||||
// los WALLs antiguos del CollisionMap. Lo usa setDoorProperty cuando un
|
||||
@@ -213,12 +215,12 @@ class MapEditor {
|
||||
struct BoundaryData {
|
||||
int x1, y1, x2, y2;
|
||||
};
|
||||
auto entityCount(EntityType type) const -> int;
|
||||
[[nodiscard]] auto entityCount(EntityType type) const -> int;
|
||||
auto entityRect(EntityType type, int index) -> SDL_FRect;
|
||||
static auto entityHasBoundaries(EntityType type) -> bool;
|
||||
auto entityBoundaries(EntityType type, int index) const -> BoundaryData;
|
||||
auto entityPosition(EntityType type, int index) const -> std::pair<float, float>;
|
||||
auto entityDataCount(EntityType type) const -> int;
|
||||
[[nodiscard]] auto entityBoundaries(EntityType type, int index) const -> BoundaryData;
|
||||
[[nodiscard]] auto entityPosition(EntityType type, int index) const -> std::pair<float, float>;
|
||||
[[nodiscard]] auto entityDataCount(EntityType type) const -> int;
|
||||
static auto entityLabel(EntityType type) -> const char*;
|
||||
|
||||
// Estado del editor
|
||||
|
||||
@@ -85,7 +85,7 @@ auto MiniMap::getOrBuildTileColorTable(const std::string& tileset_name) -> const
|
||||
|
||||
// Posiciona las rooms en un grid usando BFS desde las conexiones
|
||||
void MiniMap::layoutRooms() {
|
||||
auto& rooms = Resource::Cache::get()->getRooms();
|
||||
const auto& rooms = Resource::Cache::get()->getRooms();
|
||||
if (rooms.empty()) { return; }
|
||||
|
||||
// Mapa de nombre → Room::Data
|
||||
|
||||
@@ -166,8 +166,8 @@ void TilePicker::render() {
|
||||
int cells_h = row_max - row_min + 1;
|
||||
float rx = tileset_screen_x + static_cast<float>(col_min * out_cell);
|
||||
float ry = tileset_screen_y + static_cast<float>(row_min * out_cell);
|
||||
float rw = static_cast<float>((cells_w * out_cell) - spacing_out_);
|
||||
float rh = static_cast<float>((cells_h * out_cell) - spacing_out_);
|
||||
auto rw = static_cast<float>((cells_w * out_cell) - spacing_out_);
|
||||
auto rh = static_cast<float>((cells_h * out_cell) - spacing_out_);
|
||||
if (ry + rh > 0 && ry < static_cast<float>(visible_height_)) {
|
||||
SDL_FRect rect_box = {.x = rx, .y = ry, .w = rw, .h = rh};
|
||||
game_surface->drawRectBorder(&rect_box, 15);
|
||||
@@ -198,6 +198,27 @@ void TilePicker::render() {
|
||||
}
|
||||
}
|
||||
|
||||
// Invoca el callback con el rect formado por rect_start_tile_ y el hover actual, luego cierra.
|
||||
void TilePicker::commitRectSelection() {
|
||||
int end_tile = (hover_tile_ >= 0) ? hover_tile_ : last_valid_hover_;
|
||||
if (end_tile >= 0 && rect_start_tile_ >= 0) {
|
||||
int c1 = rect_start_tile_ % tileset_width_;
|
||||
int r1 = rect_start_tile_ / tileset_width_;
|
||||
int c2 = end_tile % tileset_width_;
|
||||
int r2 = end_tile / tileset_width_;
|
||||
int col_min = std::min(c1, c2);
|
||||
int col_max = std::max(c1, c2);
|
||||
int row_min = std::min(r1, r2);
|
||||
int row_max = std::max(r1, r2);
|
||||
int width = col_max - col_min + 1;
|
||||
int height = row_max - row_min + 1;
|
||||
if (on_select) { on_select(col_min, row_min, width, height); }
|
||||
}
|
||||
selecting_rect_ = false;
|
||||
rect_start_tile_ = -1;
|
||||
close();
|
||||
}
|
||||
|
||||
// Maneja eventos del picker
|
||||
void TilePicker::handleEvent(const SDL_Event& event) {
|
||||
if (!open_) { return; }
|
||||
@@ -226,23 +247,7 @@ void TilePicker::handleEvent(const SDL_Event& event) {
|
||||
}
|
||||
|
||||
if (event.type == SDL_EVENT_MOUSE_BUTTON_UP && event.button.button == SDL_BUTTON_LEFT && selecting_rect_) {
|
||||
int end_tile = (hover_tile_ >= 0) ? hover_tile_ : last_valid_hover_;
|
||||
if (end_tile >= 0 && rect_start_tile_ >= 0) {
|
||||
int c1 = rect_start_tile_ % tileset_width_;
|
||||
int r1 = rect_start_tile_ / tileset_width_;
|
||||
int c2 = end_tile % tileset_width_;
|
||||
int r2 = end_tile / tileset_width_;
|
||||
int col_min = std::min(c1, c2);
|
||||
int col_max = std::max(c1, c2);
|
||||
int row_min = std::min(r1, r2);
|
||||
int row_max = std::max(r1, r2);
|
||||
int width = col_max - col_min + 1;
|
||||
int height = row_max - row_min + 1;
|
||||
if (on_select) { on_select(col_min, row_min, width, height); }
|
||||
}
|
||||
selecting_rect_ = false;
|
||||
rect_start_tile_ = -1;
|
||||
close();
|
||||
commitRectSelection();
|
||||
}
|
||||
|
||||
if (event.type == SDL_EVENT_MOUSE_WHEEL) {
|
||||
|
||||
@@ -44,6 +44,7 @@ class TilePicker {
|
||||
|
||||
private:
|
||||
void updateMousePosition();
|
||||
void commitRectSelection();
|
||||
|
||||
bool open_{false};
|
||||
std::shared_ptr<Surface> tileset_; // Surface del tileset original
|
||||
|
||||
Reference in New Issue
Block a user