treballant en editor de items i tile_picker
This commit is contained in:
@@ -100,6 +100,7 @@ set(APP_SOURCES
|
|||||||
source/game/editor/map_editor.cpp
|
source/game/editor/map_editor.cpp
|
||||||
source/game/editor/editor_statusbar.cpp
|
source/game/editor/editor_statusbar.cpp
|
||||||
source/game/editor/room_saver.cpp
|
source/game/editor/room_saver.cpp
|
||||||
|
source/game/editor/tile_picker.cpp
|
||||||
|
|
||||||
# Game - UI
|
# Game - UI
|
||||||
source/game/ui/console.cpp
|
source/game/ui/console.cpp
|
||||||
|
|||||||
@@ -226,13 +226,20 @@ categories:
|
|||||||
completions:
|
completions:
|
||||||
ENEMY: [ADD, DELETE, DUPLICATE]
|
ENEMY: [ADD, DELETE, DUPLICATE]
|
||||||
|
|
||||||
|
- keyword: ITEM
|
||||||
|
handler: cmd_item
|
||||||
|
description: "Add, delete or duplicate item (editor)"
|
||||||
|
usage: "ITEM <ADD|DELETE|DUPLICATE>"
|
||||||
|
completions:
|
||||||
|
ITEM: [ADD, DELETE, DUPLICATE]
|
||||||
|
|
||||||
- keyword: SET
|
- keyword: SET
|
||||||
handler: cmd_set
|
handler: cmd_set
|
||||||
description: "Set property (enemy or room, editor mode)"
|
description: "Set property (enemy or room, editor mode)"
|
||||||
usage: "SET <property> <value>"
|
usage: "SET <property> <value>"
|
||||||
dynamic_completions: true
|
dynamic_completions: true
|
||||||
completions:
|
completions:
|
||||||
SET: [ANIMATION, COLOR, VX, VY, FLIP, MIRROR, BGCOLOR, BORDER, ITEMCOLOR1, ITEMCOLOR2, CONVEYOR, TILESET, UP, DOWN, LEFT, RIGHT]
|
SET: [ANIMATION, COLOR, VX, VY, FLIP, MIRROR, BGCOLOR, BORDER, ITEMCOLOR1, ITEMCOLOR2, CONVEYOR, TILESET, UP, DOWN, LEFT, RIGHT, TILE, COUNTER]
|
||||||
SET FLIP: [ON, OFF]
|
SET FLIP: [ON, OFF]
|
||||||
SET MIRROR: [ON, OFF]
|
SET MIRROR: [ON, OFF]
|
||||||
SET CONVEYOR: [LEFT, NONE, RIGHT]
|
SET CONVEYOR: [LEFT, NONE, RIGHT]
|
||||||
|
|||||||
@@ -13,13 +13,13 @@
|
|||||||
#include "core/resources/resource_cache.hpp" // Para Resource::Cache
|
#include "core/resources/resource_cache.hpp" // Para Resource::Cache
|
||||||
#include "core/resources/resource_list.hpp" // Para Resource::List
|
#include "core/resources/resource_list.hpp" // Para Resource::List
|
||||||
#include "game/editor/editor_statusbar.hpp" // Para EditorStatusBar
|
#include "game/editor/editor_statusbar.hpp" // Para EditorStatusBar
|
||||||
#include "game/ui/console.hpp" // Para Console
|
|
||||||
#include "game/editor/room_saver.hpp" // Para RoomSaver
|
#include "game/editor/room_saver.hpp" // Para RoomSaver
|
||||||
#include "game/entities/player.hpp" // Para Player
|
#include "game/entities/player.hpp" // Para Player
|
||||||
#include "game/gameplay/enemy_manager.hpp" // Para EnemyManager
|
#include "game/gameplay/enemy_manager.hpp" // Para EnemyManager
|
||||||
#include "game/gameplay/item_manager.hpp" // Para ItemManager
|
#include "game/gameplay/item_manager.hpp" // Para ItemManager
|
||||||
#include "game/gameplay/room.hpp" // Para Room
|
#include "game/gameplay/room.hpp" // Para Room
|
||||||
#include "game/options.hpp" // Para Options
|
#include "game/options.hpp" // Para Options
|
||||||
|
#include "game/ui/console.hpp" // Para Console
|
||||||
#include "utils/defines.hpp" // Para Tile::SIZE, PlayArea
|
#include "utils/defines.hpp" // Para Tile::SIZE, PlayArea
|
||||||
#include "utils/utils.hpp" // Para stringToColor
|
#include "utils/utils.hpp" // Para stringToColor
|
||||||
|
|
||||||
@@ -193,6 +193,11 @@ void MapEditor::render() {
|
|||||||
// Renderizar highlight de selección (encima de los sprites)
|
// Renderizar highlight de selección (encima de los sprites)
|
||||||
renderSelectionHighlight();
|
renderSelectionHighlight();
|
||||||
|
|
||||||
|
// Tile picker (encima de todo en el play area)
|
||||||
|
if (tile_picker_.isOpen()) {
|
||||||
|
tile_picker_.render();
|
||||||
|
}
|
||||||
|
|
||||||
// Renderizar barra de estado del editor (reemplaza al scoreboard)
|
// Renderizar barra de estado del editor (reemplaza al scoreboard)
|
||||||
if (statusbar_) {
|
if (statusbar_) {
|
||||||
statusbar_->render();
|
statusbar_->render();
|
||||||
@@ -201,6 +206,12 @@ void MapEditor::render() {
|
|||||||
|
|
||||||
// Maneja eventos del editor
|
// Maneja eventos del editor
|
||||||
void MapEditor::handleEvent(const SDL_Event& event) {
|
void MapEditor::handleEvent(const SDL_Event& event) {
|
||||||
|
// Si el tile picker está abierto, los eventos van a él
|
||||||
|
if (tile_picker_.isOpen()) {
|
||||||
|
tile_picker_.handleEvent(event);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (event.type == SDL_EVENT_MOUSE_BUTTON_DOWN && event.button.button == SDL_BUTTON_LEFT) {
|
if (event.type == SDL_EVENT_MOUSE_BUTTON_DOWN && event.button.button == SDL_BUTTON_LEFT) {
|
||||||
handleMouseDown(mouse_game_x_, mouse_game_y_);
|
handleMouseDown(mouse_game_x_, mouse_game_y_);
|
||||||
} else if (event.type == SDL_EVENT_MOUSE_BUTTON_UP && event.button.button == SDL_BUTTON_LEFT) {
|
} else if (event.type == SDL_EVENT_MOUSE_BUTTON_UP && event.button.button == SDL_BUTTON_LEFT) {
|
||||||
@@ -268,8 +279,9 @@ void MapEditor::handleMouseDown(float game_x, float game_y) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Click en el fondo: deseleccionar
|
// Click en el fondo: deseleccionar todo
|
||||||
selected_enemy_ = -1;
|
selected_enemy_ = -1;
|
||||||
|
selected_item_ = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Procesa soltar el ratón: commit del drag
|
// Procesa soltar el ratón: commit del drag
|
||||||
@@ -281,11 +293,14 @@ void MapEditor::handleMouseUp() {
|
|||||||
// Si no se movió: fue un click → seleccionar/deseleccionar
|
// Si no se movió: fue un click → seleccionar/deseleccionar
|
||||||
if (!drag_.moved) {
|
if (!drag_.moved) {
|
||||||
if (drag_.target == DragTarget::ENEMY_INITIAL) {
|
if (drag_.target == DragTarget::ENEMY_INITIAL) {
|
||||||
// Toggle selección: si ya estaba seleccionado, deseleccionar
|
|
||||||
selected_enemy_ = (selected_enemy_ == IDX) ? -1 : IDX;
|
selected_enemy_ = (selected_enemy_ == IDX) ? -1 : IDX;
|
||||||
} else {
|
selected_item_ = -1;
|
||||||
// Click en otro tipo de entidad: deseleccionar enemigo
|
} else if (drag_.target == DragTarget::ITEM) {
|
||||||
|
selected_item_ = (selected_item_ == IDX) ? -1 : IDX;
|
||||||
selected_enemy_ = -1;
|
selected_enemy_ = -1;
|
||||||
|
} else {
|
||||||
|
selected_enemy_ = -1;
|
||||||
|
selected_item_ = -1;
|
||||||
}
|
}
|
||||||
drag_ = {};
|
drag_ = {};
|
||||||
return;
|
return;
|
||||||
@@ -333,6 +348,7 @@ void MapEditor::handleMouseUp() {
|
|||||||
case DragTarget::ITEM:
|
case DragTarget::ITEM:
|
||||||
if (IDX >= 0 && IDX < room_->getItemManager()->getCount()) {
|
if (IDX >= 0 && IDX < room_->getItemManager()->getCount()) {
|
||||||
room_->getItemManager()->getItem(IDX)->setPosition(drag_.snap_x, drag_.snap_y);
|
room_->getItemManager()->getItem(IDX)->setPosition(drag_.snap_x, drag_.snap_y);
|
||||||
|
selected_item_ = IDX;
|
||||||
selected_enemy_ = -1;
|
selected_enemy_ = -1;
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
@@ -415,6 +431,17 @@ void MapEditor::renderSelectionHighlight() {
|
|||||||
game_surface->drawRectBorder(&border, stringToColor("bright_green"));
|
game_surface->drawRectBorder(&border, stringToColor("bright_green"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Highlight del item seleccionado (persistente, color bright_green)
|
||||||
|
if (selected_item_ >= 0 && selected_item_ < room_->getItemManager()->getCount()) {
|
||||||
|
SDL_FRect item_rect = room_->getItemManager()->getItem(selected_item_)->getCollider();
|
||||||
|
SDL_FRect border = {
|
||||||
|
.x = item_rect.x - 1,
|
||||||
|
.y = item_rect.y - 1,
|
||||||
|
.w = item_rect.w + 2,
|
||||||
|
.h = item_rect.h + 2};
|
||||||
|
game_surface->drawRectBorder(&border, stringToColor("bright_green"));
|
||||||
|
}
|
||||||
|
|
||||||
// Highlight del drag activo (temporal, color bright_white)
|
// Highlight del drag activo (temporal, color bright_white)
|
||||||
if (drag_.target == DragTarget::NONE || !drag_.moved) { return; }
|
if (drag_.target == DragTarget::NONE || !drag_.moved) { return; }
|
||||||
|
|
||||||
@@ -559,12 +586,23 @@ void MapEditor::updateStatusBarInfo() {
|
|||||||
// Info de drag activo (línea 5, junto a tile coords)
|
// Info de drag activo (línea 5, junto a tile coords)
|
||||||
if (drag_.target != DragTarget::NONE && drag_.moved) {
|
if (drag_.target != DragTarget::NONE && drag_.moved) {
|
||||||
switch (drag_.target) {
|
switch (drag_.target) {
|
||||||
case DragTarget::PLAYER: line5 = "dragging: player"; break;
|
case DragTarget::PLAYER:
|
||||||
case DragTarget::ENEMY_INITIAL: line5 = "dragging: enemy " + std::to_string(drag_.index); break;
|
line5 = "dragging: player";
|
||||||
case DragTarget::ENEMY_BOUND1: line5 = "dragging: e" + std::to_string(drag_.index) + " bound1"; break;
|
break;
|
||||||
case DragTarget::ENEMY_BOUND2: line5 = "dragging: e" + std::to_string(drag_.index) + " bound2"; break;
|
case DragTarget::ENEMY_INITIAL:
|
||||||
case DragTarget::ITEM: line5 = "dragging: item " + std::to_string(drag_.index); break;
|
line5 = "dragging: enemy " + std::to_string(drag_.index);
|
||||||
case DragTarget::NONE: break;
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -581,11 +619,20 @@ void MapEditor::updateStatusBarInfo() {
|
|||||||
" vy:" + std::to_string(static_cast<int>(e.vy));
|
" vy:" + std::to_string(static_cast<int>(e.vy));
|
||||||
if (e.flip) { line3 += " flip"; }
|
if (e.flip) { line3 += " flip"; }
|
||||||
if (e.mirror) { line3 += " mirror"; }
|
if (e.mirror) { line3 += " mirror"; }
|
||||||
|
} else if (selected_item_ >= 0 && selected_item_ < static_cast<int>(room_data_.items.size())) {
|
||||||
|
// Item seleccionado
|
||||||
|
const auto& it = room_data_.items[selected_item_];
|
||||||
|
line2 = "item " + std::to_string(selected_item_) + ": tile=" + std::to_string(it.tile) +
|
||||||
|
" counter=" + std::to_string(it.counter);
|
||||||
|
line3 = "tileset: " + it.tile_set_file;
|
||||||
} else {
|
} else {
|
||||||
// Propiedades de la habitación
|
// Propiedades de la habitación
|
||||||
std::string conv = "none";
|
std::string conv = "none";
|
||||||
if (room_data_.conveyor_belt_direction < 0) { conv = "left"; }
|
if (room_data_.conveyor_belt_direction < 0) {
|
||||||
else if (room_data_.conveyor_belt_direction > 0) { conv = "right"; }
|
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;
|
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) +
|
line3 = "u:" + conn(room_data_.upper_room) + " d:" + conn(room_data_.lower_room) +
|
||||||
@@ -595,12 +642,14 @@ void MapEditor::updateStatusBarInfo() {
|
|||||||
|
|
||||||
statusbar_->setLine2(line2);
|
statusbar_->setLine2(line2);
|
||||||
statusbar_->setLine3(line3);
|
statusbar_->setLine3(line3);
|
||||||
statusbar_->setLine4(""); // Disponible para uso futuro
|
statusbar_->setLine4("");
|
||||||
statusbar_->setLine5(line5);
|
statusbar_->setLine5(line5);
|
||||||
|
|
||||||
// Actualizar el prompt de la consola según la selección
|
// Actualizar el prompt de la consola según la selección
|
||||||
if (selected_enemy_ >= 0) {
|
if (selected_enemy_ >= 0) {
|
||||||
Console::get()->setPrompt("enemy " + std::to_string(selected_enemy_) + "> ");
|
Console::get()->setPrompt("enemy " + std::to_string(selected_enemy_) + "> ");
|
||||||
|
} else if (selected_item_ >= 0) {
|
||||||
|
Console::get()->setPrompt("item " + std::to_string(selected_item_) + "> ");
|
||||||
} else {
|
} else {
|
||||||
Console::get()->setPrompt("room> ");
|
Console::get()->setPrompt("room> ");
|
||||||
}
|
}
|
||||||
@@ -826,9 +875,14 @@ auto MapEditor::setRoomProperty(const std::string& property, const std::string&
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (property == "CONVEYOR") {
|
if (property == "CONVEYOR") {
|
||||||
if (val == "left") { room_data_.conveyor_belt_direction = -1; }
|
if (val == "left") {
|
||||||
else if (val == "right") { room_data_.conveyor_belt_direction = 1; }
|
room_data_.conveyor_belt_direction = -1;
|
||||||
else { room_data_.conveyor_belt_direction = 0; val = "none"; }
|
} else if (val == "right") {
|
||||||
|
room_data_.conveyor_belt_direction = 1;
|
||||||
|
} else {
|
||||||
|
room_data_.conveyor_belt_direction = 0;
|
||||||
|
val = "none";
|
||||||
|
}
|
||||||
autosave();
|
autosave();
|
||||||
return "conveyor: " + val;
|
return "conveyor: " + val;
|
||||||
}
|
}
|
||||||
@@ -858,10 +912,15 @@ auto MapEditor::setRoomProperty(const std::string& property, const std::string&
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (property == "UP") { room_data_.upper_room = connection; }
|
if (property == "UP") {
|
||||||
else if (property == "DOWN") { room_data_.lower_room = connection; }
|
room_data_.upper_room = connection;
|
||||||
else if (property == "LEFT") { room_data_.left_room = connection; }
|
} else if (property == "DOWN") {
|
||||||
else { room_data_.right_room = connection; }
|
room_data_.lower_room = connection;
|
||||||
|
} else if (property == "LEFT") {
|
||||||
|
room_data_.left_room = connection;
|
||||||
|
} else {
|
||||||
|
room_data_.right_room = connection;
|
||||||
|
}
|
||||||
|
|
||||||
autosave();
|
autosave();
|
||||||
return toLower(property) + ": " + connection;
|
return toLower(property) + ": " + connection;
|
||||||
@@ -870,4 +929,113 @@ auto MapEditor::setRoomProperty(const std::string& property, const std::string&
|
|||||||
return "Unknown property: " + property + " (use: bgcolor, border, itemcolor1, itemcolor2, conveyor, tileset, up, down, left, right)";
|
return "Unknown property: " + property + " (use: bgcolor, border, itemcolor1, itemcolor2, conveyor, tileset, up, down, left, right)";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ¿Hay un item seleccionado?
|
||||||
|
auto MapEditor::hasSelectedItem() const -> bool {
|
||||||
|
return selected_item_ >= 0 && selected_item_ < static_cast<int>(room_data_.items.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modifica una propiedad del item seleccionado
|
||||||
|
auto MapEditor::setItemProperty(const std::string& property, const std::string& value) -> std::string {
|
||||||
|
if (!active_) { return "Editor not active"; }
|
||||||
|
if (!hasSelectedItem()) { return "No item selected"; }
|
||||||
|
|
||||||
|
auto& item = room_data_.items[selected_item_];
|
||||||
|
|
||||||
|
if (property == "TILE") {
|
||||||
|
// Abrir el tile picker visual
|
||||||
|
openTilePicker(item.tile_set_file, item.tile);
|
||||||
|
return "Select tile...";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (property == "COUNTER") {
|
||||||
|
try {
|
||||||
|
item.counter = std::stoi(value);
|
||||||
|
} catch (...) { return "Invalid value: " + value; }
|
||||||
|
autosave();
|
||||||
|
return "counter: " + std::to_string(item.counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
return "Unknown property: " + property + " (use: tile, counter)";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Abre el tile picker para seleccionar un tile
|
||||||
|
void MapEditor::openTilePicker(const std::string& tileset_name, int current_tile) {
|
||||||
|
// Cerrar la consola si está abierta (para que el primer click vaya al picker)
|
||||||
|
if (Console::get()->isActive()) {
|
||||||
|
Console::get()->toggle();
|
||||||
|
}
|
||||||
|
|
||||||
|
tile_picker_.on_select = [this](int tile) {
|
||||||
|
if (!hasSelectedItem()) { return; }
|
||||||
|
room_data_.items[selected_item_].tile = tile;
|
||||||
|
room_->getItemManager()->getItem(selected_item_)->setTile(tile);
|
||||||
|
autosave();
|
||||||
|
};
|
||||||
|
// Pasar color de fondo de la habitación + color de sustitución del item
|
||||||
|
int bg = stringToColor(room_data_.bg_color);
|
||||||
|
int item_color = stringToColor(room_data_.item_color1);
|
||||||
|
tile_picker_.open(tileset_name, current_tile, bg, 1, item_color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Crea un nuevo item con valores por defecto, centrado en la habitación
|
||||||
|
auto MapEditor::addItem() -> std::string {
|
||||||
|
if (!active_) { return "Editor not active"; }
|
||||||
|
|
||||||
|
Item::Data new_item;
|
||||||
|
new_item.tile_set_file = "items.gif";
|
||||||
|
new_item.tile = 42; // Tile por defecto
|
||||||
|
new_item.x = PlayArea::CENTER_X;
|
||||||
|
new_item.y = PlayArea::CENTER_Y;
|
||||||
|
new_item.counter = 0;
|
||||||
|
new_item.color1 = stringToColor(room_data_.item_color1);
|
||||||
|
new_item.color2 = stringToColor(room_data_.item_color2);
|
||||||
|
|
||||||
|
room_data_.items.push_back(new_item);
|
||||||
|
room_->getItemManager()->addItem(std::make_shared<Item>(new_item));
|
||||||
|
|
||||||
|
selected_item_ = static_cast<int>(room_data_.items.size()) - 1;
|
||||||
|
selected_enemy_ = -1;
|
||||||
|
|
||||||
|
autosave();
|
||||||
|
return "Added item " + std::to_string(selected_item_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Elimina el item seleccionado
|
||||||
|
auto MapEditor::deleteItem() -> std::string {
|
||||||
|
if (!active_) { return "Editor not active"; }
|
||||||
|
if (!hasSelectedItem()) { return "No item selected"; }
|
||||||
|
|
||||||
|
const int IDX = selected_item_;
|
||||||
|
room_data_.items.erase(room_data_.items.begin() + IDX);
|
||||||
|
|
||||||
|
// Recrear todos los items (los índices cambian al borrar)
|
||||||
|
auto* item_mgr = room_->getItemManager();
|
||||||
|
item_mgr->clear();
|
||||||
|
for (const auto& item_data : room_data_.items) {
|
||||||
|
item_mgr->addItem(std::make_shared<Item>(item_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
selected_item_ = -1;
|
||||||
|
autosave();
|
||||||
|
return "Deleted item " + std::to_string(IDX);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Duplica el item seleccionado (lo pone un tile a la derecha)
|
||||||
|
auto MapEditor::duplicateItem() -> std::string {
|
||||||
|
if (!active_) { return "Editor not active"; }
|
||||||
|
if (!hasSelectedItem()) { return "No item selected"; }
|
||||||
|
|
||||||
|
Item::Data copy = room_data_.items[selected_item_];
|
||||||
|
copy.x += Tile::SIZE;
|
||||||
|
|
||||||
|
room_data_.items.push_back(copy);
|
||||||
|
room_->getItemManager()->addItem(std::make_shared<Item>(copy));
|
||||||
|
|
||||||
|
selected_item_ = static_cast<int>(room_data_.items.size()) - 1;
|
||||||
|
selected_enemy_ = -1;
|
||||||
|
|
||||||
|
autosave();
|
||||||
|
return "Duplicated as item " + std::to_string(selected_item_);
|
||||||
|
}
|
||||||
|
|
||||||
#endif // _DEBUG
|
#endif // _DEBUG
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include <string> // Para string
|
#include <string> // Para string
|
||||||
|
|
||||||
#include "external/fkyaml_node.hpp" // Para fkyaml::node
|
#include "external/fkyaml_node.hpp" // Para fkyaml::node
|
||||||
|
#include "game/editor/tile_picker.hpp" // Para TilePicker
|
||||||
#include "game/entities/enemy.hpp" // Para Enemy::Data
|
#include "game/entities/enemy.hpp" // Para Enemy::Data
|
||||||
#include "game/entities/item.hpp" // Para Item::Data
|
#include "game/entities/item.hpp" // Para Item::Data
|
||||||
#include "game/entities/player.hpp" // Para Player::SpawnData
|
#include "game/entities/player.hpp" // Para Player::SpawnData
|
||||||
@@ -42,6 +43,14 @@ class MapEditor {
|
|||||||
// Comandos para propiedades de la habitación
|
// Comandos para propiedades de la habitación
|
||||||
auto setRoomProperty(const std::string& property, const std::string& value) -> std::string;
|
auto setRoomProperty(const std::string& property, const std::string& value) -> 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;
|
||||||
|
void openTilePicker(const std::string& tileset_name, int current_tile);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static MapEditor* instance_; // [SINGLETON] Objeto privado
|
static MapEditor* instance_; // [SINGLETON] Objeto privado
|
||||||
|
|
||||||
@@ -49,7 +58,12 @@ class MapEditor {
|
|||||||
~MapEditor(); // Destructor
|
~MapEditor(); // Destructor
|
||||||
|
|
||||||
// Tipos para drag & drop y selección
|
// Tipos para drag & drop y selección
|
||||||
enum class DragTarget { NONE, PLAYER, ENEMY_INITIAL, ENEMY_BOUND1, ENEMY_BOUND2, ITEM };
|
enum class DragTarget { NONE,
|
||||||
|
PLAYER,
|
||||||
|
ENEMY_INITIAL,
|
||||||
|
ENEMY_BOUND1,
|
||||||
|
ENEMY_BOUND2,
|
||||||
|
ITEM };
|
||||||
|
|
||||||
struct DragState {
|
struct DragState {
|
||||||
DragTarget target{DragTarget::NONE};
|
DragTarget target{DragTarget::NONE};
|
||||||
@@ -78,6 +92,7 @@ class MapEditor {
|
|||||||
bool active_{false};
|
bool active_{false};
|
||||||
DragState drag_;
|
DragState drag_;
|
||||||
int selected_enemy_{-1}; // Índice del enemigo seleccionado (-1 = ninguno)
|
int selected_enemy_{-1}; // Índice del enemigo seleccionado (-1 = ninguno)
|
||||||
|
int selected_item_{-1}; // Índice del item seleccionado (-1 = ninguno)
|
||||||
|
|
||||||
// Datos de la habitación
|
// Datos de la habitación
|
||||||
Room::Data room_data_;
|
Room::Data room_data_;
|
||||||
@@ -96,6 +111,9 @@ class MapEditor {
|
|||||||
// Barra de estado del editor
|
// Barra de estado del editor
|
||||||
std::unique_ptr<EditorStatusBar> statusbar_;
|
std::unique_ptr<EditorStatusBar> statusbar_;
|
||||||
|
|
||||||
|
// Tile picker (para seleccionar tiles de un tileset)
|
||||||
|
TilePicker tile_picker_;
|
||||||
|
|
||||||
// Estado del ratón
|
// Estado del ratón
|
||||||
float mouse_game_x_{0.0F};
|
float mouse_game_x_{0.0F};
|
||||||
float mouse_game_y_{0.0F};
|
float mouse_game_y_{0.0F};
|
||||||
|
|||||||
208
source/game/editor/tile_picker.cpp
Normal file
208
source/game/editor/tile_picker.cpp
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
#ifdef _DEBUG
|
||||||
|
|
||||||
|
#include "game/editor/tile_picker.hpp"
|
||||||
|
|
||||||
|
#include <algorithm> // Para std::clamp, std::min
|
||||||
|
|
||||||
|
#include "core/rendering/screen.hpp" // Para Screen
|
||||||
|
#include "core/rendering/surface.hpp" // Para Surface
|
||||||
|
#include "core/resources/resource_cache.hpp" // Para Resource::Cache
|
||||||
|
#include "utils/defines.hpp" // Para Tile::SIZE, PlayArea
|
||||||
|
#include "utils/utils.hpp" // Para stringToColor
|
||||||
|
|
||||||
|
// Margen del borde alrededor del tileset (en pixels)
|
||||||
|
static constexpr int BORDER_PAD = 3;
|
||||||
|
|
||||||
|
// Abre el picker con un tileset
|
||||||
|
void TilePicker::open(const std::string& tileset_name, int current_tile, int bg_color, int source_color, int target_color) {
|
||||||
|
tileset_ = Resource::Cache::get()->getSurface(tileset_name);
|
||||||
|
if (!tileset_) {
|
||||||
|
open_ = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tileset_width_ = static_cast<int>(tileset_->getWidth()) / Tile::SIZE;
|
||||||
|
tileset_height_ = static_cast<int>(tileset_->getHeight()) / Tile::SIZE;
|
||||||
|
current_tile_ = current_tile;
|
||||||
|
hover_tile_ = -1;
|
||||||
|
scroll_y_ = 0;
|
||||||
|
|
||||||
|
int tileset_px_w = tileset_width_ * Tile::SIZE;
|
||||||
|
int tileset_px_h = tileset_height_ * Tile::SIZE;
|
||||||
|
|
||||||
|
// Crear surface con borde: tileset + BORDER_PAD pixels a cada lado
|
||||||
|
int frame_w = tileset_px_w + BORDER_PAD * 2;
|
||||||
|
int frame_h = tileset_px_h + BORDER_PAD * 2;
|
||||||
|
frame_surface_ = std::make_shared<Surface>(frame_w, frame_h);
|
||||||
|
|
||||||
|
// Componer: fondo + borde + tileset (con sustitución de color opcional)
|
||||||
|
{
|
||||||
|
auto prev = Screen::get()->getRendererSurface();
|
||||||
|
Screen::get()->setRendererSurface(frame_surface_);
|
||||||
|
|
||||||
|
// Fondo: color personalizado o negro por defecto
|
||||||
|
Uint8 fill_color = (bg_color >= 0) ? static_cast<Uint8>(bg_color) : stringToColor("black");
|
||||||
|
frame_surface_->clear(fill_color);
|
||||||
|
|
||||||
|
// Borde doble (bright_white + white)
|
||||||
|
SDL_FRect outer = {.x = 0, .y = 0, .w = static_cast<float>(frame_w), .h = static_cast<float>(frame_h)};
|
||||||
|
frame_surface_->drawRectBorder(&outer, stringToColor("bright_white"));
|
||||||
|
SDL_FRect inner = {.x = 1, .y = 1, .w = static_cast<float>(frame_w - 2), .h = static_cast<float>(frame_h - 2)};
|
||||||
|
frame_surface_->drawRectBorder(&inner, stringToColor("white"));
|
||||||
|
|
||||||
|
// Tileset dentro del borde (con o sin sustitución de color)
|
||||||
|
if (source_color >= 0 && target_color >= 0) {
|
||||||
|
tileset_->renderWithColorReplace(BORDER_PAD, BORDER_PAD, static_cast<Uint8>(source_color), static_cast<Uint8>(target_color));
|
||||||
|
} else {
|
||||||
|
SDL_FRect dst_rect = {.x = static_cast<float>(BORDER_PAD), .y = static_cast<float>(BORDER_PAD), .w = static_cast<float>(tileset_px_w), .h = static_cast<float>(tileset_px_h)};
|
||||||
|
tileset_->render(nullptr, &dst_rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
Screen::get()->setRendererSurface(prev);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Centrar en el play area
|
||||||
|
offset_x_ = (PlayArea::WIDTH - frame_w) / 2;
|
||||||
|
int offset_y = (PlayArea::HEIGHT - frame_h) / 2;
|
||||||
|
if (offset_y < 0) { offset_y = 0; }
|
||||||
|
|
||||||
|
// Área visible
|
||||||
|
visible_height_ = PlayArea::HEIGHT;
|
||||||
|
|
||||||
|
// Posición de destino del frame
|
||||||
|
frame_dst_ = {.x = static_cast<float>(offset_x_), .y = static_cast<float>(offset_y), .w = static_cast<float>(frame_w), .h = static_cast<float>(frame_h)};
|
||||||
|
|
||||||
|
// Si el frame es más alto que el play area, necesitará scroll
|
||||||
|
if (frame_h > visible_height_) {
|
||||||
|
frame_dst_.y = 0;
|
||||||
|
// Scroll hasta el tile actual si está fuera de vista
|
||||||
|
if (current_tile_ >= 0) {
|
||||||
|
int tile_row = current_tile_ / tileset_width_;
|
||||||
|
int tile_y_px = tile_row * Tile::SIZE;
|
||||||
|
if (tile_y_px > visible_height_ / 2) {
|
||||||
|
scroll_y_ = tile_y_px - visible_height_ / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cierra el picker
|
||||||
|
void TilePicker::close() {
|
||||||
|
open_ = false;
|
||||||
|
tileset_.reset();
|
||||||
|
frame_surface_.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Renderiza el picker
|
||||||
|
void TilePicker::render() {
|
||||||
|
if (!open_ || !frame_surface_) { return; }
|
||||||
|
|
||||||
|
auto game_surface = Screen::get()->getRendererSurface();
|
||||||
|
if (!game_surface) { return; }
|
||||||
|
|
||||||
|
int frame_h = static_cast<int>(frame_dst_.h);
|
||||||
|
|
||||||
|
if (frame_h <= visible_height_) {
|
||||||
|
// El frame cabe entero: renderizar tal cual (flotando sobre el mapa)
|
||||||
|
frame_surface_->render(nullptr, &frame_dst_);
|
||||||
|
} else {
|
||||||
|
// El frame no cabe: renderizar porción visible con scroll
|
||||||
|
int max_scroll = frame_h - visible_height_;
|
||||||
|
scroll_y_ = std::clamp(scroll_y_, 0, max_scroll);
|
||||||
|
|
||||||
|
SDL_FRect src = {.x = 0, .y = static_cast<float>(scroll_y_), .w = frame_dst_.w, .h = static_cast<float>(visible_height_)};
|
||||||
|
SDL_FRect dst = {.x = frame_dst_.x, .y = 0, .w = frame_dst_.w, .h = static_cast<float>(visible_height_)};
|
||||||
|
frame_surface_->render(&src, &dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Los highlights se dibujan directamente en game_surface (encima del frame)
|
||||||
|
float tileset_screen_x = frame_dst_.x + BORDER_PAD;
|
||||||
|
float tileset_screen_y = frame_dst_.y + BORDER_PAD - static_cast<float>(scroll_y_);
|
||||||
|
|
||||||
|
// Highlight del tile bajo el cursor (blanco)
|
||||||
|
if (hover_tile_ >= 0) {
|
||||||
|
int col = hover_tile_ % tileset_width_;
|
||||||
|
int row = hover_tile_ / tileset_width_;
|
||||||
|
float hx = tileset_screen_x + static_cast<float>(col * Tile::SIZE);
|
||||||
|
float hy = tileset_screen_y + static_cast<float>(row * Tile::SIZE);
|
||||||
|
if (hy >= 0 && hy + Tile::SIZE <= visible_height_) {
|
||||||
|
SDL_FRect highlight = {.x = hx, .y = hy, .w = static_cast<float>(Tile::SIZE), .h = static_cast<float>(Tile::SIZE)};
|
||||||
|
game_surface->drawRectBorder(&highlight, stringToColor("bright_white"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Highlight del tile actual (verde)
|
||||||
|
if (current_tile_ >= 0) {
|
||||||
|
int col = current_tile_ % tileset_width_;
|
||||||
|
int row = current_tile_ / tileset_width_;
|
||||||
|
float cx = tileset_screen_x + static_cast<float>(col * Tile::SIZE);
|
||||||
|
float cy = tileset_screen_y + static_cast<float>(row * Tile::SIZE);
|
||||||
|
if (cy >= 0 && cy + Tile::SIZE <= visible_height_) {
|
||||||
|
SDL_FRect cur_rect = {.x = cx, .y = cy, .w = static_cast<float>(Tile::SIZE), .h = static_cast<float>(Tile::SIZE)};
|
||||||
|
game_surface->drawRectBorder(&cur_rect, stringToColor("bright_green"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Maneja eventos del picker
|
||||||
|
void TilePicker::handleEvent(const SDL_Event& event) {
|
||||||
|
if (!open_) { return; }
|
||||||
|
|
||||||
|
if (event.type == SDL_EVENT_MOUSE_MOTION) {
|
||||||
|
updateMousePosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.type == SDL_EVENT_MOUSE_BUTTON_DOWN) {
|
||||||
|
if (event.button.button == SDL_BUTTON_LEFT && hover_tile_ >= 0) {
|
||||||
|
if (on_select) { on_select(hover_tile_); }
|
||||||
|
close();
|
||||||
|
} else if (event.button.button == SDL_BUTTON_RIGHT) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.type == SDL_EVENT_MOUSE_WHEEL) {
|
||||||
|
scroll_y_ -= static_cast<int>(event.wheel.y) * Tile::SIZE * 2;
|
||||||
|
int max_scroll = static_cast<int>(frame_dst_.h) - visible_height_;
|
||||||
|
if (max_scroll < 0) { max_scroll = 0; }
|
||||||
|
scroll_y_ = std::clamp(scroll_y_, 0, max_scroll);
|
||||||
|
updateMousePosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.type == SDL_EVENT_KEY_DOWN && event.key.key == SDLK_ESCAPE) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calcula qué tile está bajo el cursor
|
||||||
|
void TilePicker::updateMousePosition() {
|
||||||
|
float mouse_x = 0.0F;
|
||||||
|
float mouse_y = 0.0F;
|
||||||
|
SDL_GetMouseState(&mouse_x, &mouse_y);
|
||||||
|
|
||||||
|
float render_x = 0.0F;
|
||||||
|
float render_y = 0.0F;
|
||||||
|
SDL_RenderCoordinatesFromWindow(Screen::get()->getRenderer(), mouse_x, mouse_y, &render_x, &render_y);
|
||||||
|
|
||||||
|
SDL_FRect dst_rect = Screen::get()->getGameSurfaceDstRect();
|
||||||
|
float game_x = render_x - dst_rect.x;
|
||||||
|
float game_y = render_y - dst_rect.y;
|
||||||
|
|
||||||
|
// Coordenada relativa al tileset (dentro del frame, con scroll)
|
||||||
|
float tileset_x = game_x - frame_dst_.x - BORDER_PAD;
|
||||||
|
float tileset_y = game_y - frame_dst_.y - BORDER_PAD + static_cast<float>(scroll_y_);
|
||||||
|
|
||||||
|
int tile_x = static_cast<int>(tileset_x) / Tile::SIZE;
|
||||||
|
int tile_y = static_cast<int>(tileset_y) / Tile::SIZE;
|
||||||
|
|
||||||
|
if (tileset_x >= 0 && tile_x >= 0 && tile_x < tileset_width_ &&
|
||||||
|
tileset_y >= 0 && tile_y >= 0 && tile_y < tileset_height_) {
|
||||||
|
hover_tile_ = tile_y * tileset_width_ + tile_x;
|
||||||
|
} else {
|
||||||
|
hover_tile_ = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // _DEBUG
|
||||||
58
source/game/editor/tile_picker.hpp
Normal file
58
source/game/editor/tile_picker.hpp
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
|
#include <functional> // Para function
|
||||||
|
#include <memory> // Para shared_ptr
|
||||||
|
#include <string> // Para string
|
||||||
|
|
||||||
|
class Surface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Selector visual de tiles de un tileset
|
||||||
|
*
|
||||||
|
* Muestra el tileset centrado en el play area.
|
||||||
|
* Hover ilumina el tile bajo el cursor.
|
||||||
|
* Click selecciona el tile y cierra el picker.
|
||||||
|
* Mouse wheel para scroll si el tileset es más alto que el play area.
|
||||||
|
* ESC o click derecho para cancelar.
|
||||||
|
*/
|
||||||
|
class TilePicker {
|
||||||
|
public:
|
||||||
|
TilePicker() = default;
|
||||||
|
~TilePicker() = default;
|
||||||
|
|
||||||
|
// Abre el picker con un tileset
|
||||||
|
// bg_color: color de fondo del panel (-1 = negro)
|
||||||
|
// source_color/target_color: sustitución de color al renderizar el tileset (-1 = sin sustitución)
|
||||||
|
void open(const std::string& tileset_name, int current_tile = -1, int bg_color = -1, int source_color = -1, int target_color = -1);
|
||||||
|
void close();
|
||||||
|
[[nodiscard]] auto isOpen() const -> bool { return open_; }
|
||||||
|
|
||||||
|
void render();
|
||||||
|
void handleEvent(const SDL_Event& event);
|
||||||
|
|
||||||
|
// Callback al seleccionar un tile (índice del tile)
|
||||||
|
std::function<void(int)> on_select;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateMousePosition();
|
||||||
|
|
||||||
|
bool open_{false};
|
||||||
|
std::shared_ptr<Surface> tileset_; // Surface del tileset original
|
||||||
|
std::shared_ptr<Surface> frame_surface_; // Surface compuesta: borde + tileset
|
||||||
|
SDL_FRect frame_dst_{}; // Posición del frame en pantalla
|
||||||
|
int tileset_width_{0}; // Ancho del tileset en tiles
|
||||||
|
int tileset_height_{0}; // Alto del tileset en tiles
|
||||||
|
int current_tile_{-1}; // Tile actualmente seleccionado (highlight)
|
||||||
|
int hover_tile_{-1}; // Tile bajo el cursor
|
||||||
|
|
||||||
|
// Scroll y posicionamiento
|
||||||
|
int scroll_y_{0}; // Scroll vertical en pixels
|
||||||
|
int offset_x_{0}; // Offset X para centrar en pantalla
|
||||||
|
int visible_height_{0}; // Altura visible en pixels
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _DEBUG
|
||||||
@@ -49,6 +49,13 @@ void Item::setPosition(float x, float y) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
// Cambia el tile del item (para editor)
|
||||||
|
void Item::setTile(int tile) {
|
||||||
|
sprite_->setClip((tile % 10) * ITEM_SIZE, (tile / 10) * ITEM_SIZE, ITEM_SIZE, ITEM_SIZE);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Asigna los colores del objeto
|
// Asigna los colores del objeto
|
||||||
void Item::setColors(Uint8 col1, Uint8 col2) {
|
void Item::setColors(Uint8 col1, Uint8 col2) {
|
||||||
// Reinicializa el vector de colores
|
// Reinicializa el vector de colores
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ class Item {
|
|||||||
void setColors(Uint8 col1, Uint8 col2); // Asigna los colores del objeto
|
void setColors(Uint8 col1, Uint8 col2); // Asigna los colores del objeto
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
void setPosition(float x, float y); // Establece la posición del item (para editor)
|
void setPosition(float x, float y); // Establece la posición del item (para editor)
|
||||||
|
void setTile(int tile); // Cambia el tile del item (para editor)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -708,6 +708,13 @@ static auto cmd_edit(const std::vector<std::string>& args) -> std::string {
|
|||||||
// SET <property> <value> — modifica propiedad del enemigo seleccionado o de la habitación
|
// 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 {
|
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() || !MapEditor::get()->isActive()) { return "Editor not active"; }
|
||||||
|
if (args.empty()) { return "usage: set <property> <value>"; }
|
||||||
|
|
||||||
|
// SET TILE no necesita argumento (abre el tile picker visual)
|
||||||
|
if (args[0] == "TILE" && MapEditor::get()->hasSelectedItem()) {
|
||||||
|
return MapEditor::get()->setItemProperty("TILE", "");
|
||||||
|
}
|
||||||
|
|
||||||
if (args.size() < 2) { return "usage: set <property> <value>"; }
|
if (args.size() < 2) { return "usage: set <property> <value>"; }
|
||||||
|
|
||||||
// Si hay enemigo seleccionado, aplicar a enemigo
|
// Si hay enemigo seleccionado, aplicar a enemigo
|
||||||
@@ -715,6 +722,11 @@ static auto cmd_set(const std::vector<std::string>& args) -> std::string {
|
|||||||
return MapEditor::get()->setEnemyProperty(args[0], args[1]);
|
return MapEditor::get()->setEnemyProperty(args[0], args[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Si hay item seleccionado, aplicar a item
|
||||||
|
if (MapEditor::get()->hasSelectedItem()) {
|
||||||
|
return MapEditor::get()->setItemProperty(args[0], args[1]);
|
||||||
|
}
|
||||||
|
|
||||||
// Si no, aplicar a la habitación
|
// Si no, aplicar a la habitación
|
||||||
return MapEditor::get()->setRoomProperty(args[0], args[1]);
|
return MapEditor::get()->setRoomProperty(args[0], args[1]);
|
||||||
}
|
}
|
||||||
@@ -734,6 +746,22 @@ static auto cmd_enemy(const std::vector<std::string>& args) -> std::string {
|
|||||||
}
|
}
|
||||||
return "usage: enemy <add|delete|duplicate>";
|
return "usage: enemy <add|delete|duplicate>";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ITEM [ADD|DELETE|DUPLICATE]
|
||||||
|
static auto cmd_item(const std::vector<std::string>& args) -> std::string {
|
||||||
|
if (!MapEditor::get() || !MapEditor::get()->isActive()) { return "Editor not active"; }
|
||||||
|
if (args.empty()) { return "usage: item <add|delete|duplicate>"; }
|
||||||
|
if (args[0] == "ADD") { return MapEditor::get()->addItem(); }
|
||||||
|
if (args[0] == "DELETE") {
|
||||||
|
if (!MapEditor::get()->hasSelectedItem()) { return "No item selected"; }
|
||||||
|
return MapEditor::get()->deleteItem();
|
||||||
|
}
|
||||||
|
if (args[0] == "DUPLICATE") {
|
||||||
|
if (!MapEditor::get()->hasSelectedItem()) { return "No item selected"; }
|
||||||
|
return MapEditor::get()->duplicateItem();
|
||||||
|
}
|
||||||
|
return "usage: item <add|delete|duplicate>";
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// SHOW [INFO|NOTIFICATION|CHEEVO]
|
// SHOW [INFO|NOTIFICATION|CHEEVO]
|
||||||
@@ -937,6 +965,7 @@ void CommandRegistry::registerHandlers() {
|
|||||||
handlers_["cmd_edit"] = cmd_edit;
|
handlers_["cmd_edit"] = cmd_edit;
|
||||||
handlers_["cmd_set"] = cmd_set;
|
handlers_["cmd_set"] = cmd_set;
|
||||||
handlers_["cmd_enemy"] = cmd_enemy;
|
handlers_["cmd_enemy"] = cmd_enemy;
|
||||||
|
handlers_["cmd_item"] = cmd_item;
|
||||||
#endif
|
#endif
|
||||||
// HELP se registra en load() como lambda que captura this
|
// HELP se registra en load() como lambda que captura this
|
||||||
|
|
||||||
@@ -967,9 +996,7 @@ void CommandRegistry::registerHandlers() {
|
|||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
// Colores de la paleta (compartido por SET COLOR, BGCOLOR, BORDER, ITEMCOLOR1, ITEMCOLOR2)
|
// Colores de la paleta (compartido por SET COLOR, BGCOLOR, BORDER, ITEMCOLOR1, ITEMCOLOR2)
|
||||||
auto color_provider = []() -> std::vector<std::string> {
|
auto color_provider = []() -> std::vector<std::string> {
|
||||||
return {"BLACK", "BRIGHT_BLACK", "BLUE", "BRIGHT_BLUE", "RED", "BRIGHT_RED",
|
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"};
|
||||||
"MAGENTA", "BRIGHT_MAGENTA", "GREEN", "BRIGHT_GREEN", "CYAN", "BRIGHT_CYAN",
|
|
||||||
"YELLOW", "BRIGHT_YELLOW", "WHITE", "BRIGHT_WHITE"};
|
|
||||||
};
|
};
|
||||||
dynamic_providers_["SET COLOR"] = color_provider;
|
dynamic_providers_["SET COLOR"] = color_provider;
|
||||||
dynamic_providers_["SET BGCOLOR"] = color_provider;
|
dynamic_providers_["SET BGCOLOR"] = color_provider;
|
||||||
|
|||||||
Reference in New Issue
Block a user