mil arreglos cosmetics a console 2.0

This commit is contained in:
2026-03-30 19:56:31 +02:00
parent cd14ae22c5
commit 32f22c99db
6 changed files with 18111 additions and 1572 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,59 +1,633 @@
#pragma once #pragma once
#include <cstdint>
#include <cstddef> #include <cstddef>
#include <cstdint>
static const uint8_t kupscale_frag_spv[] = { static const uint8_t kupscale_frag_spv[] = {
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0b, 0x00, 0x0d, 0x00, 0x03,
0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x02,
0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x23,
0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, 0x07,
0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x01,
0x09, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x0b,
0x02, 0x00, 0x00, 0x00, 0xc2, 0x01, 0x00, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00,
0x47, 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x63, 0x70, 0x0d,
0x70, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x00,
0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, 0x00, 0x14,
0x04, 0x00, 0x08, 0x00, 0x47, 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, 0x4c, 0x00,
0x45, 0x5f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x64, 0x69, 0x00,
0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, 0x05, 0x00, 0x04, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00,
0x05, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x5f, 0x00,
0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x00,
0x0d, 0x00, 0x00, 0x00, 0x73, 0x63, 0x65, 0x6e, 0x65, 0x00, 0x00, 0x00, 0x00,
0x05, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00, 0x76, 0x5f, 0x75, 0x76, 0x11,
0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00,
0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x02,
0x0d, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x47, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x01,
0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00,
0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0b,
0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x06,
0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00,
0x3b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01,
0x03, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x03, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x47,
0x0a, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x4c,
0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x53,
0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c,
0x17, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2e,
0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x73,
0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x74,
0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x64,
0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x2e,
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x34,
0x05, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x35,
0x0e, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x30,
0x0f, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00,
0x57, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00,
0x0e, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x00,
0x09, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, 0x00,
0x38, 0x00, 0x01, 0x00 0x0e,
}; 0x00,
0x03,
0x00,
0x00,
0x00,
0x00,
0x00,
0x01,
0x00,
0x00,
0x00,
0x0f,
0x00,
0x07,
0x00,
0x04,
0x00,
0x00,
0x00,
0x04,
0x00,
0x00,
0x00,
0x6d,
0x61,
0x69,
0x6e,
0x00,
0x00,
0x00,
0x00,
0x09,
0x00,
0x00,
0x00,
0x11,
0x00,
0x00,
0x00,
0x10,
0x00,
0x03,
0x00,
0x04,
0x00,
0x00,
0x00,
0x07,
0x00,
0x00,
0x00,
0x03,
0x00,
0x03,
0x00,
0x02,
0x00,
0x00,
0x00,
0xc2,
0x01,
0x00,
0x00,
0x04,
0x00,
0x0a,
0x00,
0x47,
0x4c,
0x5f,
0x47,
0x4f,
0x4f,
0x47,
0x4c,
0x45,
0x5f,
0x63,
0x70,
0x70,
0x5f,
0x73,
0x74,
0x79,
0x6c,
0x65,
0x5f,
0x6c,
0x69,
0x6e,
0x65,
0x5f,
0x64,
0x69,
0x72,
0x65,
0x63,
0x74,
0x69,
0x76,
0x65,
0x00,
0x00,
0x04,
0x00,
0x08,
0x00,
0x47,
0x4c,
0x5f,
0x47,
0x4f,
0x4f,
0x47,
0x4c,
0x45,
0x5f,
0x69,
0x6e,
0x63,
0x6c,
0x75,
0x64,
0x65,
0x5f,
0x64,
0x69,
0x72,
0x65,
0x63,
0x74,
0x69,
0x76,
0x65,
0x00,
0x05,
0x00,
0x04,
0x00,
0x04,
0x00,
0x00,
0x00,
0x6d,
0x61,
0x69,
0x6e,
0x00,
0x00,
0x00,
0x00,
0x05,
0x00,
0x05,
0x00,
0x09,
0x00,
0x00,
0x00,
0x6f,
0x75,
0x74,
0x5f,
0x63,
0x6f,
0x6c,
0x6f,
0x72,
0x00,
0x00,
0x00,
0x05,
0x00,
0x04,
0x00,
0x0d,
0x00,
0x00,
0x00,
0x73,
0x63,
0x65,
0x6e,
0x65,
0x00,
0x00,
0x00,
0x05,
0x00,
0x04,
0x00,
0x11,
0x00,
0x00,
0x00,
0x76,
0x5f,
0x75,
0x76,
0x00,
0x00,
0x00,
0x00,
0x47,
0x00,
0x04,
0x00,
0x09,
0x00,
0x00,
0x00,
0x1e,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x47,
0x00,
0x04,
0x00,
0x0d,
0x00,
0x00,
0x00,
0x21,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x47,
0x00,
0x04,
0x00,
0x0d,
0x00,
0x00,
0x00,
0x22,
0x00,
0x00,
0x00,
0x02,
0x00,
0x00,
0x00,
0x47,
0x00,
0x04,
0x00,
0x11,
0x00,
0x00,
0x00,
0x1e,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x13,
0x00,
0x02,
0x00,
0x02,
0x00,
0x00,
0x00,
0x21,
0x00,
0x03,
0x00,
0x03,
0x00,
0x00,
0x00,
0x02,
0x00,
0x00,
0x00,
0x16,
0x00,
0x03,
0x00,
0x06,
0x00,
0x00,
0x00,
0x20,
0x00,
0x00,
0x00,
0x17,
0x00,
0x04,
0x00,
0x07,
0x00,
0x00,
0x00,
0x06,
0x00,
0x00,
0x00,
0x04,
0x00,
0x00,
0x00,
0x20,
0x00,
0x04,
0x00,
0x08,
0x00,
0x00,
0x00,
0x03,
0x00,
0x00,
0x00,
0x07,
0x00,
0x00,
0x00,
0x3b,
0x00,
0x04,
0x00,
0x08,
0x00,
0x00,
0x00,
0x09,
0x00,
0x00,
0x00,
0x03,
0x00,
0x00,
0x00,
0x19,
0x00,
0x09,
0x00,
0x0a,
0x00,
0x00,
0x00,
0x06,
0x00,
0x00,
0x00,
0x01,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x01,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x1b,
0x00,
0x03,
0x00,
0x0b,
0x00,
0x00,
0x00,
0x0a,
0x00,
0x00,
0x00,
0x20,
0x00,
0x04,
0x00,
0x0c,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x0b,
0x00,
0x00,
0x00,
0x3b,
0x00,
0x04,
0x00,
0x0c,
0x00,
0x00,
0x00,
0x0d,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x17,
0x00,
0x04,
0x00,
0x0f,
0x00,
0x00,
0x00,
0x06,
0x00,
0x00,
0x00,
0x02,
0x00,
0x00,
0x00,
0x20,
0x00,
0x04,
0x00,
0x10,
0x00,
0x00,
0x00,
0x01,
0x00,
0x00,
0x00,
0x0f,
0x00,
0x00,
0x00,
0x3b,
0x00,
0x04,
0x00,
0x10,
0x00,
0x00,
0x00,
0x11,
0x00,
0x00,
0x00,
0x01,
0x00,
0x00,
0x00,
0x36,
0x00,
0x05,
0x00,
0x02,
0x00,
0x00,
0x00,
0x04,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x03,
0x00,
0x00,
0x00,
0xf8,
0x00,
0x02,
0x00,
0x05,
0x00,
0x00,
0x00,
0x3d,
0x00,
0x04,
0x00,
0x0b,
0x00,
0x00,
0x00,
0x0e,
0x00,
0x00,
0x00,
0x0d,
0x00,
0x00,
0x00,
0x3d,
0x00,
0x04,
0x00,
0x0f,
0x00,
0x00,
0x00,
0x12,
0x00,
0x00,
0x00,
0x11,
0x00,
0x00,
0x00,
0x57,
0x00,
0x05,
0x00,
0x07,
0x00,
0x00,
0x00,
0x13,
0x00,
0x00,
0x00,
0x0e,
0x00,
0x00,
0x00,
0x12,
0x00,
0x00,
0x00,
0x3e,
0x00,
0x03,
0x00,
0x09,
0x00,
0x00,
0x00,
0x13,
0x00,
0x00,
0x00,
0xfd,
0x00,
0x01,
0x00,
0x38,
0x00,
0x01,
0x00};
static const size_t kupscale_frag_spv_size = 628; static const size_t kupscale_frag_spv_size = 628;

