neteja cppcheck (105 → 0)
This commit is contained in:
@@ -265,13 +265,13 @@ inline JA_Music_t* JA_LoadMusic(const Uint8* buffer, Uint32 length) {
|
||||
auto* music = new JA_Music_t();
|
||||
music->ogg_data.assign(buffer, buffer + length);
|
||||
|
||||
int error = 0;
|
||||
int err_code = 0;
|
||||
music->vorbis = stb_vorbis_open_memory(music->ogg_data.data(),
|
||||
static_cast<int>(length),
|
||||
&error,
|
||||
&err_code,
|
||||
nullptr);
|
||||
if (!music->vorbis) {
|
||||
std::cout << "JA_LoadMusic: stb_vorbis_open_memory failed (error " << error << ")" << '\n';
|
||||
std::cout << "JA_LoadMusic: stb_vorbis_open_memory failed (error " << err_code << ")" << '\n';
|
||||
delete music;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "core/input/define_buttons.hpp"
|
||||
|
||||
#include <algorithm> // Para __all_of_fn, all_of
|
||||
#include <algorithm> // Para __all_of_fn, all_of, ranges::transform
|
||||
#include <iterator> // Para back_inserter
|
||||
#include <memory> // Para unique_ptr, allocator, shared_ptr, operator==, make_unique
|
||||
|
||||
#include "core/input/input.hpp" // Para Input
|
||||
@@ -16,10 +17,9 @@ DefineButtons::DefineButtons()
|
||||
: input_(Input::get()) {
|
||||
clearButtons();
|
||||
|
||||
auto gamepads = input_->getGamepads();
|
||||
for (const auto& gamepad : gamepads) {
|
||||
controller_names_.emplace_back(Input::getControllerName(gamepad));
|
||||
}
|
||||
const auto gamepads = input_->getGamepads();
|
||||
controller_names_.reserve(gamepads.size());
|
||||
std::ranges::transform(gamepads, std::back_inserter(controller_names_), Input::getControllerName);
|
||||
|
||||
// Crear la ventana de mensaje
|
||||
WindowMessage::Config config(param.service_menu.window_message);
|
||||
|
||||
+24
-70
@@ -118,53 +118,22 @@ auto Input::checkAction(Action action, bool repeat, bool check_keyboard, const s
|
||||
|
||||
// Comprueba si hay almenos una acción activa
|
||||
auto Input::checkAnyInput(bool check_keyboard, const std::shared_ptr<Gamepad>& gamepad) -> bool {
|
||||
// Obtenemos el número total de acciones posibles para iterar sobre ellas.
|
||||
const auto JUST_PRESSED = [](const auto& pair) { return pair.second.just_pressed; };
|
||||
|
||||
// --- Comprobación del Teclado ---
|
||||
if (check_keyboard) {
|
||||
for (const auto& pair : keyboard_.bindings) {
|
||||
// Simplemente leemos el estado pre-calculado por Input::update().
|
||||
// Ya no se llama a SDL_GetKeyboardState ni se modifica el estado '.active'.
|
||||
if (pair.second.just_pressed) {
|
||||
return true; // Se encontró una acción recién pulsada.
|
||||
}
|
||||
}
|
||||
if (check_keyboard && std::ranges::any_of(keyboard_.bindings, JUST_PRESSED)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// --- Comprobación del Mando ---
|
||||
// Comprobamos si hay mandos y si el índice solicitado es válido.
|
||||
if (gamepad != nullptr) {
|
||||
// Iteramos sobre todas las acciones, no sobre el número de mandos.
|
||||
for (const auto& pair : gamepad->bindings) {
|
||||
// Leemos el estado pre-calculado para el mando y la acción específicos.
|
||||
if (pair.second.just_pressed) {
|
||||
return true; // Se encontró una acción recién pulsada en el mando.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Si llegamos hasta aquí, no se detectó ninguna nueva pulsación.
|
||||
return false;
|
||||
return gamepad != nullptr && std::ranges::any_of(gamepad->bindings, JUST_PRESSED);
|
||||
}
|
||||
|
||||
// Comprueba si hay algún botón pulsado
|
||||
auto Input::checkAnyButton(bool repeat) -> bool {
|
||||
// Solo comprueba los botones definidos previamente
|
||||
for (auto bi : BUTTON_INPUTS) {
|
||||
// Comprueba el teclado
|
||||
if (checkAction(bi, repeat, CHECK_KEYBOARD)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Comprueba los mandos
|
||||
for (const auto& gamepad : gamepads_) {
|
||||
if (checkAction(bi, repeat, DO_NOT_CHECK_KEYBOARD, gamepad)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return std::ranges::any_of(BUTTON_INPUTS, [this, repeat](auto bi) {
|
||||
if (checkAction(bi, repeat, CHECK_KEYBOARD)) { return true; }
|
||||
return std::ranges::any_of(gamepads_, [this, bi, repeat](const auto& gamepad) {
|
||||
return checkAction(bi, repeat, DO_NOT_CHECK_KEYBOARD, gamepad);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Comprueba si hay algun mando conectado
|
||||
@@ -178,9 +147,8 @@ auto Input::getControllerName(const std::shared_ptr<Gamepad>& gamepad) -> std::s
|
||||
// Obtiene la lista de nombres de mandos
|
||||
auto Input::getControllerNames() const -> std::vector<std::string> {
|
||||
std::vector<std::string> names;
|
||||
for (const auto& gamepad : gamepads_) {
|
||||
names.push_back(gamepad->name);
|
||||
}
|
||||
names.reserve(gamepads_.size());
|
||||
std::ranges::transform(gamepads_, std::back_inserter(names), [](const auto& gamepad) { return gamepad->name; });
|
||||
return names;
|
||||
}
|
||||
|
||||
@@ -189,21 +157,15 @@ auto Input::getNumGamepads() const -> int { return gamepads_.size(); }
|
||||
|
||||
// Obtiene el gamepad a partir de un event.id
|
||||
auto Input::getGamepad(SDL_JoystickID id) const -> std::shared_ptr<Input::Gamepad> {
|
||||
for (const auto& gamepad : gamepads_) {
|
||||
if (gamepad->instance_id == id) {
|
||||
return gamepad;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
const auto it = std::ranges::find_if(gamepads_,
|
||||
[id](const auto& gamepad) { return gamepad->instance_id == id; });
|
||||
return it != gamepads_.end() ? *it : nullptr;
|
||||
}
|
||||
|
||||
auto Input::getGamepadByName(const std::string& name) const -> std::shared_ptr<Input::Gamepad> {
|
||||
for (const auto& gamepad : gamepads_) {
|
||||
if (gamepad && gamepad->name == name) {
|
||||
return gamepad;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
const auto it = std::ranges::find_if(gamepads_,
|
||||
[&name](const auto& gamepad) { return gamepad && gamepad->name == name; });
|
||||
return it != gamepads_.end() ? *it : nullptr;
|
||||
}
|
||||
|
||||
// Obtiene el SDL_GamepadButton asignado a un action
|
||||
@@ -359,7 +321,7 @@ void Input::resetInputStates() {
|
||||
key.second.just_pressed = false;
|
||||
}
|
||||
// Resetear todos los ControllerBindings.active a false
|
||||
for (auto& gamepad : gamepads_) {
|
||||
for (const auto& gamepad : gamepads_) {
|
||||
for (auto& binding : gamepad->bindings) {
|
||||
binding.second.is_held = false;
|
||||
binding.second.just_pressed = false;
|
||||
@@ -568,19 +530,11 @@ auto Input::findAvailableGamepadByName(const std::string& gamepad_name) -> std::
|
||||
}
|
||||
|
||||
// Buscar por nombre
|
||||
for (const auto& gamepad : gamepads_) {
|
||||
if (gamepad && gamepad->name == gamepad_name) {
|
||||
return gamepad;
|
||||
}
|
||||
}
|
||||
auto by_name = std::ranges::find_if(gamepads_,
|
||||
[&gamepad_name](const auto& gamepad) { return gamepad && gamepad->name == gamepad_name; });
|
||||
if (by_name != gamepads_.end()) { return *by_name; }
|
||||
|
||||
// Si no se encuentra por nombre, devolver el primer gamepad válido
|
||||
for (const auto& gamepad : gamepads_) {
|
||||
if (gamepad) {
|
||||
return gamepad;
|
||||
}
|
||||
}
|
||||
|
||||
// Si llegamos aquí, no hay gamepads válidos
|
||||
return nullptr;
|
||||
auto first_valid = std::ranges::find_if(gamepads_, [](const auto& gamepad) { return gamepad != nullptr; });
|
||||
return first_valid != gamepads_.end() ? *first_valid : nullptr;
|
||||
}
|
||||
@@ -32,7 +32,7 @@ class Input {
|
||||
bool is_held; // Está pulsada ahora mismo
|
||||
bool just_pressed; // Se acaba de pulsar en este fotograma
|
||||
|
||||
KeyState(Uint8 scancode = 0, bool is_held = false, bool just_pressed = false)
|
||||
explicit KeyState(Uint8 scancode = 0, bool is_held = false, bool just_pressed = false)
|
||||
: scancode(scancode),
|
||||
is_held(is_held),
|
||||
just_pressed(just_pressed) {}
|
||||
@@ -45,7 +45,7 @@ class Input {
|
||||
bool axis_active; // Estado del eje
|
||||
bool trigger_active{false}; // Estado del trigger como botón digital
|
||||
|
||||
ButtonState(int btn = static_cast<int>(SDL_GAMEPAD_BUTTON_INVALID), bool is_held = false, bool just_pressed = false, bool axis_act = false)
|
||||
explicit ButtonState(int btn = static_cast<int>(SDL_GAMEPAD_BUTTON_INVALID), bool is_held = false, bool just_pressed = false, bool axis_act = false)
|
||||
: button(btn),
|
||||
is_held(is_held),
|
||||
just_pressed(just_pressed),
|
||||
@@ -115,7 +115,7 @@ class Input {
|
||||
return s;
|
||||
}
|
||||
|
||||
Gamepad(SDL_Gamepad* gamepad)
|
||||
explicit Gamepad(SDL_Gamepad* gamepad)
|
||||
: pad(gamepad),
|
||||
instance_id(SDL_GetJoystickID(SDL_GetGamepadJoystick(gamepad))),
|
||||
name(trimName(SDL_GetGamepadName(gamepad))),
|
||||
@@ -148,7 +148,7 @@ class Input {
|
||||
|
||||
// Reasigna un botón a una acción
|
||||
void rebindAction(Action action, SDL_GamepadButton new_button) {
|
||||
bindings[action] = static_cast<int>(new_button);
|
||||
bindings[action] = ButtonState{static_cast<int>(new_button)};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
// --- Clase PauseManager: maneja el sistema de pausa del juego ---
|
||||
class PauseManager {
|
||||
@@ -48,7 +50,7 @@ class PauseManager {
|
||||
|
||||
// --- Métodos principales ---
|
||||
void setFlag(Source source, bool enable) { // Establece/quita una fuente de pausa específica
|
||||
bool was_paused = isPaused();
|
||||
const bool WAS_PAUSED = isPaused();
|
||||
|
||||
if (enable) {
|
||||
flags_ |= source;
|
||||
@@ -56,7 +58,8 @@ class PauseManager {
|
||||
flags_ &= ~source; // Ahora funciona: Source &= uint8_t
|
||||
}
|
||||
|
||||
if (was_paused != isPaused()) {
|
||||
// cppcheck-suppress knownConditionTrueFalse // false-positive: flags_ ha estat modificat entre les dues crides a isPaused()
|
||||
if (WAS_PAUSED != isPaused()) {
|
||||
notifyPauseChanged();
|
||||
}
|
||||
}
|
||||
@@ -88,30 +91,16 @@ class PauseManager {
|
||||
return "Active";
|
||||
}
|
||||
|
||||
std::vector<std::string> parts;
|
||||
if (hasFlag(Source::PLAYER)) { parts.emplace_back("Player"); }
|
||||
if (hasFlag(Source::SERVICE_MENU)) { parts.emplace_back("ServiceMenu"); }
|
||||
if (hasFlag(Source::FOCUS_LOST)) { parts.emplace_back("FocusLoss"); }
|
||||
|
||||
std::string result = "Paused by: ";
|
||||
bool first = true;
|
||||
|
||||
if (hasFlag(Source::PLAYER)) {
|
||||
if (!first) {
|
||||
result += ", ";
|
||||
}
|
||||
result += "Player";
|
||||
first = false;
|
||||
for (size_t i = 0; i < parts.size(); ++i) {
|
||||
if (i > 0) { result += ", "; }
|
||||
result += parts[i];
|
||||
}
|
||||
if (hasFlag(Source::SERVICE_MENU)) {
|
||||
if (!first) {
|
||||
result += ", ";
|
||||
}
|
||||
result += "ServiceMenu";
|
||||
first = false;
|
||||
}
|
||||
if (hasFlag(Source::FOCUS_LOST)) {
|
||||
if (!first) {
|
||||
result += ", ";
|
||||
}
|
||||
result += "FocusLoss";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
void setCallback(std::function<void(bool)> callback) { // Permite cambiar el callback en runtime
|
||||
|
||||
+14
-28
@@ -1,5 +1,6 @@
|
||||
#include "core/locale/lang.hpp"
|
||||
|
||||
#include <algorithm> // Para ranges::find_if
|
||||
#include <cstddef> // Para size_t
|
||||
#include <exception> // Para exception
|
||||
#include <fstream> // Para basic_ifstream, basic_istream, ifstream
|
||||
@@ -80,35 +81,23 @@ namespace Lang {
|
||||
|
||||
// Obtiene un idioma del vector de idiomas a partir de un código
|
||||
auto getLanguage(Code code) -> Language {
|
||||
for (const auto& lang : languages) {
|
||||
if (lang.code == code) {
|
||||
return lang;
|
||||
}
|
||||
}
|
||||
// Si no se encuentra, devuelve el primero por defecto
|
||||
return languages[0];
|
||||
const auto it = std::ranges::find_if(languages,
|
||||
[code](const auto& lang) { return lang.code == code; });
|
||||
return it != languages.end() ? *it : languages[0];
|
||||
}
|
||||
|
||||
// Devuelve el código de un idioma a partir de un nombre
|
||||
auto getCodeFromName(const std::string& name) -> Code {
|
||||
for (const auto& lang : languages) {
|
||||
if (lang.name == name) {
|
||||
return lang.code;
|
||||
}
|
||||
}
|
||||
// Si no se encuentra, devuelve el primero por defecto
|
||||
return languages[0].code;
|
||||
const auto it = std::ranges::find_if(languages,
|
||||
[&name](const auto& lang) { return lang.name == name; });
|
||||
return it != languages.end() ? it->code : languages[0].code;
|
||||
}
|
||||
|
||||
// Devuelve el nombre de un idioma a partir de un código
|
||||
auto getNameFromCode(Code code) -> std::string {
|
||||
for (const auto& lang : languages) {
|
||||
if (lang.code == code) {
|
||||
return lang.name;
|
||||
}
|
||||
}
|
||||
// Si no se encuentra, devuelve el nombre del primer idioma por defecto
|
||||
return languages[0].name;
|
||||
const auto it = std::ranges::find_if(languages,
|
||||
[code](const auto& lang) { return lang.code == code; });
|
||||
return it != languages.end() ? it->name : languages[0].name;
|
||||
}
|
||||
|
||||
// Actualiza los nombres de los idiomas
|
||||
@@ -155,13 +144,10 @@ namespace Lang {
|
||||
|
||||
// Obtiene una fichero a partir de un lang::Code
|
||||
auto getLanguageFileName(Lang::Code code) -> std::string {
|
||||
for (const auto& lang : languages) {
|
||||
if (lang.code == code) {
|
||||
return Asset::get()->getPath(lang.file_name);
|
||||
}
|
||||
}
|
||||
// Si no se encuentra, devuelve el fichero del primer idioma por defecto
|
||||
return Asset::get()->getPath(languages[0].file_name);
|
||||
const auto it = std::ranges::find_if(languages,
|
||||
[code](const auto& lang) { return lang.code == code; });
|
||||
const auto& file = (it != languages.end()) ? it->file_name : languages[0].file_name;
|
||||
return Asset::get()->getPath(file);
|
||||
}
|
||||
|
||||
// Establece el idioma
|
||||
|
||||
@@ -562,14 +562,13 @@ void Background::createMoonPath() {
|
||||
const int FREEZE_START_INDEX = static_cast<int>(NUM_STEPS * (1.0F - FREEZE_PERCENTAGE));
|
||||
|
||||
for (int i = 0; i < NUM_STEPS; ++i) {
|
||||
double theta = i * STEP;
|
||||
float x = CENTER_X + (RADIUS * cos(theta));
|
||||
float y = CENTER_Y - (RADIUS * sin(theta));
|
||||
|
||||
if (i >= FREEZE_START_INDEX && !moon_path_.empty()) {
|
||||
moon_path_.push_back(moon_path_.back()); // Repite el último punto válido
|
||||
} else {
|
||||
moon_path_.push_back({.x = x, .y = y});
|
||||
const double THETA = i * STEP;
|
||||
const float X = CENTER_X + (RADIUS * cos(THETA));
|
||||
const float Y = CENTER_Y - (RADIUS * sin(THETA));
|
||||
moon_path_.push_back({.x = X, .y = Y});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,8 +28,8 @@ class Background {
|
||||
using ProgressCallback = std::function<void(float)>; // Callback para sincronización
|
||||
|
||||
// --- Constructor y destructor ---
|
||||
Background(float total_progress_to_complete = 6100.0F); // Constructor principal
|
||||
~Background(); // Destructor
|
||||
explicit Background(float total_progress_to_complete = 6100.0F); // Constructor principal
|
||||
~Background(); // Destructor
|
||||
|
||||
// --- Métodos principales ---
|
||||
void update(float delta_time); // Actualiza la lógica del objeto
|
||||
|
||||
@@ -66,7 +66,7 @@ class Screen {
|
||||
[[nodiscard]] auto getText() const -> std::shared_ptr<Text> { return text_; } // Obtiene el puntero al texto de Screen
|
||||
|
||||
// --- Display Monitor getters ---
|
||||
[[nodiscard]] auto getDisplayMonitorName() const -> std::string { return display_monitor_.name; }
|
||||
[[nodiscard]] auto getDisplayMonitorName() const -> const std::string& { return display_monitor_.name; }
|
||||
[[nodiscard]] auto getDisplayMonitorWidth() const -> int { return display_monitor_.width; }
|
||||
[[nodiscard]] auto getDisplayMonitorHeight() const -> int { return display_monitor_.height; }
|
||||
[[nodiscard]] auto getDisplayMonitorRefreshRate() const -> int { return display_monitor_.refresh_rate; }
|
||||
|
||||
@@ -25,12 +25,12 @@ enum class PathCentered { // Centrado del recorrido
|
||||
|
||||
// --- Estructuras ---
|
||||
struct Path { // Define un recorrido para el sprite
|
||||
float start_pos; // Posición inicial
|
||||
float end_pos; // Posición final
|
||||
PathType type; // Tipo de movimiento (horizontal/vertical)
|
||||
float fixed_pos; // Posición fija en el eje contrario
|
||||
float duration_s; // Duración de la animación en segundos
|
||||
float waiting_time_s; // Tiempo de espera una vez en el destino
|
||||
float start_pos = 0.0F; // Posición inicial
|
||||
float end_pos = 0.0F; // Posición final
|
||||
PathType type = PathType::HORIZONTAL; // Tipo de movimiento (horizontal/vertical)
|
||||
float fixed_pos = 0.0F; // Posición fija en el eje contrario
|
||||
float duration_s = 0.0F; // Duración de la animación en segundos
|
||||
float waiting_time_s = 0.0F; // Tiempo de espera una vez en el destino
|
||||
std::function<double(double)> easing_function; // Función de easing
|
||||
float elapsed_time = 0.0F; // Tiempo transcurrido
|
||||
float waiting_elapsed = 0.0F; // Tiempo de espera transcurrido
|
||||
|
||||
@@ -403,9 +403,8 @@ auto Text::loadFile(const std::string& file_path) -> std::shared_ptr<Text::File>
|
||||
file.open(file_path);
|
||||
}
|
||||
|
||||
std::istream& input_stream = using_resource_data ? stream : static_cast<std::istream&>(file);
|
||||
|
||||
if ((using_resource_data && stream.good()) || (!using_resource_data && file.is_open() && file.good())) {
|
||||
std::istream& input_stream = using_resource_data ? stream : static_cast<std::istream&>(file);
|
||||
std::string buffer;
|
||||
|
||||
// Lee los dos primeros valores del fichero
|
||||
|
||||
@@ -39,7 +39,7 @@ class Text {
|
||||
int kerning;
|
||||
|
||||
// Constructor con argumentos por defecto
|
||||
Style(Uint8 flags = 0,
|
||||
explicit Style(Uint8 flags = 0,
|
||||
Color text = Color(),
|
||||
Color shadow = Color(),
|
||||
Uint8 distance = 1,
|
||||
|
||||
@@ -2,12 +2,14 @@
|
||||
|
||||
#include <SDL3/SDL.h> // Para SDL_LogInfo, SDL_LogCategory, SDL_LogError, SDL_SetRenderDrawColor, SDL_EventType, SDL_PollEvent, SDL_RenderFillRect, SDL_RenderRect, SDLK_ESCAPE, SDL_Event
|
||||
|
||||
#include <algorithm> // Para ranges::transform, ranges::find_if
|
||||
#include <array> // Para array
|
||||
#include <cstdlib> // Para exit
|
||||
#include <exception> // Para exception
|
||||
#include <filesystem> // Para exists, path, remove
|
||||
#include <fstream> // Para basic_ofstream, basic_ios, basic_ostream::write, ios, ofstream
|
||||
#include <iostream> // Para std::cout
|
||||
#include <iterator> // Para back_inserter
|
||||
#include <ranges> // Para __find_if_fn, find_if, __find_fn, find
|
||||
#include <stdexcept> // Para runtime_error
|
||||
#include <utility> // Para move
|
||||
@@ -138,40 +140,37 @@ void Resource::loadEssentialTextures() {
|
||||
|
||||
// Inicializa las listas de recursos sin cargar el contenido (modo lazy)
|
||||
void Resource::initResourceLists() {
|
||||
const auto file_to_name = [](const auto& file) { return getFileName(file); };
|
||||
|
||||
// Inicializa lista de sonidos
|
||||
auto sound_list = Asset::get()->getListByType(Asset::Type::SOUND);
|
||||
const auto sound_list = Asset::get()->getListByType(Asset::Type::SOUND);
|
||||
sounds_.clear();
|
||||
for (const auto& file : sound_list) {
|
||||
sounds_.emplace_back(getFileName(file));
|
||||
}
|
||||
sounds_.reserve(sound_list.size());
|
||||
std::ranges::transform(sound_list, std::back_inserter(sounds_), [&](const auto& file) { return ResourceSound(file_to_name(file)); });
|
||||
|
||||
// Inicializa lista de músicas
|
||||
auto music_list = Asset::get()->getListByType(Asset::Type::MUSIC);
|
||||
const auto music_list = Asset::get()->getListByType(Asset::Type::MUSIC);
|
||||
musics_.clear();
|
||||
for (const auto& file : music_list) {
|
||||
musics_.emplace_back(getFileName(file));
|
||||
}
|
||||
musics_.reserve(music_list.size());
|
||||
std::ranges::transform(music_list, std::back_inserter(musics_), [&](const auto& file) { return ResourceMusic(file_to_name(file)); });
|
||||
|
||||
// Inicializa lista de texturas
|
||||
auto texture_list = Asset::get()->getListByType(Asset::Type::BITMAP);
|
||||
const auto texture_list = Asset::get()->getListByType(Asset::Type::BITMAP);
|
||||
textures_.clear();
|
||||
for (const auto& file : texture_list) {
|
||||
textures_.emplace_back(getFileName(file));
|
||||
}
|
||||
textures_.reserve(texture_list.size());
|
||||
std::ranges::transform(texture_list, std::back_inserter(textures_), [&](const auto& file) { return ResourceTexture(file_to_name(file)); });
|
||||
|
||||
// Inicializa lista de ficheros de texto
|
||||
auto text_file_list = Asset::get()->getListByType(Asset::Type::FONT);
|
||||
const auto text_file_list = Asset::get()->getListByType(Asset::Type::FONT);
|
||||
text_files_.clear();
|
||||
for (const auto& file : text_file_list) {
|
||||
text_files_.emplace_back(getFileName(file));
|
||||
}
|
||||
text_files_.reserve(text_file_list.size());
|
||||
std::ranges::transform(text_file_list, std::back_inserter(text_files_), [&](const auto& file) { return ResourceTextFile(file_to_name(file)); });
|
||||
|
||||
// Inicializa lista de animaciones
|
||||
auto animation_list = Asset::get()->getListByType(Asset::Type::ANIMATION);
|
||||
const auto animation_list = Asset::get()->getListByType(Asset::Type::ANIMATION);
|
||||
animations_.clear();
|
||||
for (const auto& file : animation_list) {
|
||||
animations_.emplace_back(getFileName(file));
|
||||
}
|
||||
animations_.reserve(animation_list.size());
|
||||
std::ranges::transform(animation_list, std::back_inserter(animations_), [&](const auto& file) { return ResourceAnimation(file_to_name(file)); });
|
||||
|
||||
// Los demos se cargan directamente sin mostrar progreso (son pocos y pequeños)
|
||||
loadDemoDataQuiet();
|
||||
@@ -192,9 +191,8 @@ void Resource::initResourceLists() {
|
||||
"smb2_grad"};
|
||||
|
||||
texts_.clear();
|
||||
for (const auto& text_name : TEXT_OBJECTS) {
|
||||
texts_.emplace_back(text_name); // Constructor con nullptr por defecto
|
||||
}
|
||||
texts_.reserve(TEXT_OBJECTS.size());
|
||||
std::ranges::transform(TEXT_OBJECTS, std::back_inserter(texts_), [](const auto& text_name) { return ResourceText(text_name); });
|
||||
}
|
||||
|
||||
// Obtiene el sonido a partir de un nombre (con carga perezosa)
|
||||
@@ -336,23 +334,17 @@ auto Resource::loadMusicLazy(const std::string& name) -> JA_Music_t* {
|
||||
}
|
||||
|
||||
auto Resource::loadTextureLazy(const std::string& name) -> std::shared_ptr<Texture> {
|
||||
auto texture_list = Asset::get()->getListByType(Asset::Type::BITMAP);
|
||||
for (const auto& file : texture_list) {
|
||||
if (getFileName(file) == name) {
|
||||
return std::make_shared<Texture>(Screen::get()->getRenderer(), file);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
const auto texture_list = Asset::get()->getListByType(Asset::Type::BITMAP);
|
||||
const auto it = std::ranges::find_if(texture_list,
|
||||
[&name](const auto& file) { return getFileName(file) == name; });
|
||||
return it != texture_list.end() ? std::make_shared<Texture>(Screen::get()->getRenderer(), *it) : nullptr;
|
||||
}
|
||||
|
||||
auto Resource::loadTextFileLazy(const std::string& name) -> std::shared_ptr<Text::File> {
|
||||
auto text_file_list = Asset::get()->getListByType(Asset::Type::FONT);
|
||||
for (const auto& file : text_file_list) {
|
||||
if (getFileName(file) == name) {
|
||||
return Text::loadFile(file);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
const auto text_file_list = Asset::get()->getListByType(Asset::Type::FONT);
|
||||
const auto it = std::ranges::find_if(text_file_list,
|
||||
[&name](const auto& file) { return getFileName(file) == name; });
|
||||
return it != text_file_list.end() ? Text::loadFile(*it) : nullptr;
|
||||
}
|
||||
|
||||
auto Resource::loadTextLazy(const std::string& name) -> std::shared_ptr<Text> {
|
||||
@@ -377,27 +369,22 @@ auto Resource::loadTextLazy(const std::string& name) -> std::shared_ptr<Text> {
|
||||
{.key = "smb2", .texture_file = "smb2.png", .text_file = "smb2.txt"},
|
||||
{.key = "smb2_grad", .texture_file = "smb2_grad.png", .text_file = "smb2.txt"}};
|
||||
|
||||
for (const auto& mapping : TEXT_MAPPINGS) {
|
||||
if (mapping.key == name) {
|
||||
// Cargar las dependencias automáticamente
|
||||
auto texture = getTexture(mapping.texture_file); // Esto cargará la textura si no está cargada
|
||||
auto text_file = getTextFile(mapping.text_file); // Esto cargará el archivo de texto si no está cargado
|
||||
|
||||
if (texture && text_file) {
|
||||
return std::make_shared<Text>(texture, text_file);
|
||||
}
|
||||
}
|
||||
const auto it = std::ranges::find_if(TEXT_MAPPINGS,
|
||||
[&name](const auto& mapping) { return mapping.key == name; });
|
||||
if (it == TEXT_MAPPINGS.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
auto texture = getTexture(it->texture_file); // Esto cargará la textura si no está cargada
|
||||
auto text_file = getTextFile(it->text_file); // Esto cargará el archivo de texto si no está cargado
|
||||
return (texture && text_file) ? std::make_shared<Text>(texture, text_file) : nullptr;
|
||||
}
|
||||
|
||||
auto Resource::loadAnimationLazy(const std::string& name) -> AnimationsFileBuffer {
|
||||
auto animation_list = Asset::get()->getListByType(Asset::Type::ANIMATION);
|
||||
for (const auto& file : animation_list) {
|
||||
if (getFileName(file) == name) {
|
||||
return loadAnimationsFromFile(file);
|
||||
}
|
||||
const auto animation_list = Asset::get()->getListByType(Asset::Type::ANIMATION);
|
||||
const auto it = std::ranges::find_if(animation_list,
|
||||
[&name](const auto& file) { return getFileName(file) == name; });
|
||||
if (it != animation_list.end()) {
|
||||
return loadAnimationsFromFile(*it);
|
||||
}
|
||||
// Si no se encuentra, retorna vector vacío
|
||||
return AnimationsFileBuffer{};
|
||||
@@ -640,14 +627,10 @@ void Resource::createPlayerTextures() {
|
||||
const auto& player = players[player_idx]; // Obtenemos el jugador actual
|
||||
|
||||
// Encontrar el archivo original de la textura
|
||||
std::string texture_file_path;
|
||||
auto texture_list = Asset::get()->getListByType(Asset::Type::BITMAP);
|
||||
for (const auto& file : texture_list) {
|
||||
if (getFileName(file) == player.base_texture) {
|
||||
texture_file_path = file;
|
||||
break;
|
||||
}
|
||||
}
|
||||
const auto texture_list = Asset::get()->getListByType(Asset::Type::BITMAP);
|
||||
const auto it = std::ranges::find_if(texture_list,
|
||||
[&player](const auto& file) { return getFileName(file) == player.base_texture; });
|
||||
const std::string texture_file_path = (it != texture_list.end()) ? *it : std::string{};
|
||||
|
||||
// Crear las 4 texturas con sus respectivas paletas
|
||||
for (int palette_idx = 0; palette_idx < 4; ++palette_idx) {
|
||||
@@ -720,9 +703,9 @@ void Resource::createTextTextures() {
|
||||
{"game_text_1000000_points", Lang::getText("[GAME_TEXT] 8")}};
|
||||
|
||||
auto text1 = getText("04b_25_enhanced");
|
||||
for (const auto& s : strings1) {
|
||||
textures_.emplace_back(s.name, text1->writeDXToTexture(Text::STROKE, s.text, -2, Colors::NO_COLOR_MOD, 1, param.game.item_text_outline_color));
|
||||
}
|
||||
std::ranges::transform(strings1, std::back_inserter(textures_), [&](const auto& s) {
|
||||
return ResourceTexture(s.name, text1->writeDXToTexture(Text::STROKE, s.text, -2, Colors::NO_COLOR_MOD, 1, param.game.item_text_outline_color));
|
||||
});
|
||||
|
||||
// Texturas de tamaño doble
|
||||
std::vector<NameAndText> strings2 = {
|
||||
@@ -734,9 +717,9 @@ void Resource::createTextTextures() {
|
||||
{"game_text_game_over", "Game Over"}};
|
||||
|
||||
auto text2 = getText("04b_25_2x_enhanced");
|
||||
for (const auto& s : strings2) {
|
||||
textures_.emplace_back(s.name, text2->writeDXToTexture(Text::STROKE, s.text, -4, Colors::NO_COLOR_MOD, 1, param.game.item_text_outline_color));
|
||||
}
|
||||
std::ranges::transform(strings2, std::back_inserter(textures_), [&](const auto& s) {
|
||||
return ResourceTexture(s.name, text2->writeDXToTexture(Text::STROKE, s.text, -4, Colors::NO_COLOR_MOD, 1, param.game.item_text_outline_color));
|
||||
});
|
||||
}
|
||||
|
||||
// Crea los objetos de texto a partir de los archivos de textura y texto
|
||||
@@ -897,12 +880,10 @@ void Resource::renderProgress() {
|
||||
|
||||
// Carga los datos para el modo demostración (sin mostrar progreso)
|
||||
void Resource::loadDemoDataQuiet() {
|
||||
auto list = Asset::get()->getListByType(Asset::Type::DEMODATA);
|
||||
const auto list = Asset::get()->getListByType(Asset::Type::DEMODATA);
|
||||
demos_.clear();
|
||||
|
||||
for (const auto& l : list) {
|
||||
demos_.emplace_back(loadDemoDataFromFile(l));
|
||||
}
|
||||
demos_.reserve(list.size());
|
||||
std::ranges::transform(list, std::back_inserter(demos_), [this](const auto& l) { return loadDemoDataFromFile(l); });
|
||||
}
|
||||
|
||||
// Inicializa los rectangulos que definen la barra de progreso
|
||||
|
||||
@@ -60,7 +60,7 @@ class Resource {
|
||||
std::string name; // Nombre del sonido
|
||||
JA_Sound_t* sound; // Objeto con el sonido
|
||||
|
||||
ResourceSound(std::string name, JA_Sound_t* sound = nullptr)
|
||||
explicit ResourceSound(std::string name, JA_Sound_t* sound = nullptr)
|
||||
: name(std::move(name)),
|
||||
sound(sound) {}
|
||||
};
|
||||
@@ -69,7 +69,7 @@ class Resource {
|
||||
std::string name; // Nombre de la música
|
||||
JA_Music_t* music; // Objeto con la música
|
||||
|
||||
ResourceMusic(std::string name, JA_Music_t* music = nullptr)
|
||||
explicit ResourceMusic(std::string name, JA_Music_t* music = nullptr)
|
||||
: name(std::move(name)),
|
||||
music(music) {}
|
||||
};
|
||||
@@ -78,7 +78,7 @@ class Resource {
|
||||
std::string name; // Nombre de la textura
|
||||
std::shared_ptr<Texture> texture; // Objeto con la textura
|
||||
|
||||
ResourceTexture(std::string name, std::shared_ptr<Texture> texture = nullptr)
|
||||
explicit ResourceTexture(std::string name, std::shared_ptr<Texture> texture = nullptr)
|
||||
: name(std::move(name)),
|
||||
texture(std::move(texture)) {}
|
||||
};
|
||||
@@ -87,7 +87,7 @@ class Resource {
|
||||
std::string name; // Nombre del fichero
|
||||
std::shared_ptr<Text::File> text_file; // Objeto con los descriptores de la fuente de texto
|
||||
|
||||
ResourceTextFile(std::string name, std::shared_ptr<Text::File> text_file = nullptr)
|
||||
explicit ResourceTextFile(std::string name, std::shared_ptr<Text::File> text_file = nullptr)
|
||||
: name(std::move(name)),
|
||||
text_file(std::move(text_file)) {}
|
||||
};
|
||||
@@ -96,7 +96,7 @@ class Resource {
|
||||
std::string name; // Nombre del objeto
|
||||
std::shared_ptr<Text> text; // Objeto de texto
|
||||
|
||||
ResourceText(std::string name, std::shared_ptr<Text> text = nullptr)
|
||||
explicit ResourceText(std::string name, std::shared_ptr<Text> text = nullptr)
|
||||
: name(std::move(name)),
|
||||
text(std::move(text)) {}
|
||||
};
|
||||
@@ -105,7 +105,7 @@ class Resource {
|
||||
std::string name; // Nombre de la animación
|
||||
AnimationsFileBuffer animation; // Objeto con las animaciones
|
||||
|
||||
ResourceAnimation(std::string name, AnimationsFileBuffer animation = {})
|
||||
explicit ResourceAnimation(std::string name, AnimationsFileBuffer animation = {})
|
||||
: name(std::move(name)),
|
||||
animation(std::move(animation)) {}
|
||||
};
|
||||
@@ -116,7 +116,7 @@ class Resource {
|
||||
size_t loaded{0}; // Número de recursos cargados
|
||||
|
||||
ResourceCount() = default;
|
||||
ResourceCount(size_t total)
|
||||
explicit ResourceCount(size_t total)
|
||||
: total(total) {}
|
||||
|
||||
void add(size_t amount) { loaded += amount; }
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint> // Para uint8_t
|
||||
#include <filesystem> // Para remove, path
|
||||
#include <fstream> // Para basic_ofstream, basic_ios, basic_ostream::write, ios, ofstream
|
||||
#include <string> // Para string, basic_string, hash, operator+, to_string, __str_hash_base
|
||||
#include <vector> // Para vector
|
||||
#include <cstdint> // Para uint8_t
|
||||
#include <string> // Para string
|
||||
#include <vector> // Para vector
|
||||
|
||||
// Helper functions para integrar ResourceLoader con el sistema existente
|
||||
namespace ResourceHelper {
|
||||
@@ -22,24 +20,4 @@ namespace ResourceHelper {
|
||||
|
||||
// Convierte ruta Asset a ruta relativa para ResourceLoader
|
||||
auto getPackPath(const std::string& asset_path) -> std::string;
|
||||
|
||||
// Wrappea la carga de archivos para mantener compatibilidad
|
||||
template <typename T>
|
||||
auto loadResourceFile(const std::string& asset_path, T* (*loader_func)(const char*)) -> T* {
|
||||
auto data = loadFile(asset_path);
|
||||
if (data.empty()) {
|
||||
return loader_func(asset_path.c_str());
|
||||
}
|
||||
|
||||
// Crear archivo temporal para funciones que esperan path
|
||||
std::string temp_path = "/tmp/ccae_" + std::to_string(std::hash<std::string>{}(asset_path));
|
||||
std::ofstream temp_file(temp_path, std::ios::binary);
|
||||
temp_file.write(reinterpret_cast<const char*>(data.data()), data.size());
|
||||
temp_file.close();
|
||||
|
||||
T* result = loader_func(temp_path.c_str());
|
||||
std::filesystem::remove(temp_path);
|
||||
|
||||
return result;
|
||||
}
|
||||
} // namespace ResourceHelper
|
||||
@@ -1,10 +1,11 @@
|
||||
#include "core/resources/resource_pack.hpp"
|
||||
|
||||
#include <algorithm> // Para replace
|
||||
#include <algorithm> // Para replace, ranges::all_of
|
||||
#include <array> // Para array
|
||||
#include <filesystem> // Para path, recursive_directory_iterator, directory_entry, exists, relative
|
||||
#include <fstream> // Para basic_ifstream, basic_ostream, basic_ofstream, operator<<, basic_ios, basic_istream::read, basic_ostream::write, endl, ios, basic_istream, ifstream, operator|, basic_istream::seekg, basic_istream::tellg, ofstream, streamsize
|
||||
#include <iostream> // Para cerr
|
||||
#include <numeric> // Para accumulate
|
||||
#include <utility> // Para pair
|
||||
|
||||
const std::string ResourcePack::DEFAULT_ENCRYPT_KEY = "CCAE_RESOURCES__2024";
|
||||
@@ -17,11 +18,7 @@ ResourcePack::~ResourcePack() {
|
||||
}
|
||||
|
||||
auto ResourcePack::calculateChecksum(const std::vector<uint8_t>& data) -> uint32_t {
|
||||
uint32_t checksum = 0x12345678;
|
||||
for (unsigned char i : data) {
|
||||
checksum = ((checksum << 5) + checksum) + i;
|
||||
}
|
||||
return checksum;
|
||||
return std::accumulate(data.begin(), data.end(), static_cast<uint32_t>(0x12345678), [](uint32_t checksum, unsigned char i) { return ((checksum << 5) + checksum) + i; });
|
||||
}
|
||||
|
||||
void ResourcePack::encryptData(std::vector<uint8_t>& data, const std::string& key) {
|
||||
@@ -162,20 +159,16 @@ auto ResourcePack::addDirectory(const std::string& directory) -> bool {
|
||||
return false; // NOLINT(readability-simplify-boolean-expr)
|
||||
}
|
||||
|
||||
for (const auto& entry : std::filesystem::recursive_directory_iterator(directory)) {
|
||||
if (entry.is_regular_file()) {
|
||||
return std::ranges::all_of(std::filesystem::recursive_directory_iterator(directory),
|
||||
[this, &directory](const auto& entry) {
|
||||
if (!entry.is_regular_file()) {
|
||||
return true;
|
||||
}
|
||||
std::string filepath = entry.path().string();
|
||||
std::string filename = std::filesystem::relative(entry.path(), directory).string();
|
||||
|
||||
std::ranges::replace(filename, '\\', '/');
|
||||
|
||||
if (!addFile(filename, filepath)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return addFile(filename, filepath);
|
||||
});
|
||||
}
|
||||
|
||||
auto ResourcePack::getResource(const std::string& filename) -> std::vector<uint8_t> {
|
||||
|
||||
@@ -520,7 +520,7 @@ auto Director::iterate() -> SDL_AppResult {
|
||||
}
|
||||
|
||||
// Procesa un evento SDL (llamado desde SDL_AppEvent)
|
||||
auto Director::handleEvent(SDL_Event& event) -> SDL_AppResult {
|
||||
auto Director::handleEvent(const SDL_Event& event) -> SDL_AppResult {
|
||||
// Eventos globales (SDL_EVENT_QUIT, resize, render target reset, hotplug, service menu, ratón)
|
||||
GlobalEvents::handle(event);
|
||||
|
||||
|
||||
@@ -29,8 +29,8 @@ class Director {
|
||||
~Director();
|
||||
|
||||
// --- Callbacks para SDL_MAIN_USE_CALLBACKS ---
|
||||
auto iterate() -> SDL_AppResult; // Avanza un frame de la sección activa
|
||||
auto handleEvent(SDL_Event& event) -> SDL_AppResult; // Procesa un evento SDL
|
||||
auto iterate() -> SDL_AppResult; // Avanza un frame de la sección activa
|
||||
auto handleEvent(const SDL_Event& event) -> SDL_AppResult; // Procesa un evento SDL
|
||||
|
||||
// --- Debug config (accesible desde otras clases) ---
|
||||
struct DebugConfig {
|
||||
|
||||
@@ -85,7 +85,7 @@ class Balloon {
|
||||
};
|
||||
|
||||
// --- Constructores y destructor ---
|
||||
Balloon(const Config& config);
|
||||
explicit Balloon(const Config& config);
|
||||
~Balloon() = default;
|
||||
|
||||
// --- Métodos principales ---
|
||||
|
||||
@@ -977,7 +977,7 @@ void Player::playSound(const std::string& name) const {
|
||||
return;
|
||||
}
|
||||
|
||||
static auto* audio_ = Audio::get();
|
||||
static const auto* audio_ = Audio::get();
|
||||
audio_->playSound(name);
|
||||
}
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ class Player {
|
||||
};
|
||||
|
||||
// --- Constructor y destructor ---
|
||||
Player(const Config& config);
|
||||
explicit Player(const Config& config);
|
||||
~Player() = default;
|
||||
|
||||
// --- Inicialización y ciclo de vida ---
|
||||
@@ -201,16 +201,16 @@ class Player {
|
||||
[[nodiscard]] auto getCoffees() const -> int { return coffees_; }
|
||||
[[nodiscard]] auto getPowerUpCounter() const -> int { return power_up_counter_; }
|
||||
[[nodiscard]] auto getInvulnerableCounter() const -> int { return invulnerable_counter_; }
|
||||
[[nodiscard]] auto getBulletColor() const -> Bullet::Color; // Devuelve el color actual de bala según el estado
|
||||
auto getNextBulletColor() -> Bullet::Color; // Devuelve el color para la próxima bala (alterna si está en modo toggle)
|
||||
void setBulletColors(Bullet::Color normal, Bullet::Color powered); // Establece los colores de bala para este jugador
|
||||
[[nodiscard]] auto getBulletSoundFile() const -> std::string { return bullet_sound_file_; } // Devuelve el archivo de sonido de bala
|
||||
void setBulletSoundFile(const std::string& filename); // Establece el archivo de sonido de bala para este jugador
|
||||
[[nodiscard]] auto getBulletColor() const -> Bullet::Color; // Devuelve el color actual de bala según el estado
|
||||
auto getNextBulletColor() -> Bullet::Color; // Devuelve el color para la próxima bala (alterna si está en modo toggle)
|
||||
void setBulletColors(Bullet::Color normal, Bullet::Color powered); // Establece los colores de bala para este jugador
|
||||
[[nodiscard]] auto getBulletSoundFile() const -> const std::string& { return bullet_sound_file_; } // Devuelve el archivo de sonido de bala
|
||||
void setBulletSoundFile(const std::string& filename); // Establece el archivo de sonido de bala para este jugador
|
||||
|
||||
// Contadores y timers
|
||||
[[nodiscard]] auto getContinueCounter() const -> int { return continue_counter_; }
|
||||
[[nodiscard]] auto getRecordName() const -> std::string { return enter_name_ ? enter_name_->getFinalName() : "xxx"; }
|
||||
[[nodiscard]] auto getLastEnterName() const -> std::string { return last_enter_name_; }
|
||||
[[nodiscard]] auto getLastEnterName() const -> const std::string& { return last_enter_name_; }
|
||||
|
||||
// --- Configuración e interfaz externa ---
|
||||
void setName(const std::string& name) { name_ = name; }
|
||||
|
||||
@@ -222,13 +222,13 @@ void BalloonFormations::createFloaterVariants() {
|
||||
formations_.resize(100);
|
||||
|
||||
// Crear variantes flotantes de las primeras 50 formaciones
|
||||
for (size_t k = 0; k < 50 && k < formations_.size(); k++) {
|
||||
for (size_t k = 0; k < 50; k++) {
|
||||
const auto& source = formations_.at(k).balloons;
|
||||
std::vector<SpawnParams> floater_params;
|
||||
floater_params.reserve(formations_.at(k).balloons.size());
|
||||
|
||||
for (const auto& original : formations_.at(k).balloons) {
|
||||
floater_params.emplace_back(original.x, original.y, original.vel_x, Balloon::Type::FLOATER, original.size, original.creation_counter);
|
||||
}
|
||||
floater_params.reserve(source.size());
|
||||
std::ranges::transform(source, std::back_inserter(floater_params), [](const auto& original) {
|
||||
return SpawnParams{original.x, original.y, original.vel_x, Balloon::Type::FLOATER, original.size, original.creation_counter};
|
||||
});
|
||||
|
||||
formations_.at(k + 50) = Formation(floater_params);
|
||||
}
|
||||
@@ -395,24 +395,21 @@ void BalloonFormations::loadDefaultPools() {
|
||||
}
|
||||
}
|
||||
|
||||
// Pool 2: Mix de formaciones normales y floaters (50+)
|
||||
// Pools 2 i 3: requereixen formacions de floaters (>50)
|
||||
if (total_formations > 50) {
|
||||
// Pool 2: Mix de formacions normals i floaters
|
||||
Pool pool2;
|
||||
// Agregar algunas formaciones básicas
|
||||
for (size_t i = 0; i < std::min(static_cast<size_t>(5), total_formations); ++i) {
|
||||
pool2.push_back(static_cast<int>(i));
|
||||
}
|
||||
// Agregar algunas floaters si existen
|
||||
for (size_t i = 50; i < std::min(static_cast<size_t>(55), total_formations); ++i) {
|
||||
pool2.push_back(static_cast<int>(i));
|
||||
}
|
||||
if (!pool2.empty()) {
|
||||
pools_.push_back(pool2);
|
||||
}
|
||||
}
|
||||
|
||||
// Pool 3: Solo floaters (si existen formaciones 50+)
|
||||
if (total_formations > 50) {
|
||||
// Pool 3: Només floaters
|
||||
Pool pool3;
|
||||
for (size_t i = 50; i < std::min(static_cast<size_t>(70), total_formations); ++i) {
|
||||
pool3.push_back(static_cast<int>(i));
|
||||
|
||||
@@ -39,7 +39,7 @@ class BalloonFormations {
|
||||
std::vector<SpawnParams> balloons; // Vector con todas las inicializaciones de los globos de la formación
|
||||
|
||||
// Constructor con parámetros
|
||||
Formation(const std::vector<SpawnParams>& spawn_params)
|
||||
explicit Formation(const std::vector<SpawnParams>& spawn_params)
|
||||
: balloons(spawn_params) {}
|
||||
|
||||
// Constructor por defecto
|
||||
|
||||
@@ -106,7 +106,7 @@ void BalloonManager::deployRandomFormation(int stage) {
|
||||
|
||||
// Crea los globos de la formación
|
||||
const auto BALLOONS = balloon_formations_->getFormationFromPool(stage, formation_id).balloons;
|
||||
for (auto balloon : BALLOONS) {
|
||||
for (const auto& balloon : BALLOONS) {
|
||||
Balloon::Config config = {
|
||||
.x = balloon.x,
|
||||
.y = balloon.y,
|
||||
@@ -127,7 +127,7 @@ void BalloonManager::deployRandomFormation(int stage) {
|
||||
// Crea una formación de globos específica
|
||||
void BalloonManager::deployFormation(int formation_id) {
|
||||
const auto BALLOONS = balloon_formations_->getFormation(formation_id).balloons;
|
||||
for (auto balloon : BALLOONS) {
|
||||
for (const auto& balloon : BALLOONS) {
|
||||
Balloon::Config config = {
|
||||
.x = balloon.x,
|
||||
.y = balloon.y,
|
||||
@@ -143,7 +143,7 @@ void BalloonManager::deployFormation(int formation_id) {
|
||||
// Crea una formación de globos específica a una altura determinada
|
||||
void BalloonManager::deployFormation(int formation_id, float y) {
|
||||
const auto BALLOONS = balloon_formations_->getFormation(formation_id).balloons;
|
||||
for (auto balloon : BALLOONS) {
|
||||
for (const auto& balloon : BALLOONS) {
|
||||
Balloon::Config config = {
|
||||
.x = balloon.x,
|
||||
.y = y,
|
||||
|
||||
@@ -24,7 +24,7 @@ using Balloons = std::list<std::shared_ptr<Balloon>>;
|
||||
class BalloonManager {
|
||||
public:
|
||||
// --- Constructor y destructor ---
|
||||
BalloonManager(IStageInfo* stage_info);
|
||||
explicit BalloonManager(IStageInfo* stage_info);
|
||||
~BalloonManager() = default;
|
||||
|
||||
// --- Métodos principales ---
|
||||
|
||||
@@ -14,7 +14,7 @@ BulletManager::BulletManager()
|
||||
|
||||
// Actualiza el estado de todas las balas
|
||||
void BulletManager::update(float delta_time) {
|
||||
for (auto& bullet : bullets_) {
|
||||
for (const auto& bullet : bullets_) {
|
||||
if (bullet->isEnabled()) {
|
||||
processBulletUpdate(bullet, delta_time);
|
||||
}
|
||||
@@ -23,7 +23,7 @@ void BulletManager::update(float delta_time) {
|
||||
|
||||
// Renderiza todas las balas activas
|
||||
void BulletManager::render() {
|
||||
for (auto& bullet : bullets_) {
|
||||
for (const auto& bullet : bullets_) {
|
||||
if (bullet->isEnabled()) {
|
||||
bullet->render();
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
class Cooldown {
|
||||
public:
|
||||
Cooldown(float first_delay_s = 0.0F, float repeat_delay_s = 0.0F)
|
||||
explicit Cooldown(float first_delay_s = 0.0F, float repeat_delay_s = 0.0F)
|
||||
: first_delay_s_(first_delay_s),
|
||||
repeat_delay_s_(repeat_delay_s) {}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "game/gameplay/difficulty.hpp"
|
||||
|
||||
#include <vector> // Para vector
|
||||
#include <algorithm> // Para ranges::find_if
|
||||
#include <vector> // Para vector
|
||||
|
||||
namespace Difficulty {
|
||||
|
||||
@@ -18,19 +19,19 @@ namespace Difficulty {
|
||||
}
|
||||
|
||||
auto getNameFromCode(Code code) -> std::string {
|
||||
for (const auto& difficulty : difficulties_list) {
|
||||
if (difficulty.code == code) {
|
||||
return difficulty.name;
|
||||
}
|
||||
const auto it = std::ranges::find_if(difficulties_list,
|
||||
[code](const auto& difficulty) { return difficulty.code == code; });
|
||||
if (it != difficulties_list.end()) {
|
||||
return it->name;
|
||||
}
|
||||
return !difficulties_list.empty() ? difficulties_list.front().name : "Unknown";
|
||||
}
|
||||
|
||||
auto getCodeFromName(const std::string& name) -> Code {
|
||||
for (const auto& difficulty : difficulties_list) {
|
||||
if (difficulty.name == name) {
|
||||
return difficulty.code;
|
||||
}
|
||||
const auto it = std::ranges::find_if(difficulties_list,
|
||||
[&name](const auto& difficulty) { return difficulty.name == name; });
|
||||
if (it != difficulties_list.end()) {
|
||||
return it->code;
|
||||
}
|
||||
return !difficulties_list.empty() ? difficulties_list.front().code : Code::NORMAL;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ class EnterName {
|
||||
void removeLastCharacter(); // Elimina el último carácter del nombre
|
||||
|
||||
auto getFinalName() -> std::string; // Obtiene el nombre final (o aleatorio si vacío)
|
||||
[[nodiscard]] auto getCurrentName() const -> std::string { return name_; } // Obtiene el nombre actual en proceso
|
||||
[[nodiscard]] auto getCurrentName() const -> const std::string& { return name_; } // Obtiene el nombre actual en proceso
|
||||
[[nodiscard]] auto getSelectedCharacter(int offset = 0) const -> std::string; // Devuelve el carácter seleccionado con offset relativo
|
||||
[[nodiscard]] auto getCarousel(int size) const -> std::string; // Devuelve el carrusel de caracteres (size debe ser impar)
|
||||
[[nodiscard]] auto getSelectedIndex() const -> int { return selected_index_; } // Obtiene el índice del carácter seleccionado
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <iomanip> // Para std::setw, std::setfill
|
||||
#include <iostream> // Para std::cout
|
||||
#include <iterator> // Para distance
|
||||
#include <numeric> // Para accumulate
|
||||
#include <ranges> // Para __find_if_fn, find_if
|
||||
#include <utility> // Para move
|
||||
|
||||
@@ -260,22 +261,11 @@ auto ManageHiScoreTable::verifyChecksum(SDL_IOStream* file, const std::string& f
|
||||
|
||||
// Calcula checksum de la tabla
|
||||
auto ManageHiScoreTable::calculateChecksum(const Table& table) -> unsigned int {
|
||||
unsigned int checksum = 0x12345678; // Magic seed
|
||||
|
||||
for (const auto& entry : table) {
|
||||
// Checksum del score
|
||||
return std::accumulate(table.begin(), table.end(), 0x12345678U, [](unsigned int checksum, const auto& entry) {
|
||||
checksum = ((checksum << 5) + checksum) + static_cast<unsigned int>(entry.score);
|
||||
|
||||
// Checksum del nombre
|
||||
for (char c : entry.name) {
|
||||
checksum = ((checksum << 5) + checksum) + static_cast<unsigned int>(c);
|
||||
}
|
||||
|
||||
// Checksum de one_credit_complete
|
||||
checksum = ((checksum << 5) + checksum) + (entry.one_credit_complete ? 1U : 0U);
|
||||
}
|
||||
|
||||
return checksum;
|
||||
checksum = std::accumulate(entry.name.begin(), entry.name.end(), checksum, [](unsigned int acc, char c) { return ((acc << 5) + acc) + static_cast<unsigned int>(c); });
|
||||
return ((checksum << 5) + checksum) + (entry.one_credit_complete ? 1U : 0U);
|
||||
});
|
||||
}
|
||||
|
||||
// Guarda la tabla en un fichero
|
||||
|
||||
@@ -724,7 +724,7 @@ void Scoreboard::renderSeparator() {
|
||||
// Pinta el carrusel de caracteres con efecto de color LERP y animación suave
|
||||
void Scoreboard::renderCarousel(size_t panel_index, int center_x, int y) {
|
||||
// Obtener referencia a EnterName
|
||||
EnterName* enter_name = enter_name_ref_.at(panel_index);
|
||||
const EnterName* enter_name = enter_name_ref_.at(panel_index);
|
||||
if (enter_name == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <algorithm> // Para max, min
|
||||
#include <exception> // Para exception
|
||||
#include <fstream> // Para basic_istream, basic_ifstream, ifstream, stringstream
|
||||
#include <numeric> // Para accumulate
|
||||
#include <sstream> // Para basic_stringstream
|
||||
#include <utility> // Para move
|
||||
|
||||
@@ -282,11 +283,7 @@ auto StageManager::getPowerNeededForCurrentStage() const -> int {
|
||||
}
|
||||
|
||||
auto StageManager::getTotalPowerNeededToCompleteGame() const -> int {
|
||||
int total_power_needed = 0;
|
||||
for (const auto& stage : stages_) {
|
||||
total_power_needed += stage.getPowerToComplete();
|
||||
}
|
||||
return total_power_needed;
|
||||
return std::accumulate(stages_.begin(), stages_.end(), 0, [](int total, const auto& stage) { return total + stage.getPowerToComplete(); });
|
||||
}
|
||||
|
||||
auto StageManager::getPowerNeededToReachStage(size_t target_stage_index) const -> int {
|
||||
|
||||
+27
-27
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <SDL3/SDL.h> // Para SDL_ScaleMode, SDL_LogCategory, SDL_LogError, SDL_LogInfo, SDL_LogWarn
|
||||
|
||||
#include <algorithm> // Para clamp
|
||||
#include <algorithm> // Para clamp, ranges::find_if
|
||||
#include <cstddef> // Para size_t
|
||||
#include <fstream> // Para ifstream, ofstream
|
||||
#include <iostream> // Para std::cout
|
||||
@@ -820,14 +820,14 @@ namespace Options {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const auto& physical_gamepad : physical_gamepads) {
|
||||
if (physical_gamepad->path == desired_path && !isGamepadAssigned(physical_gamepad, assigned_instances)) {
|
||||
gamepads_[i].instance = physical_gamepad;
|
||||
gamepads_[i].name = physical_gamepad->name;
|
||||
|
||||
assigned_instances.push_back(physical_gamepad);
|
||||
break;
|
||||
}
|
||||
const auto it = std::ranges::find_if(physical_gamepads,
|
||||
[this, &desired_path, &assigned_instances](const auto& pg) {
|
||||
return pg->path == desired_path && !isGamepadAssigned(pg, assigned_instances);
|
||||
});
|
||||
if (it != physical_gamepads.end()) {
|
||||
gamepads_[i].instance = *it;
|
||||
gamepads_[i].name = (*it)->name;
|
||||
assigned_instances.push_back(*it);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -849,15 +849,15 @@ namespace Options {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const auto& physical_gamepad : physical_gamepads) {
|
||||
if (physical_gamepad->name == desired_name && !isGamepadAssigned(physical_gamepad, assigned_instances)) {
|
||||
gamepads_[i].instance = physical_gamepad;
|
||||
gamepads_[i].name = physical_gamepad->name;
|
||||
gamepads_[i].path = physical_gamepad->path;
|
||||
|
||||
assigned_instances.push_back(physical_gamepad);
|
||||
break;
|
||||
}
|
||||
const auto it = std::ranges::find_if(physical_gamepads,
|
||||
[this, &desired_name, &assigned_instances](const auto& pg) {
|
||||
return pg->name == desired_name && !isGamepadAssigned(pg, assigned_instances);
|
||||
});
|
||||
if (it != physical_gamepads.end()) {
|
||||
gamepads_[i].instance = *it;
|
||||
gamepads_[i].name = (*it)->name;
|
||||
gamepads_[i].path = (*it)->path;
|
||||
assigned_instances.push_back(*it);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -871,15 +871,15 @@ namespace Options {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const auto& physical_gamepad : physical_gamepads) {
|
||||
if (!isGamepadAssigned(physical_gamepad, assigned_instances)) {
|
||||
gamepads_[i].instance = physical_gamepad;
|
||||
gamepads_[i].name = physical_gamepad->name;
|
||||
gamepads_[i].path = physical_gamepad->path;
|
||||
|
||||
assigned_instances.push_back(physical_gamepad);
|
||||
break;
|
||||
}
|
||||
const auto it = std::ranges::find_if(physical_gamepads,
|
||||
[this, &assigned_instances](const auto& pg) {
|
||||
return !isGamepadAssigned(pg, assigned_instances);
|
||||
});
|
||||
if (it != physical_gamepads.end()) {
|
||||
gamepads_[i].instance = *it;
|
||||
gamepads_[i].name = (*it)->name;
|
||||
gamepads_[i].path = (*it)->path;
|
||||
assigned_instances.push_back(*it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ namespace Options {
|
||||
std::string path; // Ruta física del dispositivo
|
||||
Player::Id player_id; // Jugador asociado al mando
|
||||
|
||||
Gamepad(Player::Id custom_player_id = Player::Id::NO_PLAYER)
|
||||
explicit Gamepad(Player::Id custom_player_id = Player::Id::NO_PLAYER)
|
||||
: player_id(custom_player_id) {}
|
||||
};
|
||||
|
||||
|
||||
@@ -683,10 +683,11 @@ void Credits::startCredits() {
|
||||
init_right_x_ = static_cast<int>(right_black_rect_.x);
|
||||
|
||||
// Objetivos
|
||||
const int CENTER_X = param.game.game_area.center_x;
|
||||
int top_target_h = param.game.game_area.center_y - 1;
|
||||
int bottom_target_y = param.game.game_area.center_y + 1;
|
||||
int left_target_w = param.game.game_area.center_x;
|
||||
int right_target_x = param.game.game_area.center_x;
|
||||
int left_target_w = CENTER_X;
|
||||
int right_target_x = CENTER_X;
|
||||
|
||||
// Pasos verticales
|
||||
int pasos_top = std::max(0, top_target_h - init_top_h_);
|
||||
|
||||
+15
-29
@@ -801,7 +801,7 @@ void Game::renderPathSprites() {
|
||||
}
|
||||
|
||||
// Acciones a realizar cuando el jugador colisiona con un globo
|
||||
void Game::handlePlayerCollision(std::shared_ptr<Player>& player, std::shared_ptr<Balloon>& balloon) {
|
||||
void Game::handlePlayerCollision(std::shared_ptr<Player>& player, const std::shared_ptr<Balloon>& balloon) {
|
||||
if (!player->isPlaying() || player->isInvulnerable()) {
|
||||
return; // Si no está jugando o tiene inmunidad, no hace nada
|
||||
}
|
||||
@@ -1243,18 +1243,6 @@ auto Game::getPlayer(Player::Id id) -> std::shared_ptr<Player> {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Obtiene un controlador a partir del "id" del jugador
|
||||
auto Game::getController(Player::Id player_id) -> int {
|
||||
switch (player_id) {
|
||||
case Player::Id::PLAYER1:
|
||||
return 0;
|
||||
case Player::Id::PLAYER2:
|
||||
return 1;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Gestiona la entrada durante el juego
|
||||
void Game::checkInput() {
|
||||
Input::get()->update();
|
||||
@@ -1293,11 +1281,12 @@ void Game::checkInput() {
|
||||
// Verifica si alguno de los controladores ha solicitado una pausa y actualiza el estado de pausa del juego.
|
||||
void Game::checkPauseInput() {
|
||||
// Comprueba los mandos
|
||||
for (const auto& gamepad : input_->getGamepads()) {
|
||||
if (input_->checkAction(Input::Action::PAUSE, Input::DO_NOT_ALLOW_REPEAT, Input::DO_NOT_CHECK_KEYBOARD, gamepad)) {
|
||||
pause_manager_->togglePlayerPause();
|
||||
return;
|
||||
}
|
||||
const auto& gamepads = input_->getGamepads();
|
||||
if (std::ranges::any_of(gamepads, [this](const auto& gamepad) {
|
||||
return input_->checkAction(Input::Action::PAUSE, Input::DO_NOT_ALLOW_REPEAT, Input::DO_NOT_CHECK_KEYBOARD, gamepad);
|
||||
})) {
|
||||
pause_manager_->togglePlayerPause();
|
||||
return;
|
||||
}
|
||||
|
||||
// Comprueba el teclado
|
||||
@@ -1973,7 +1962,7 @@ void Game::playSound(const std::string& name) const {
|
||||
return;
|
||||
}
|
||||
|
||||
static auto* audio_ = Audio::get();
|
||||
static const auto* audio_ = Audio::get();
|
||||
audio_->playSound(name);
|
||||
}
|
||||
|
||||
@@ -2048,9 +2037,7 @@ void Game::handleGameOverEvents() {
|
||||
void Game::buildPlayerDrawList(const Players& elements, Players& draw_list) {
|
||||
draw_list.clear();
|
||||
draw_list.reserve(elements.size());
|
||||
for (const auto& e : elements) {
|
||||
draw_list.push_back(e); // copia el shared_ptr
|
||||
}
|
||||
std::ranges::copy(elements, std::back_inserter(draw_list));
|
||||
std::ranges::stable_sort(draw_list, [](const std::shared_ptr<Player>& a, const std::shared_ptr<Player>& b) -> bool {
|
||||
return a->getZOrder() < b->getZOrder();
|
||||
});
|
||||
@@ -2154,8 +2141,8 @@ void Game::autoplayHandleInput() {
|
||||
|
||||
// Comprueba los eventos en el modo DEBUG
|
||||
void Game::handleDebugEvents(const SDL_Event& event) {
|
||||
static int formation_id_ = 0;
|
||||
if (event.type == SDL_EVENT_KEY_DOWN && static_cast<int>(event.key.repeat) == 0) {
|
||||
static int formation_id_ = 0;
|
||||
switch (event.key.key) {
|
||||
case SDLK_1: { // Crea una powerball
|
||||
balloon_manager_->createPowerBall();
|
||||
@@ -2196,12 +2183,11 @@ void Game::handleDebugEvents(const SDL_Event& event) {
|
||||
break;
|
||||
}
|
||||
case SDLK_8: {
|
||||
for (const auto& player : players_) {
|
||||
if (player->isPlaying()) {
|
||||
createItem(ItemType::COFFEE_MACHINE, player->getPosX(), param.game.game_area.rect.y - Item::COFFEE_MACHINE_HEIGHT);
|
||||
coffee_machine_enabled_ = true;
|
||||
break;
|
||||
}
|
||||
const auto it = std::ranges::find_if(players_,
|
||||
[](const auto& player) { return player->isPlaying(); });
|
||||
if (it != players_.end()) {
|
||||
createItem(ItemType::COFFEE_MACHINE, (*it)->getPosX(), param.game.game_area.rect.y - Item::COFFEE_MACHINE_HEIGHT);
|
||||
coffee_machine_enabled_ = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -227,7 +227,6 @@ class Game {
|
||||
void updatePlayers(float delta_time); // Actualiza las variables y estados de los jugadores
|
||||
void renderPlayers(); // Renderiza todos los jugadores en pantalla
|
||||
auto getPlayer(Player::Id id) -> std::shared_ptr<Player>; // Obtiene un jugador por su identificador
|
||||
static auto getController(Player::Id player_id) -> int; // Obtiene el controlador asignado a un jugador
|
||||
|
||||
// --- Estado de jugadores ---
|
||||
void checkAndUpdatePlayerStatus(int active_player_index, int inactive_player_index); // Actualiza estado entre jugadores
|
||||
@@ -237,9 +236,9 @@ class Game {
|
||||
auto allPlayersAreNotPlaying() -> bool; // Verifica si ningún jugador está activo
|
||||
|
||||
// --- Colisiones de jugadores ---
|
||||
void handlePlayerCollision(std::shared_ptr<Player>& player, std::shared_ptr<Balloon>& balloon); // Procesa colisión de jugador con globo
|
||||
auto checkPlayerBalloonCollision(std::shared_ptr<Player>& player) -> std::shared_ptr<Balloon>; // Detecta colisión jugador-globo
|
||||
void checkPlayerItemCollision(std::shared_ptr<Player>& player); // Detecta colisión jugador-ítem
|
||||
void handlePlayerCollision(std::shared_ptr<Player>& player, const std::shared_ptr<Balloon>& balloon); // Procesa colisión de jugador con globo
|
||||
auto checkPlayerBalloonCollision(std::shared_ptr<Player>& player) -> std::shared_ptr<Balloon>; // Detecta colisión jugador-globo
|
||||
void checkPlayerItemCollision(std::shared_ptr<Player>& player); // Detecta colisión jugador-ítem
|
||||
|
||||
// --- Sistema de entrada (input) ---
|
||||
void checkInput(); // Gestiona toda la entrada durante el juego
|
||||
|
||||
@@ -245,9 +245,6 @@ void Title::run() {
|
||||
}
|
||||
}
|
||||
|
||||
// Reinicia el contador interno
|
||||
void Title::resetCounter() { counter_time_ = 0.0F; }
|
||||
|
||||
// Intercambia la asignación de mandos a los jugadores
|
||||
void Title::swapControllers() {
|
||||
if (Input::get()->getNumGamepads() == 0) {
|
||||
|
||||
@@ -107,7 +107,6 @@ class Title {
|
||||
auto calculateDeltaTime() -> float; // Calcula el tiempo transcurrido desde el último frame
|
||||
void updateState(float delta_time); // Actualiza el estado actual del título
|
||||
void setState(State state); // Cambia el estado del título
|
||||
void resetCounter(); // Reinicia el contador interno
|
||||
|
||||
// --- Entrada de usuario ---
|
||||
void checkEvents(); // Comprueba los eventos
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <algorithm> // Para max, clamp
|
||||
#include <cstddef> // Para size_t
|
||||
#include <functional> // Para function
|
||||
#include <numeric> // Para accumulate
|
||||
#include <string> // Para allocator, string, basic_string, to_string, operator==, char_traits
|
||||
#include <utility> // Para move
|
||||
#include <vector> // Para vector
|
||||
@@ -174,11 +175,7 @@ class ListOption : public MenuOption {
|
||||
setter_(value_list_[list_index_]);
|
||||
}
|
||||
auto getMaxValueWidth(Text* text_renderer) const -> int override {
|
||||
int max_w = 0;
|
||||
for (const auto& val : value_list_) {
|
||||
max_w = std::max(max_w, text_renderer->length(val, -2));
|
||||
}
|
||||
return max_w;
|
||||
return std::accumulate(value_list_.begin(), value_list_.end(), 0, [text_renderer](int max_w, const auto& val) { return std::max(max_w, text_renderer->length(val, -2)); });
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -381,9 +381,7 @@ void MenuRenderer::updatePosition() {
|
||||
// Resto de métodos (sin cambios significativos)
|
||||
|
||||
void MenuRenderer::precalculateMenuWidths(const std::vector<std::unique_ptr<MenuOption>>& all_options, const ServiceMenu* menu_state) { // NOLINT(readability-named-parameter)
|
||||
for (int& w : group_menu_widths_) {
|
||||
w = ServiceMenu::MIN_WIDTH;
|
||||
}
|
||||
std::ranges::fill(group_menu_widths_, ServiceMenu::MIN_WIDTH);
|
||||
for (int group = 0; group < 5; ++group) {
|
||||
auto sg = static_cast<ServiceMenu::SettingsGroup>(group);
|
||||
int max_option_width = 0;
|
||||
@@ -433,33 +431,6 @@ auto MenuRenderer::getAnimatedSelectedColor() const -> Color {
|
||||
static auto color_cycle_ = Colors::generateMirroredCycle(param.service_menu.selected_color, ColorCycleStyle::HUE_WAVE);
|
||||
return color_cycle_.at(color_counter_ % color_cycle_.size());
|
||||
}
|
||||
auto MenuRenderer::setRect(SDL_FRect rect) -> SDL_FRect {
|
||||
border_rect_ = {.x = rect.x - 1, .y = rect.y + 1, .w = rect.w + 2, .h = rect.h - 2};
|
||||
return rect;
|
||||
}
|
||||
auto MenuRenderer::getTruncatedValueWidth(const std::string& value, int available_width) const -> int {
|
||||
int value_width = element_text_->length(value, -2);
|
||||
if (value_width <= available_width) {
|
||||
return value_width;
|
||||
}
|
||||
|
||||
// Calculamos cuántos caracteres podemos mostrar más los puntos suspensivos
|
||||
// Estimamos el ancho de los puntos suspensivos como 3 caracteres promedio
|
||||
int ellipsis_width = element_text_->length("...", -2);
|
||||
int available_for_text = available_width - ellipsis_width;
|
||||
|
||||
if (available_for_text <= 0) {
|
||||
return ellipsis_width; // Solo mostramos los puntos suspensivos
|
||||
}
|
||||
|
||||
// Calculamos aproximadamente cuántos caracteres caben
|
||||
float char_width = static_cast<float>(value_width) / value.length();
|
||||
auto max_chars = static_cast<size_t>(available_for_text / char_width);
|
||||
|
||||
// Verificamos el ancho real del texto truncado
|
||||
std::string truncated = truncateWithEllipsis(value, max_chars);
|
||||
return element_text_->length(truncated, -2);
|
||||
}
|
||||
|
||||
auto MenuRenderer::getTruncatedValue(const std::string& value, int available_width) const -> std::string {
|
||||
int value_width = element_text_->length(value, -2);
|
||||
|
||||
@@ -82,8 +82,10 @@ class MenuRenderer {
|
||||
// --- Estructuras de Animación ---
|
||||
struct ResizeAnimation {
|
||||
bool active = false;
|
||||
float start_width, start_height;
|
||||
float target_width, target_height;
|
||||
float start_width = 0.0F;
|
||||
float start_height = 0.0F;
|
||||
float target_width = 0.0F;
|
||||
float target_height = 0.0F;
|
||||
float elapsed = 0.0F;
|
||||
float duration = 0.2F;
|
||||
|
||||
@@ -97,7 +99,8 @@ class MenuRenderer {
|
||||
HIDING };
|
||||
Type type = Type::NONE;
|
||||
bool active = false;
|
||||
float target_width, target_height;
|
||||
float target_width = 0.0F;
|
||||
float target_height = 0.0F;
|
||||
float elapsed = 0.0F;
|
||||
float duration = 0.25F;
|
||||
|
||||
@@ -140,8 +143,6 @@ class MenuRenderer {
|
||||
[[nodiscard]] auto getMenuWidthForGroup(ServiceMenu::SettingsGroup group) const -> int;
|
||||
[[nodiscard]] auto getAnimatedSelectedColor() const -> Color;
|
||||
void updateColorCounter();
|
||||
auto setRect(SDL_FRect rect) -> SDL_FRect;
|
||||
[[nodiscard]] auto getTruncatedValueWidth(const std::string& value, int available_width) const -> int;
|
||||
[[nodiscard]] auto getTruncatedValue(const std::string& value, int available_width) const -> std::string;
|
||||
[[nodiscard]] static auto easeOut(float t) -> float;
|
||||
[[nodiscard]] auto shouldShowContent() const -> bool;
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
#include <SDL3/SDL.h> // Para SDL_RenderFillRect, SDL_FRect, SDL_RenderClear
|
||||
|
||||
#include <algorithm> // Para remove_if, min
|
||||
#include <string> // Para basic_string, string
|
||||
#include <algorithm> // Para ranges::transform, min
|
||||
#include <iterator> // Para back_inserter
|
||||
#include <string> // Para basic_string, string, erase_if
|
||||
#include <utility>
|
||||
#include <vector> // Para vector
|
||||
|
||||
@@ -77,7 +78,7 @@ void Notifier::playNotificationSoundIfNeeded(const Notification& notification) {
|
||||
}
|
||||
|
||||
void Notifier::updateNotificationState(int index, float delta_time) {
|
||||
auto& notification = notifications_[index];
|
||||
const auto& notification = notifications_[index];
|
||||
|
||||
switch (notification.state) {
|
||||
case State::RISING:
|
||||
@@ -167,7 +168,7 @@ void Notifier::show(std::vector<std::string> texts, int icon, const std::string&
|
||||
}
|
||||
|
||||
// Elimina las cadenas vacías
|
||||
texts.erase(std::ranges::remove_if(texts, [](const std::string& s) -> bool { return s.empty(); }).begin(), texts.end());
|
||||
std::erase_if(texts, [](const std::string& s) -> bool { return s.empty(); });
|
||||
|
||||
// Encuentra la cadena más larga
|
||||
std::string longest;
|
||||
@@ -303,8 +304,6 @@ void Notifier::clearAllNotifications() {
|
||||
auto Notifier::getCodes() -> std::vector<std::string> {
|
||||
std::vector<std::string> codes;
|
||||
codes.reserve(notifications_.size());
|
||||
for (const auto& notification : notifications_) {
|
||||
codes.emplace_back(notification.code);
|
||||
}
|
||||
std::ranges::transform(notifications_, std::back_inserter(codes), [](const auto& notification) { return notification.code; });
|
||||
return codes;
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
#include "game/ui/service_menu.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <numeric>
|
||||
#include <utility>
|
||||
|
||||
#include "core/audio/audio.hpp" // Para Audio
|
||||
@@ -175,7 +178,7 @@ void ServiceMenu::selectOption() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto* folder = dynamic_cast<FolderOption*>(selected_option)) {
|
||||
if (const auto* folder = dynamic_cast<const FolderOption*>(selected_option)) {
|
||||
previous_settings_group_ = current_settings_group_;
|
||||
current_settings_group_ = folder->getTargetGroup();
|
||||
selected_ = 0;
|
||||
@@ -200,9 +203,8 @@ void ServiceMenu::updateDisplayOptions() {
|
||||
|
||||
void ServiceMenu::updateOptionPairs() {
|
||||
option_pairs_.clear();
|
||||
for (const auto& option : display_options_) {
|
||||
option_pairs_.emplace_back(option->getCaption(), option->getValueAsString());
|
||||
}
|
||||
option_pairs_.reserve(display_options_.size());
|
||||
std::ranges::transform(display_options_, std::back_inserter(option_pairs_), [](const auto* option) { return std::pair{option->getCaption(), option->getValueAsString()}; });
|
||||
}
|
||||
|
||||
void ServiceMenu::updateMenu() {
|
||||
@@ -250,12 +252,9 @@ void ServiceMenu::applySettingsSettings() {
|
||||
}
|
||||
|
||||
auto ServiceMenu::getOptionByCaption(const std::string& caption) const -> MenuOption* {
|
||||
for (const auto& option : options_) {
|
||||
if (option->getCaption() == caption) {
|
||||
return option.get();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
const auto it = std::ranges::find_if(options_,
|
||||
[&caption](const auto& option) { return option->getCaption() == caption; });
|
||||
return it != options_.end() ? it->get() : nullptr;
|
||||
}
|
||||
|
||||
// --- Getters y otros ---
|
||||
@@ -273,13 +272,8 @@ auto ServiceMenu::getCurrentGroupAlignment() const -> ServiceMenu::GroupAlignmen
|
||||
}
|
||||
|
||||
auto ServiceMenu::countOptionsInGroup(SettingsGroup group) const -> size_t {
|
||||
size_t count = 0;
|
||||
for (const auto& option : options_) {
|
||||
if (option->getGroup() == group && !option->isHidden()) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
return std::ranges::count_if(options_,
|
||||
[group](const auto& option) { return option->getGroup() == group && !option->isHidden(); });
|
||||
}
|
||||
|
||||
// Inicializa todas las opciones del menú
|
||||
@@ -300,7 +294,7 @@ void ServiceMenu::initializeOptions() {
|
||||
[this]() -> void {
|
||||
// Acción: configurar botones del mando del jugador 1
|
||||
auto* gamepad = &Options::gamepad_manager.getGamepad(Player::Id::PLAYER1);
|
||||
if ((gamepad != nullptr) && gamepad->instance) {
|
||||
if (gamepad->instance != nullptr) {
|
||||
define_buttons_->enable(gamepad);
|
||||
}
|
||||
}));
|
||||
@@ -318,7 +312,7 @@ void ServiceMenu::initializeOptions() {
|
||||
[this]() -> void {
|
||||
// Acción: configurar botones del mando del jugador 2
|
||||
auto* gamepad = &Options::gamepad_manager.getGamepad(Player::Id::PLAYER2);
|
||||
if ((gamepad != nullptr) && gamepad->instance) {
|
||||
if (gamepad->instance != nullptr) {
|
||||
define_buttons_->enable(gamepad);
|
||||
}
|
||||
}));
|
||||
@@ -436,11 +430,10 @@ void ServiceMenu::initializeOptions() {
|
||||
}
|
||||
Screen::initShaders();
|
||||
};
|
||||
auto preset_max_width = [](Text* text) -> int {
|
||||
int max_w = 0;
|
||||
for (const auto& p : Options::postfx_presets) { max_w = std::max(max_w, text->length(p.name, -2)); }
|
||||
for (const auto& p : Options::crtpi_presets) { max_w = std::max(max_w, text->length(p.name, -2)); }
|
||||
return max_w;
|
||||
auto preset_max_width = [](const Text* text) -> int {
|
||||
const auto presets_length = [text](int max_w, const auto& p) { return std::max(max_w, text->length(p.name, -2)); };
|
||||
int max_w = std::accumulate(Options::postfx_presets.begin(), Options::postfx_presets.end(), 0, presets_length);
|
||||
return std::accumulate(Options::crtpi_presets.begin(), Options::crtpi_presets.end(), max_w, presets_length);
|
||||
};
|
||||
|
||||
options_.push_back(std::make_unique<CallbackOption>(
|
||||
|
||||
@@ -51,7 +51,7 @@ class WindowMessage {
|
||||
text_color{200, 200, 200, 255} {}
|
||||
|
||||
// Constructor que convierte desde ParamServiceMenu::WindowMessage
|
||||
Config(const ParamServiceMenu::WindowMessage& param_config)
|
||||
explicit Config(const ParamServiceMenu::WindowMessage& param_config)
|
||||
: bg_color(param_config.bg_color),
|
||||
border_color(param_config.border_color),
|
||||
title_color(param_config.title_color),
|
||||
@@ -67,7 +67,7 @@ class WindowMessage {
|
||||
animation_duration(param_config.animation_duration) {}
|
||||
};
|
||||
|
||||
WindowMessage(
|
||||
explicit WindowMessage(
|
||||
std::shared_ptr<Text> text_renderer,
|
||||
std::string title = "",
|
||||
const Config& config = Config{});
|
||||
@@ -148,8 +148,10 @@ class WindowMessage {
|
||||
// Animación de redimensionado
|
||||
struct ResizeAnimation {
|
||||
bool active = false;
|
||||
float start_width, start_height;
|
||||
float target_width, target_height;
|
||||
float start_width = 0.0F;
|
||||
float start_height = 0.0F;
|
||||
float target_width = 0.0F;
|
||||
float target_height = 0.0F;
|
||||
float elapsed = 0.0F;
|
||||
|
||||
void start(float from_w, float from_h, float to_w, float to_h) {
|
||||
@@ -183,7 +185,8 @@ class WindowMessage {
|
||||
|
||||
Type type = Type::NONE;
|
||||
bool active = false;
|
||||
float target_width, target_height; // Tamaño final al mostrar
|
||||
float target_width = 0.0F;
|
||||
float target_height = 0.0F;
|
||||
float elapsed = 0.0F;
|
||||
|
||||
void startShow(float to_w, float to_h) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#define _USE_MATH_DEFINES
|
||||
#include "utils/color.hpp"
|
||||
|
||||
#include <algorithm> // Para ranges::any_of
|
||||
#include <cctype> // Para isxdigit
|
||||
#include <cmath> // Para sinf, fmaxf, fminf, M_PI, fmodf, roundf, fmod
|
||||
#include <cstdint> // Para uint8_t
|
||||
@@ -22,10 +23,8 @@ auto Color::fromHex(const std::string& hex_str) -> Color {
|
||||
}
|
||||
|
||||
// Verificar que todos los caracteres sean hexadecimales válidos
|
||||
for (char c : hex) {
|
||||
if (std::isxdigit(c) == 0) {
|
||||
throw std::invalid_argument("String contiene caracteres no hexadecimales");
|
||||
}
|
||||
if (std::ranges::any_of(hex, [](char c) { return std::isxdigit(c) == 0; })) {
|
||||
throw std::invalid_argument("String contiene caracteres no hexadecimales");
|
||||
}
|
||||
|
||||
// Convertir cada par de caracteres a valores RGB(A)
|
||||
|
||||
@@ -189,8 +189,6 @@ namespace {
|
||||
{"service_menu.window_message.text_safety_margin", [](const std::string& v) -> void { param.service_menu.window_message.text_safety_margin = std::stof(v); }},
|
||||
{"service_menu.window_message.animation_duration", [](const std::string& v) -> void { param.service_menu.window_message.animation_duration = std::stof(v); }}};
|
||||
|
||||
static const std::unordered_map<std::string, std::function<void(const std::string&)>> INT_PARAMS_EXTRA = {};
|
||||
|
||||
// Colores válidos para globos
|
||||
static const std::unordered_map<std::string, bool> VALID_BALLOON_COLORS = {
|
||||
{"blue", true},
|
||||
|
||||
@@ -52,7 +52,7 @@ struct ParamBalloon {
|
||||
float vel;
|
||||
|
||||
// Constructor por defecto
|
||||
constexpr Settings(float grav_val = 0.0F, float vel_val = 0.0F)
|
||||
explicit constexpr Settings(float grav_val = 0.0F, float vel_val = 0.0F)
|
||||
: grav(grav_val),
|
||||
vel(vel_val) {}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user