135 lines
4.9 KiB
C++
135 lines
4.9 KiB
C++
#pragma once
|
|
|
|
#ifdef _DEBUG
|
|
|
|
#include <cstdint>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
class Surface;
|
|
class Tilemap;
|
|
|
|
// Mode editor modal del GameScene. Només disponible en Debug — en Release
|
|
// aquesta classe no existeix (el .cpp es compila a un object buit i cap
|
|
// codi del joc final en fa referència).
|
|
//
|
|
// L'editor NO gestiona la tecla de toggle pròpia (`editor_toggle`): això
|
|
// ho fa GameScene per poder decidir la coexistència amb la pausa F11
|
|
// (mútuament excloents). L'editor s'encarrega de:
|
|
// - Estat propi (mode actiu, brush per mode, picker obert).
|
|
// - Input del ratolí i tecles internes (`T`, `E`, `H`, `Supr`, `ESC`).
|
|
// - Render del border blau + brush preview + picker.
|
|
// - Persistència del tilemap i de les entitats al YAML del repo en sortir.
|
|
//
|
|
// Modes del cursor (`Mode`):
|
|
// - TILE : el clic esquerre pinta el `brush_tile_` al tilemap.
|
|
// - ENTITY : el clic esquerre col·loca una instància de `brush_entity_`.
|
|
// - HAND : selecciona/mou/borra entitats existents.
|
|
//
|
|
// Pickers (`Picker`):
|
|
// - TILE_PICKER (`T`) : selecciona índex de tile.
|
|
// - ENTITY_PICKER (`E`) : selecciona tipus d'entitat (nom registrat al
|
|
// factory).
|
|
// Mútuament excloents: obrir un tanca l'altre.
|
|
class Editor {
|
|
public:
|
|
// Entra al mode editor: notifica i marca `active=true`. La congelació
|
|
// d'entitats / jugador la gestiona GameScene consultant `active()`.
|
|
void enter();
|
|
|
|
// Surt del mode editor: persisteix el tilemap al YAML (writer surgical)
|
|
// i notifica. Si la persistència falla, emet la notificació d'error.
|
|
void exit(Tilemap& tilemap);
|
|
|
|
// Helper: enter() si no actiu, exit() si actiu. Útil des de GameScene
|
|
// quan detecta la tecla de toggle.
|
|
void toggle(Tilemap& tilemap);
|
|
|
|
[[nodiscard]] auto active() const -> bool { return active_; }
|
|
|
|
// Processa input propi (brush, picker). No-op si no actiu.
|
|
void update(int delta_ms, Tilemap& tilemap);
|
|
|
|
// Pinta el border blau i, segons mode i picker, brush preview, marc
|
|
// d'entitat seleccionada o el picker. No-op si no actiu.
|
|
void render(const Tilemap& tilemap) const;
|
|
|
|
private:
|
|
// Mode del cursor: determina què fa el clic esquerre sobre el mapa.
|
|
enum class Mode : std::uint8_t { TILE,
|
|
ENTITY,
|
|
HAND };
|
|
|
|
// Quin picker està obert (si n'hi ha). Mútuament excloents.
|
|
enum class Picker : std::uint8_t { NONE,
|
|
TILE,
|
|
ENTITY };
|
|
|
|
// Consum de hotkeys pròpies (T, E, H, ESC). Modifica `mode_` / `picker_`.
|
|
// Es crida al principi d'`update` perquè altres handlers no vegin
|
|
// tecles ja interpretades pel propi editor.
|
|
void handleHotkeys();
|
|
|
|
// Aplica una tecla i retorna true si l'editor l'ha consumit. Aïllat
|
|
// per mantenir baixa la complexitat cognitiva de `handleHotkeys` —
|
|
// l'iteració del buffer queda neta i la lògica de transició viu en
|
|
// un sol lloc.
|
|
auto applyHotkey(int scancode) -> bool;
|
|
|
|
// Branques d'update segons (mode, picker). Només té sentit cridar-les
|
|
// des d'`update`.
|
|
void updateTileBrush(Tilemap& tilemap, int canvas_x, int canvas_y);
|
|
void updateEntityBrush(int canvas_x, int canvas_y);
|
|
void updateHand(int canvas_x, int canvas_y);
|
|
void updateTilePicker(const Tilemap& tilemap, int canvas_x, int canvas_y);
|
|
void updateEntityPicker(int canvas_x, int canvas_y);
|
|
|
|
void renderTilePicker(const Tilemap& tilemap) const;
|
|
void renderEntityPicker(const Tilemap& tilemap) const;
|
|
|
|
bool active_{false};
|
|
Mode mode_{Mode::TILE};
|
|
Picker picker_{Picker::NONE};
|
|
|
|
// Cursor en cel·les del tilemap. -1/-1 = fora del mapa.
|
|
int cursor_col_{-1};
|
|
int cursor_row_{-1};
|
|
|
|
// Brush actiu per Mode::TILE (índex al tileset; -1 = sense brush).
|
|
int brush_tile_{-1};
|
|
// Estat del TilePicker.
|
|
int tile_picker_scroll_{0};
|
|
int tile_picker_hover_{-1};
|
|
|
|
// Brush actiu per Mode::ENTITY (nom registrat al factory; "" = cap).
|
|
std::string brush_entity_;
|
|
// Estat de l'EntityPicker.
|
|
int entity_picker_scroll_{0};
|
|
int entity_picker_hover_{-1}; // Índex a la llista de noms.
|
|
|
|
// Entrada editable del picker. Cada item recorda el nom (clau de
|
|
// factory + YAML), el surface del sprite (frame 0 com a icona) i la
|
|
// mida de cada frame al GIF — necessària per clipar el primer frame
|
|
// quan el GIF és un strip multi-frame.
|
|
struct EditableEntity {
|
|
std::string name;
|
|
std::shared_ptr<Surface> sprite;
|
|
int frame_w{0};
|
|
int frame_h{0};
|
|
};
|
|
|
|
// Construïda lazy al primer enter() i preservada entre sessions:
|
|
// el cost és I/O + parse de N plantilles YAML, però `EntityLoader`
|
|
// ja les memoritza, així que rellegir només resoldria per sortida i
|
|
// entrada al editor — no val la pena.
|
|
void ensureEditableEntities();
|
|
|
|
std::vector<EditableEntity> editable_entities_;
|
|
|
|
// Selecció en Mode::HAND (índex dins de l'EntityManager; -1 = cap).
|
|
int hand_selected_idx_{-1};
|
|
};
|
|
|
|
#endif // _DEBUG
|