View File

@@ -31,6 +31,7 @@
struct ConsoleCommand { struct ConsoleCommand {
std::string_view keyword; std::string_view keyword;
std::function<std::string(const std::vector<std::string>& args)> execute; std::function<std::string(const std::vector<std::string>& args)> execute;
bool instant{false}; // Si true, muestra la respuesta sin efecto typewriter
}; };
// Convierte la entrada a uppercase y la divide en tokens por espacios // Convierte la entrada a uppercase y la divide en tokens por espacios
@@ -70,7 +71,7 @@ static auto parseTokens(const std::string& input) -> std::vector<std::string> {
(toggle_fn); \ (toggle_fn); \
return label " OFF"; \ return label " OFF"; \
} \ } \
return "Usage: " label " [ON|OFF]"; \ return "usage: " label " [on|off]"; \
} }
// Texto de ayuda común para HELP y ? // Texto de ayuda común para HELP y ?
@@ -155,7 +156,7 @@ static const std::vector<ConsoleCommand> COMMANDS = {
Screen::get()->setLinearUpscale(true); Screen::get()->setLinearUpscale(true);
return "Upscale: Linear"; return "Upscale: Linear";
} }
return "Usage: SS UPSCALE [NEAREST|LINEAR]"; return "usage: ss upscale [nearest|linear]";
} }
if (!args.empty() && args[0] == "DOWNSCALE") { if (!args.empty() && args[0] == "DOWNSCALE") {
if (args.size() == 1) { if (args.size() == 1) {
@@ -165,7 +166,7 @@ static const std::vector<ConsoleCommand> COMMANDS = {
if (args[1] == "BILINEAR") { algo = 0; } if (args[1] == "BILINEAR") { algo = 0; }
if (args[1] == "LANCZOS2") { algo = 1; } if (args[1] == "LANCZOS2") { algo = 1; }
if (args[1] == "LANCZOS3") { algo = 2; } if (args[1] == "LANCZOS3") { algo = 2; }
if (algo == -1) { return "Usage: SS DOWNSCALE [BILINEAR|LANCZOS2|LANCZOS3]"; } if (algo == -1) { return "usage: ss downscale [bilinear|lanczos2|lanczos3]"; }
if (Options::video.downscale_algo == algo) { if (Options::video.downscale_algo == algo) {
return std::string("Downscale already ") + std::string(DOWNSCALE_NAMES[static_cast<size_t>(algo)]); return std::string("Downscale already ") + std::string(DOWNSCALE_NAMES[static_cast<size_t>(algo)]);
} }
@@ -186,7 +187,7 @@ static const std::vector<ConsoleCommand> COMMANDS = {
Screen::get()->toggleSupersampling(); Screen::get()->toggleSupersampling();
return "PostFX Supersampling OFF"; return "PostFX Supersampling OFF";
} }
return "Usage: SS [ON|OFF|SIZE|UPSCALE [NEAREST|LINEAR]|DOWNSCALE [BILINEAR|LANCZOS2|LANCZOS3]]"; return "usage: ss [on|off|size|upscale [nearest|linear]|downscale [bilinear|lanczos2|lanczos3]]";
}}, }},
// SHADER [ON|OFF|NEXT [PRESET]|POSTFX|CRTPI] — Toggle/cicla/selecciona shader (F4 / Shift+F4) // SHADER [ON|OFF|NEXT [PRESET]|POSTFX|CRTPI] — Toggle/cicla/selecciona shader (F4 / Shift+F4)
@@ -238,7 +239,7 @@ static const std::vector<ConsoleCommand> COMMANDS = {
return std::string("Shader: ") + return std::string("Shader: ") +
(Options::current_shader == Rendering::ShaderType::CRTPI ? "CRTPI" : "POSTFX"); (Options::current_shader == Rendering::ShaderType::CRTPI ? "CRTPI" : "POSTFX");
} }
return "Usage: SHADER [ON|OFF|NEXT [PRESET]|POSTFX|CRTPI]"; return "usage: shader [on|off|next [preset]|postfx|crtpi]";
}}, }},
// BORDER [ON|OFF] — Borde decorativo (B) // BORDER [ON|OFF] — Borde decorativo (B)
@@ -269,12 +270,12 @@ static const std::vector<ConsoleCommand> COMMANDS = {
Screen::get()->toggleVideoMode(); Screen::get()->toggleVideoMode();
return std::string("Fullscreen ") + (Options::video.fullscreen ? "ON" : "OFF"); return std::string("Fullscreen ") + (Options::video.fullscreen ? "ON" : "OFF");
} }
return "Usage: FULLSCREEN [ON|OFF]"; return "usage: fullscreen [on|off]";
}}, }},
// ZOOM UP/DOWN — Zoom de ventana (F1/F2) // ZOOM UP/DOWN — Zoom de ventana (F1/F2)
{.keyword = "ZOOM", .execute = [](const std::vector<std::string>& args) -> std::string { {.keyword = "ZOOM", .execute = [](const std::vector<std::string>& args) -> std::string {
if (args.empty()) { return "Usage: ZOOM [UP|DOWN]"; } if (args.empty()) { return "usage: zoom [up|down]"; }
if (args[0] == "UP") { if (args[0] == "UP") {
if (!Screen::get()->incWindowZoom()) { return "Max zoom reached"; } if (!Screen::get()->incWindowZoom()) { return "Max zoom reached"; }
return "Zoom " + std::to_string(Options::window.zoom); return "Zoom " + std::to_string(Options::window.zoom);
@@ -283,7 +284,7 @@ static const std::vector<ConsoleCommand> COMMANDS = {
if (!Screen::get()->decWindowZoom()) { return "Min zoom reached"; } if (!Screen::get()->decWindowZoom()) { return "Min zoom reached"; }
return "Zoom " + std::to_string(Options::window.zoom); return "Zoom " + std::to_string(Options::window.zoom);
} }
return "Usage: ZOOM [UP|DOWN]"; return "usage: zoom [up|down]";
}}, }},
// INTSCALE [ON|OFF] — Escalado entero (F7) // INTSCALE [ON|OFF] — Escalado entero (F7)
@@ -291,7 +292,7 @@ static const std::vector<ConsoleCommand> COMMANDS = {
const bool ON = args.empty() ? !Options::video.integer_scale const bool ON = args.empty() ? !Options::video.integer_scale
: (args[0] == "ON"); : (args[0] == "ON");
if (!args.empty() && args[0] != "ON" && args[0] != "OFF") { if (!args.empty() && args[0] != "ON" && args[0] != "OFF") {
return "Usage: INTSCALE [ON|OFF]"; return "usage: intscale [on|off]";
} }
if (ON == Options::video.integer_scale) { if (ON == Options::video.integer_scale) {
return std::string("IntScale already ") + (ON ? "ON" : "OFF"); return std::string("IntScale already ") + (ON ? "ON" : "OFF");
@@ -362,7 +363,7 @@ static const std::vector<ConsoleCommand> COMMANDS = {
// PALETTE NEXT/PREV — Paleta de colores (F5/F6) // PALETTE NEXT/PREV — Paleta de colores (F5/F6)
{.keyword = "PALETTE", .execute = [](const std::vector<std::string>& args) -> std::string { {.keyword = "PALETTE", .execute = [](const std::vector<std::string>& args) -> std::string {
if (args.empty()) { return "Usage: PALETTE [NEXT|PREV]"; } if (args.empty()) { return "usage: palette [next|prev]"; }
if (args[0] == "NEXT") { if (args[0] == "NEXT") {
Screen::get()->nextPalette(); Screen::get()->nextPalette();
return "Palette: " + Options::video.palette; return "Palette: " + Options::video.palette;
@@ -371,7 +372,7 @@ static const std::vector<ConsoleCommand> COMMANDS = {
Screen::get()->previousPalette(); Screen::get()->previousPalette();
return "Palette: " + Options::video.palette; return "Palette: " + Options::video.palette;
} }
return "Usage: PALETTE [NEXT|PREV]"; return "usage: palette [next|prev]";
}}, }},
#ifdef _DEBUG #ifdef _DEBUG
@@ -390,7 +391,7 @@ static const std::vector<ConsoleCommand> COMMANDS = {
GameControl::toggle_debug_mode(); GameControl::toggle_debug_mode();
return "Debug mode OFF"; return "Debug mode OFF";
} }
if (!args.empty()) { return "Usage: DEBUG [ON|OFF]"; } if (!args.empty()) { return "usage: debug [on|off]"; }
GameControl::toggle_debug_mode(); GameControl::toggle_debug_mode();
return std::string("Debug mode ") + (Debug::get()->isEnabled() ? "ON" : "OFF"); return std::string("Debug mode ") + (Debug::get()->isEnabled() ? "ON" : "OFF");
}}, }},
@@ -398,7 +399,7 @@ static const std::vector<ConsoleCommand> COMMANDS = {
// ROOM <num>|NEXT|PREV — Cambia a la habitación indicada (1-60); solo en escena GAME // ROOM <num>|NEXT|PREV — Cambia a la habitación indicada (1-60); solo en escena GAME
{.keyword = "ROOM", .execute = [](const std::vector<std::string>& args) -> std::string { {.keyword = "ROOM", .execute = [](const std::vector<std::string>& args) -> std::string {
if (SceneManager::current != SceneManager::Scene::GAME) { return "Only available in GAME scene"; } if (SceneManager::current != SceneManager::Scene::GAME) { return "Only available in GAME scene"; }
if (args.empty()) { return "Usage: ROOM <1-60>|NEXT|PREV"; } if (args.empty()) { return "usage: room <1-60>|next|prev"; }
int num = 0; int num = 0;
if (args[0] == "NEXT" || args[0] == "PREV") { if (args[0] == "NEXT" || args[0] == "PREV") {
if (!GameControl::get_current_room) { return "Game not initialized"; } if (!GameControl::get_current_room) { return "Game not initialized"; }
@@ -410,7 +411,7 @@ static const std::vector<ConsoleCommand> COMMANDS = {
} else { } else {
try { try {
num = std::stoi(args[0]); num = std::stoi(args[0]);
} catch (...) { return "Usage: ROOM <1-60>|NEXT|PREV"; } } catch (...) { return "usage: room <1-60>|next|prev"; }
} }
if (num < 1 || num > 60) { return "Room must be between 1 and 60"; } if (num < 1 || num > 60) { return "Room must be between 1 and 60"; }
char buf[16]; char buf[16];
@@ -434,9 +435,9 @@ static const std::vector<ConsoleCommand> COMMANDS = {
Notifier::get()->show({Locale::get()->get("achievements.header"), Locale::get()->get("achievements.c1")}, Notifier::Style::CHEEVO, -1, false); // NOLINT(readability-static-accessed-through-instance) Notifier::get()->show({Locale::get()->get("achievements.header"), Locale::get()->get("achievements.c1")}, Notifier::Style::CHEEVO, -1, false); // NOLINT(readability-static-accessed-through-instance)
return "Cheevo notification shown"; return "Cheevo notification shown";
} }
if (args.empty() || args[0] != "INFO") { return "Usage: SHOW [INFO|NOTIFICATION|CHEEVO]"; } if (args.empty() || args[0] != "INFO") { return "usage: show [info|notification|cheevo]"; }
#else #else
if (args.empty() || args[0] != "INFO") { return "Usage: SHOW [INFO]"; } if (args.empty() || args[0] != "INFO") { return "usage: show [info]"; }
#endif #endif
if (RenderInfo::get()->isActive()) { return "Info overlay already ON"; } if (RenderInfo::get()->isActive()) { return "Info overlay already ON"; }
RenderInfo::get()->toggle(); RenderInfo::get()->toggle();
@@ -445,7 +446,7 @@ static const std::vector<ConsoleCommand> COMMANDS = {
// HIDE INFO — disponible en Release // HIDE INFO — disponible en Release
{.keyword = "HIDE", .execute = [](const std::vector<std::string>& args) -> std::string { {.keyword = "HIDE", .execute = [](const std::vector<std::string>& args) -> std::string {
if (args.empty() || args[0] != "INFO") { return "Usage: HIDE [INFO]"; } if (args.empty() || args[0] != "INFO") { return "usage: hide [info]"; }
if (!RenderInfo::get()->isActive()) { return "Info overlay already OFF"; } if (!RenderInfo::get()->isActive()) { return "Info overlay already OFF"; }
RenderInfo::get()->toggle(); RenderInfo::get()->toggle();
return "Info overlay OFF"; return "Info overlay OFF";
@@ -454,11 +455,11 @@ static const std::vector<ConsoleCommand> COMMANDS = {
// CHEAT <subcomando> — Trucos de juego; solo en escena GAME; no aparece en ayuda en builds Release // CHEAT <subcomando> — Trucos de juego; solo en escena GAME; no aparece en ayuda en builds Release
{.keyword = "CHEAT", .execute = [](const std::vector<std::string>& args) -> std::string { {.keyword = "CHEAT", .execute = [](const std::vector<std::string>& args) -> std::string {
if (SceneManager::current != SceneManager::Scene::GAME) { return "Only available in GAME scene"; } if (SceneManager::current != SceneManager::Scene::GAME) { return "Only available in GAME scene"; }
if (args.empty()) { return "Usage: CHEAT [INFINITE LIVES|INVINCIBILITY|OPEN THE JAIL|CLOSE THE JAIL]"; } if (args.empty()) { return "usage: cheat [infinite lives|invincibility|open the jail|close the jail]"; }
// CHEAT INFINITE LIVES [ON|OFF] // CHEAT INFINITE LIVES [ON|OFF]
if (args[0] == "INFINITE") { if (args[0] == "INFINITE") {
if (args.size() < 2 || args[1] != "LIVES") { return "Usage: CHEAT INFINITE LIVES [ON|OFF]"; } if (args.size() < 2 || args[1] != "LIVES") { return "usage: cheat infinite lives [on|off]"; }
auto& cheat = Options::cheats.infinite_lives; auto& cheat = Options::cheats.infinite_lives;
using State = Options::Cheat::State; using State = Options::Cheat::State;
const std::vector<std::string> REST(args.begin() + 2, args.end()); const std::vector<std::string> REST(args.begin() + 2, args.end());
@@ -471,7 +472,7 @@ static const std::vector<ConsoleCommand> COMMANDS = {
if (cheat == State::DISABLED) { return "Infinite lives already OFF"; } if (cheat == State::DISABLED) { return "Infinite lives already OFF"; }
cheat = State::DISABLED; cheat = State::DISABLED;
} else { } else {
return "Usage: CHEAT INFINITE LIVES [ON|OFF]"; return "usage: cheat infinite lives [on|off]";
} }
if (GameControl::refresh_player_color) { GameControl::refresh_player_color(); } if (GameControl::refresh_player_color) { GameControl::refresh_player_color(); }
return std::string("Infinite lives ") + (cheat == State::ENABLED ? "ON" : "OFF"); return std::string("Infinite lives ") + (cheat == State::ENABLED ? "ON" : "OFF");
@@ -490,7 +491,7 @@ static const std::vector<ConsoleCommand> COMMANDS = {
if (cheat == State::DISABLED) { return "Invincibility already OFF"; } if (cheat == State::DISABLED) { return "Invincibility already OFF"; }
cheat = State::DISABLED; cheat = State::DISABLED;
} else { } else {
return "Usage: CHEAT INVINCIBILITY [ON|OFF]"; return "usage: cheat invincibility [on|off]";
} }
if (GameControl::refresh_player_color) { GameControl::refresh_player_color(); } if (GameControl::refresh_player_color) { GameControl::refresh_player_color(); }
return std::string("Invincibility ") + (cheat == State::ENABLED ? "ON" : "OFF"); return std::string("Invincibility ") + (cheat == State::ENABLED ? "ON" : "OFF");
@@ -498,7 +499,7 @@ static const std::vector<ConsoleCommand> COMMANDS = {
// CHEAT OPEN THE JAIL // CHEAT OPEN THE JAIL
if (args[0] == "OPEN") { if (args[0] == "OPEN") {
if (args.size() < 3 || args[1] != "THE" || args[2] != "JAIL") { return "Usage: CHEAT OPEN THE JAIL"; } if (args.size() < 3 || args[1] != "THE" || args[2] != "JAIL") { return "usage: cheat open the jail"; }
if (Options::cheats.jail_is_open == Options::Cheat::State::ENABLED) { return "Jail already open"; } if (Options::cheats.jail_is_open == Options::Cheat::State::ENABLED) { return "Jail already open"; }
Options::cheats.jail_is_open = Options::Cheat::State::ENABLED; Options::cheats.jail_is_open = Options::Cheat::State::ENABLED;
return "Jail opened"; return "Jail opened";
@@ -506,13 +507,13 @@ static const std::vector<ConsoleCommand> COMMANDS = {
// CHEAT CLOSE THE JAIL // CHEAT CLOSE THE JAIL
if (args[0] == "CLOSE") { if (args[0] == "CLOSE") {
if (args.size() < 3 || args[1] != "THE" || args[2] != "JAIL") { return "Usage: CHEAT CLOSE THE JAIL"; } if (args.size() < 3 || args[1] != "THE" || args[2] != "JAIL") { return "usage: cheat close the jail"; }
if (Options::cheats.jail_is_open == Options::Cheat::State::DISABLED) { return "Jail already closed"; } if (Options::cheats.jail_is_open == Options::Cheat::State::DISABLED) { return "Jail already closed"; }
Options::cheats.jail_is_open = Options::Cheat::State::DISABLED; Options::cheats.jail_is_open = Options::Cheat::State::DISABLED;
return "Jail closed"; return "Jail closed";
} }
return "Usage: CHEAT [INFINITE LIVES|INVINCIBILITY|OPEN THE JAIL|CLOSE THE JAIL]"; return "usage: cheat [infinite lives|invincibility|open the jail|close the jail]";
}}, }},
// SET PLAYER SKIN <1|2> — Cambia la skin del jugador (disponible en todos los builds, GAME) // SET PLAYER SKIN <1|2> — Cambia la skin del jugador (disponible en todos los builds, GAME)
@@ -526,7 +527,7 @@ static const std::vector<ConsoleCommand> COMMANDS = {
try { try {
num = std::stoi(args[2]); num = std::stoi(args[2]);
} catch (...) {} } catch (...) {}
if (num < 1 || num > 2) { return "Usage: SET PLAYER SKIN <1|2>"; } if (num < 1 || num > 2) { return "usage: set player skin <1|2>"; }
if (!GameControl::change_player_skin) { return "Game not initialized"; } if (!GameControl::change_player_skin) { return "Game not initialized"; }
GameControl::change_player_skin(num); GameControl::change_player_skin(num);
return "Player skin: " + std::to_string(num); return "Player skin: " + std::to_string(num);
@@ -571,23 +572,23 @@ static const std::vector<ConsoleCommand> COMMANDS = {
// SET ITEMS <0-200> — Fija el contador de items recogidos // SET ITEMS <0-200> — Fija el contador de items recogidos
if (args[0] == "ITEMS") { if (args[0] == "ITEMS") {
if (args.size() < 2) { return "Usage: SET ITEMS <0-200>"; } if (args.size() < 2) { return "usage: set items <0-200>"; }
int count = 0; int count = 0;
try { try {
count = std::stoi(args[1]); count = std::stoi(args[1]);
} catch (...) { return "Usage: SET ITEMS <0-200>"; } } catch (...) { return "usage: set items <0-200>"; }
if (count < 0 || count > 200) { return "Items must be between 0 and 200"; } if (count < 0 || count > 200) { return "Items must be between 0 and 200"; }
if (!GameControl::set_items) { return "Game not initialized"; } if (!GameControl::set_items) { return "Game not initialized"; }
GameControl::set_items(count); GameControl::set_items(count);
return "Items: " + std::to_string(count); return "Items: " + std::to_string(count);
} }
if (args.empty() || args[0] != "INITIAL") { return "Usage: SET INITIAL [ROOM|POS|SCENE] | SET ITEMS <0-200> | SET PLAYER SKIN <1|2>"; } if (args.empty() || args[0] != "INITIAL") { return "usage: set initial [room|pos|scene] | set items <0-200> | set player skin <1|2>"; }
const bool DO_ROOM = args.size() == 1 || (args.size() >= 2 && args[1] == "ROOM"); const bool DO_ROOM = args.size() == 1 || (args.size() >= 2 && args[1] == "ROOM");
const bool DO_POS = args.size() == 1 || (args.size() >= 2 && args[1] == "POS"); const bool DO_POS = args.size() == 1 || (args.size() >= 2 && args[1] == "POS");
if (!DO_ROOM && !DO_POS) { return "Usage: SET INITIAL [ROOM|POS|SCENE]"; } if (!DO_ROOM && !DO_POS) { return "usage: set initial [room|pos|scene]"; }
if (!GameControl::set_initial_room || !GameControl::set_initial_pos) { return "Game not initialized"; } if (!GameControl::set_initial_room || !GameControl::set_initial_pos) { return "Game not initialized"; }
std::string result; std::string result;
@@ -598,7 +599,7 @@ static const std::vector<ConsoleCommand> COMMANDS = {
} }
return result; return result;
#else #else
return "Usage: SET PLAYER SKIN <1|2>"; return "usage: set player skin <1|2>";
#endif #endif
}}, }},
@@ -606,7 +607,7 @@ static const std::vector<ConsoleCommand> COMMANDS = {
// SCENE [LOGO|LOADING|TITLE|CREDITS|GAME|ENDING|ENDING2|RESTART] — Cambiar o reiniciar escena; solo en Debug // SCENE [LOGO|LOADING|TITLE|CREDITS|GAME|ENDING|ENDING2|RESTART] — Cambiar o reiniciar escena; solo en Debug
{.keyword = "SCENE", .execute = [](const std::vector<std::string>& args) -> std::string { {.keyword = "SCENE", .execute = [](const std::vector<std::string>& args) -> std::string {
if (Options::kiosk.enabled) { return "Not allowed in kiosk mode"; } if (Options::kiosk.enabled) { return "Not allowed in kiosk mode"; }
if (args.empty()) { return "Usage: SCENE [LOGO|LOADING|TITLE|CREDITS|GAME|ENDING|ENDING2|RESTART]"; } if (args.empty()) { return "usage: scene [logo|loading|title|credits|game|ending|ending2|restart]"; }
// RESTART: reinicia la escena actual (funciona desde cualquier escena) // RESTART: reinicia la escena actual (funciona desde cualquier escena)
if (args[0] == "RESTART") { if (args[0] == "RESTART") {
@@ -641,7 +642,8 @@ static const std::vector<ConsoleCommand> COMMANDS = {
{.keyword = "RESTART", .execute = [](const std::vector<std::string>&) -> std::string { {.keyword = "RESTART", .execute = [](const std::vector<std::string>&) -> std::string {
SceneManager::current = SceneManager::Scene::LOGO; SceneManager::current = SceneManager::Scene::LOGO;
return "Restarting..."; return "Restarting...";
}}, },
.instant = true},
// KIOSK [ON|OFF PLEASE|PLEASE] — Modo kiosko // KIOSK [ON|OFF PLEASE|PLEASE] — Modo kiosko
{.keyword = "KIOSK", .execute = [](const std::vector<std::string>& args) -> std::string { {.keyword = "KIOSK", .execute = [](const std::vector<std::string>& args) -> std::string {
@@ -660,7 +662,7 @@ static const std::vector<ConsoleCommand> COMMANDS = {
if (!Options::video.fullscreen) { Screen::get()->toggleVideoMode(); } if (!Options::video.fullscreen) { Screen::get()->toggleVideoMode(); }
return "Kiosk mode ON"; return "Kiosk mode ON";
} }
return "Usage: KIOSK [ON]"; return "usage: kiosk [on]";
}}, }},
// AUDIO [ON|OFF|VOL <0-100>] — Audio maestro (estado + volumen) // AUDIO [ON|OFF|VOL <0-100>] — Audio maestro (estado + volumen)
@@ -689,9 +691,9 @@ static const std::vector<ConsoleCommand> COMMANDS = {
Options::audio.volume = static_cast<float>(VAL) / 100.0F; Options::audio.volume = static_cast<float>(VAL) / 100.0F;
Audio::get()->enable(Options::audio.enabled); Audio::get()->enable(Options::audio.enabled);
return "Audio vol:" + std::to_string(VAL); return "Audio vol:" + std::to_string(VAL);
} catch (...) { return "Usage: AUDIO VOL <0-100>"; } } catch (...) { return "usage: audio vol <0-100>"; }
} }
return "Usage: AUDIO [ON|OFF|VOL N]"; return "usage: audio [on|off|vol n]";
}}, }},
// MUSIC [ON|OFF|VOL <0-100>] — Volumen e interruptor de música // MUSIC [ON|OFF|VOL <0-100>] — Volumen e interruptor de música
@@ -724,9 +726,9 @@ static const std::vector<ConsoleCommand> COMMANDS = {
Audio::get()->setMusicVolume(Options::audio.music.volume); Audio::get()->setMusicVolume(Options::audio.music.volume);
} }
return "Music vol:" + std::to_string(VAL); return "Music vol:" + std::to_string(VAL);
} catch (...) { return "Usage: MUSIC VOL <0-100>"; } } catch (...) { return "usage: music vol <0-100>"; }
} }
return "Usage: MUSIC [ON|OFF|VOL N]"; return "usage: music [on|off|vol n]";
}}, }},
// SOUND [ON|OFF|VOL <0-100>] — Volumen e interruptor de efectos de sonido // SOUND [ON|OFF|VOL <0-100>] — Volumen e interruptor de efectos de sonido
@@ -759,9 +761,9 @@ static const std::vector<ConsoleCommand> COMMANDS = {
Audio::get()->setSoundVolume(Options::audio.sound.volume); Audio::get()->setSoundVolume(Options::audio.sound.volume);
} }
return "Sound vol:" + std::to_string(VAL); return "Sound vol:" + std::to_string(VAL);
} catch (...) { return "Usage: SOUND VOL <0-100>"; } } catch (...) { return "usage: sound vol <0-100>"; }
} }
return "Usage: SOUND [ON|OFF|VOL N]"; return "usage: sound [on|off|vol n]";
}}, }},
// EXIT / QUIT — Cerrar la aplicacion (bloqueado en kiosk) // EXIT / QUIT — Cerrar la aplicacion (bloqueado en kiosk)
@@ -771,14 +773,16 @@ static const std::vector<ConsoleCommand> COMMANDS = {
} }
SceneManager::current = SceneManager::Scene::QUIT; SceneManager::current = SceneManager::Scene::QUIT;
return "Quitting..."; return "Quitting...";
}}, },
.instant = true},
{.keyword = "QUIT", .execute = [](const std::vector<std::string>& args) -> std::string { {.keyword = "QUIT", .execute = [](const std::vector<std::string>& args) -> std::string {
if (Options::kiosk.enabled && (args.empty() || args[0] != "PLEASE")) { if (Options::kiosk.enabled && (args.empty() || args[0] != "PLEASE")) {
return "Not allowed in kiosk mode"; return "Not allowed in kiosk mode";
} }
SceneManager::current = SceneManager::Scene::QUIT; SceneManager::current = SceneManager::Scene::QUIT;
return "Quitting..."; return "Quitting...";
}}, },
.instant = true},
// SIZE — Devuelve el tamaño actual de la ventana en píxeles // SIZE — Devuelve el tamaño actual de la ventana en píxeles
{.keyword = "SIZE", .execute = [](const std::vector<std::string>&) -> std::string { {.keyword = "SIZE", .execute = [](const std::vector<std::string>&) -> std::string {
@@ -793,25 +797,26 @@ static const std::vector<ConsoleCommand> COMMANDS = {
printHelp(); printHelp();
std::string result = std::string result =
"Commands:\n" "Commands:\n"
"fullscreen, zoom, intscale, vsync, driver, palette, audio, music, sound, set, restart, kiosk, exit, quit, show, hide, size, help\n" "fullscreen, zoom, intscale, vsync, driver, palette, audio, music, sound, set, restart, kiosk, exit, quit, show, hide, size, help\n";
"-- more info on the terminal";
#ifdef _DEBUG #ifdef _DEBUG
result += "\n[debug] debug room scene"; result +=
result += "\ncheat"; "\nDebug commands:\n"
"debug, room, scene, cheat\n";
#endif #endif
result += "-- more info on the terminal";
return result; return result;
}}, }},
{.keyword = "?", .execute = [](const std::vector<std::string>&) -> std::string { {.keyword = "?", .execute = [](const std::vector<std::string>&) -> std::string {
printHelp(); printHelp();
std::string result = std::string result =
"Commands:\n" "Commands:\n"
"fullscreen, zoom, intscale, vsync, driver, palette, audio, music, sound, set, restart, kiosk, exit, quit, show, hide, size, help\n" "fullscreen, zoom, intscale, vsync, driver, palette, audio, music, sound, set, restart, kiosk, exit, quit, show, hide, size, help\n";
"-- more info on the terminal";
#ifdef _DEBUG #ifdef _DEBUG
result += "\n[debug] debug room scene"; result +=
result += "\ncheat"; "\nDebug commands:\n"
"debug, room, scene, cheat\n";
#endif #endif
result += "-- more info on the terminal";
return result; return result;
}}, }},
}; };
@@ -1009,6 +1014,9 @@ void Console::update(float delta_time) {
if (y_ <= -height_) { if (y_ <= -height_) {
y_ = -height_; y_ = -height_;
status_ = Status::HIDDEN; status_ = Status::HIDDEN;
// Resetear el mensaje una vez completamente oculta
msg_lines_ = {std::string(CONSOLE_NAME) + " " + std::string(CONSOLE_VERSION)};
target_height_ = calcTargetHeight(static_cast<int>(msg_lines_.size()));
} }
break; break;
} }
@@ -1053,9 +1061,8 @@ void Console::toggle() {
if (on_toggle) { on_toggle(true); } if (on_toggle) { on_toggle(true); }
break; break;
case Status::ACTIVE: case Status::ACTIVE:
// Al cerrar: resetear a 1 línea para el próximo ciclo; cerrar con la altura actual // Al cerrar: mantener el texto visible hasta que esté completamente oculta
status_ = Status::VANISHING; status_ = Status::VANISHING;
msg_lines_ = {std::string(CONSOLE_NAME) + " " + std::string(CONSOLE_VERSION)};
target_height_ = height_; // No animar durante VANISHING target_height_ = height_; // No animar durante VANISHING
history_index_ = -1; history_index_ = -1;
saved_input_.clear(); saved_input_.clear();
@@ -1132,9 +1139,11 @@ void Console::processCommand() {
const std::vector<std::string> ARGS(TOKENS.begin() + 1, TOKENS.end()); const std::vector<std::string> ARGS(TOKENS.begin() + 1, TOKENS.end());
std::string result; std::string result;
bool found = false; bool found = false;
bool instant = false;
for (const auto& command : COMMANDS) { for (const auto& command : COMMANDS) {
if (command.keyword == cmd) { if (command.keyword == cmd) {
result = command.execute(ARGS); result = command.execute(ARGS);
instant = command.instant;
found = true; found = true;
break; break;
} }
@@ -1147,8 +1156,14 @@ void Console::processCommand() {
// Actualizar la altura objetivo para animar el resize // Actualizar la altura objetivo para animar el resize
target_height_ = calcTargetHeight(static_cast<int>(msg_lines_.size())); target_height_ = calcTargetHeight(static_cast<int>(msg_lines_.size()));
// Reiniciar el typewriter para revelar la respuesta letra a letra // Typewriter: instantáneo si el comando lo requiere, letra a letra si no
typewriter_chars_ = 0; if (instant) {
int total = 0;
for (const auto& l : msg_lines_) { total += static_cast<int>(l.size()); }
typewriter_chars_ = total;
} else {
typewriter_chars_ = 0;
}
typewriter_timer_ = 0.0F; typewriter_timer_ = 0.0F;
} }
} }

View File

@@ -64,9 +64,9 @@ class Console {
~Console() = default; ~Console() = default;
// Métodos privados // Métodos privados
void buildSurface(); // Crea la Surface con el aspecto visual void buildSurface(); // Crea la Surface con el aspecto visual
void redrawText(); // Redibuja el texto dinámico (msg + input + cursor) void redrawText(); // Redibuja el texto dinámico (msg + input + cursor)
void processCommand(); // Procesa el comando introducido por el usuario void processCommand(); // Procesa el comando introducido por el usuario
[[nodiscard]] auto wrapText(const std::string& text) const -> std::vector<std::string>; // Word-wrap por ancho en píxeles [[nodiscard]] auto wrapText(const std::string& text) const -> std::vector<std::string>; // Word-wrap por ancho en píxeles
// Objetos de renderizado // Objetos de renderizado
@@ -86,12 +86,12 @@ class Console {
bool cursor_visible_{true}; bool cursor_visible_{true};
// Efecto typewriter // Efecto typewriter
int typewriter_chars_{0}; // Caracteres de msg_lines_ actualmente visibles int typewriter_chars_{0}; // Caracteres de msg_lines_ actualmente visibles
float typewriter_timer_{0.0F}; float typewriter_timer_{0.0F};
// Animación de altura dinámica // Animación de altura dinámica
float target_height_{0.0F}; // Altura objetivo (según número de líneas de mensaje) float target_height_{0.0F}; // Altura objetivo (según número de líneas de mensaje)
int notifier_offset_applied_{0}; // Acumulador del offset enviado al Notifier int notifier_offset_applied_{0}; // Acumulador del offset enviado al Notifier
// Historial de comandos (navegable con flechas arriba/abajo) // Historial de comandos (navegable con flechas arriba/abajo)
std::deque<std::string> history_; std::deque<std::string> history_;