#pragma once #ifdef _DEBUG #include #include // Para shared_ptr, unique_ptr #include // Para string #include "game/editor/mini_map.hpp" // Para MiniMap #include "game/editor/tile_picker.hpp" // Para TilePicker #include "game/entities/door.hpp" // Para Door::Data #include "game/entities/enemy.hpp" // Para Enemy::Data #include "game/entities/item.hpp" // Para Item::Data #include "game/entities/key.hpp" // Para Key::Data #include "game/entities/moving_platform.hpp" // Para MovingPlatform::Data #include "game/entities/player.hpp" // Para Player::SpawnData #include "game/gameplay/room.hpp" // Para Room::Data #include "game/gameplay/scoreboard.hpp" // Para Scoreboard::Data #include "game/options.hpp" // Para Options::Cheat class EditorStatusBar; // Tipo de entidad editable en el editor enum class EntityType { NONE, ENEMY, ITEM, PLATFORM, KEY, DOOR }; // Seleccion unificada: una sola entidad seleccionada a la vez struct Selection { EntityType type{EntityType::NONE}; int index{-1}; void clear() { type = EntityType::NONE; index = -1; } [[nodiscard]] auto isNone() const -> bool { return type == EntityType::NONE; } [[nodiscard]] auto is(EntityType t) const -> bool { return type == t && index >= 0; } }; class MapEditor { public: static void init(); // [SINGLETON] Crea el objeto static void destroy(); // [SINGLETON] Destruye el objeto static auto get() -> MapEditor*; // [SINGLETON] Obtiene el objeto void enter(std::shared_ptr room, std::shared_ptr player, const std::string& room_path, std::shared_ptr scoreboard_data); void exit(); [[nodiscard]] auto isActive() const -> bool { return active_; } void update(float delta_time); void render(); void handleEvent(const SDL_Event& event); auto revert() -> std::string; // 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 { return selection_.is(EntityType::ENEMY); } [[nodiscard]] auto getSetCompletions() const -> std::vector; // Comandos para propiedades de la habitación auto setRoomProperty(const std::string& property, const std::string& value) -> std::string; auto createNewRoom(const std::string& direction = "") -> std::string; auto deleteRoom() -> std::string; // Opciones del editor (llamados desde console_commands / teclas) 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; } void toggleMiniMap(); void setReenter(bool value) { reenter_ = value; } auto setMiniMapBg(const std::string& color) -> std::string; auto setMiniMapConn(const std::string& color) -> std::string; // Comandos para items auto setItemProperty(const std::string& property, const std::string& value) -> std::string; auto addItem() -> std::string; auto deleteItem() -> std::string; auto duplicateItem() -> std::string; [[nodiscard]] auto hasSelectedItem() const -> bool { return selection_.is(EntityType::ITEM); } void openTilePicker(const std::string& tileset_name, int current_tile); // Comandos para plataformas auto setPlatformProperty(const std::string& property, const std::string& value) -> std::string; auto addPlatform() -> std::string; auto deletePlatform() -> std::string; auto duplicatePlatform() -> std::string; [[nodiscard]] auto hasSelectedPlatform() const -> bool { return selection_.is(EntityType::PLATFORM); } // Comandos para llaves auto setKeyProperty(const std::string& property, const std::string& value) -> std::string; auto addKey() -> std::string; auto deleteKey() -> std::string; auto duplicateKey() -> std::string; [[nodiscard]] auto hasSelectedKey() const -> bool { return selection_.is(EntityType::KEY); } // Comandos para puertas auto setDoorProperty(const std::string& property, const std::string& value) -> std::string; auto addDoor() -> std::string; auto deleteDoor() -> std::string; auto duplicateDoor() -> std::string; [[nodiscard]] auto hasSelectedDoor() const -> bool { return selection_.is(EntityType::DOOR); } // Seleccion unificada [[nodiscard]] auto getSelectionType() const -> EntityType { return selection_.type; } private: static MapEditor* instance_; // NOLINT(readability-identifier-naming) [SINGLETON] Objeto privado MapEditor(); // Constructor ~MapEditor(); // Destructor // Opciones persistentes del editor struct Settings { bool grid{false}; bool show_render_info{false}; Uint8 minimap_bg{2}; Uint8 minimap_conn{14}; }; Settings settings_; void loadSettings(); void saveSettings() const; // Tipos para drag & drop enum class DragTarget { NONE, PLAYER, ENTITY_INITIAL, ENTITY_BOUND1, ENTITY_BOUND2 }; struct DragState { DragTarget target{DragTarget::NONE}; EntityType entity_type{EntityType::NONE}; int index{-1}; float offset_x{0.0F}; float offset_y{0.0F}; float snap_x{0.0F}; float snap_y{0.0F}; bool moved{false}; // true si el ratón se movió durante el drag }; // Métodos internos void updateMousePosition(); void renderEntityBoundaries(); static void renderBoundaryMarker(float x, float y, Uint8 color); void renderSelectionHighlight(); void renderGrid() const; void handleMouseDown(float game_x, float game_y); void handleMouseUp(); // Reconstruye todas las puertas vivas desde room_data_, limpiando primero // los WALLs antiguos del CollisionMap. Lo usa setDoorProperty cuando un // cambio (id, animation) requiere recrear el Door y mantener los tiles // sincronizados. void rebuildDoors(); void updateDrag(); auto commitEntityDrag() -> bool; void moveEntityVisual(); void autosave(); void updateStatusBarInfo(); static auto snapToGrid(float value) -> float; static auto pointInRect(float px, float py, const SDL_FRect& rect) -> bool; // Entity helpers: acceso abstracto a datos de entidad por tipo struct BoundaryData { int x1, y1, x2, y2; }; 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; auto entityDataCount(EntityType type) const -> int; static auto entityLabel(EntityType type) -> const char*; // Estado del editor bool active_{false}; DragState drag_; Selection selection_; // Entidad seleccionada (unificada: enemy, item o platform) static constexpr int NO_BRUSH = -2; // Sin brush activo static constexpr int ERASER_BRUSH = -1; // Brush borrador (pinta tile vacío = -1) int brush_tile_{NO_BRUSH}; // Tile activo para pintar bool painting_{false}; // true mientras se está pintando con click izquierdo mantenido bool editing_collision_{false}; // true = editando collision tilemap, false = editando draw tilemap // Datos de la habitación Room::Data room_data_; std::string room_path_; std::string file_path_; // Referencias a objetos vivos std::shared_ptr room_; std::shared_ptr player_; std::shared_ptr scoreboard_data_; // Barra de estado del editor std::unique_ptr statusbar_; // Tile picker y mini mapa TilePicker tile_picker_; std::unique_ptr mini_map_; bool mini_map_visible_{false}; // Estado del ratón float mouse_game_x_{0.0F}; float mouse_game_y_{0.0F}; int mouse_tile_x_{0}; int mouse_tile_y_{0}; // Estado previo (para restaurar al salir) Options::Cheat::State invincible_before_editor_{Options::Cheat::State::DISABLED}; bool render_info_before_editor_{false}; bool reenter_{false}; // true cuando es un re-enter tras cambio de room (no tocar render_info) }; #endif // _DEBUG