diff --git a/data/config/assets.txt b/data/config/assets.txt index 9f0c6d6..9e0f241 100644 --- a/data/config/assets.txt +++ b/data/config/assets.txt @@ -16,6 +16,7 @@ DEMODATA|${PREFIX}/data/config/demo2.bin DATA|${PREFIX}/data/config/gamecontrollerdb.txt DATA|${PREFIX}/data/config/formations.txt DATA|${PREFIX}/data/config/pools.txt +DATA|${PREFIX}/data/config/stages.txt # Música MUSIC|${PREFIX}/data/music/intro.ogg diff --git a/data/config/stages.txt b/data/config/stages.txt new file mode 100644 index 0000000..906856d --- /dev/null +++ b/data/config/stages.txt @@ -0,0 +1,19 @@ +# Archivo de configuración de fases +# Formato: power_to_complete,min_menace,max_menace,name +# Líneas que empiezan con # son comentarios y se ignoran + +# Fases iniciales - Tutorial y aprendizaje +200, 11, 19, Tutorial +300, 15, 23, Primeros pasos + +# Fases intermedias - Incremento de dificultad +600, 19, 27, Intensificación +600, 19, 27, Persistencia +600, 23, 31, Desafío medio +600, 23, 31, Resistencia + +# Fases avanzadas - Desafío final +650, 27, 35, Aproximación final +750, 27, 35, Penúltimo obstáculo +850, 31, 39, Clímax +950, 35, 47, Maestría \ No newline at end of file diff --git a/source/balloon_manager.cpp b/source/balloon_manager.cpp index a4d98c9..9214235 100644 --- a/source/balloon_manager.cpp +++ b/source/balloon_manager.cpp @@ -111,7 +111,7 @@ void BalloonManager::deployRandomFormation(int stage) { } // Reinicia el contador para el próximo despliegue - balloon_deploy_counter_ = 300; + balloon_deploy_counter_ = DEFAULT_BALLOON_DEPLOY_COUNTER; } } } diff --git a/source/balloon_manager.h b/source/balloon_manager.h index b92fd3d..6f5e055 100644 --- a/source/balloon_manager.h +++ b/source/balloon_manager.h @@ -81,6 +81,8 @@ class BalloonManager { [[nodiscard]] auto getNumBalloons() const -> int { return balloons_.size(); } private: + static const int DEFAULT_BALLOON_DEPLOY_COUNTER = 300; + Balloons balloons_; // Vector con los globos activos std::unique_ptr explosions_; // Objeto para gestionar explosiones std::unique_ptr balloon_formations_; // Objeto para manejar formaciones enemigas diff --git a/source/sections/game.cpp b/source/sections/game.cpp index 100699c..63d1a5c 100644 --- a/source/sections/game.cpp +++ b/source/sections/game.cpp @@ -67,7 +67,7 @@ Game::Game(Player::Id player_id, int current_stage, bool demo) // Otras variables Section::name = Section::Name::GAME; Section::options = Section::Options::NONE; - stage_manager_->initialize(); + stage_manager_->initialize(Asset::get()->get("stages.txt")); stage_manager_->setPowerChangeCallback([this](int amount) { background_->incrementProgress(amount); }); stage_manager_->jumpToStage(current_stage); @@ -1846,24 +1846,6 @@ void Game::cleanVectors() { freePathSprites(); } -/* // Gestiona el nivel de amenaza -void Game::updateMenace() { - if (state_ == State::PLAYING) { - const auto STAGE = Stage::get(Stage::number); - const float PERCENT = Stage::power / STAGE.power_to_complete; - const int DIFFERENCE = STAGE.max_menace - STAGE.min_menace; - - // Aumenta el nivel de amenaza en función de la puntuación - menace_threshold_ = STAGE.min_menace + (DIFFERENCE * PERCENT); - - // Si el nivel de amenza es inferior al umbral - if (menace_current_ < menace_threshold_) { - balloon_manager_->deployRandomFormation(Stage::number); // Crea una formación aleatoria de globos - evaluateAndSetMenace(); // Recalcula el nivel de amenaza con el nuevo globo - } - } -} */ - // Gestiona el nivel de amenaza void Game::updateMenace() { if (state_ != State::PLAYING) { diff --git a/source/stage.cpp b/source/stage.cpp index 4cf8526..6de0862 100644 --- a/source/stage.cpp +++ b/source/stage.cpp @@ -1,12 +1,14 @@ #include "stage.h" #include +#include +#include -// ===== IMPLEMENTACIÓN DE StageData ===== +// Implementación de StageData StageData::StageData(int power_to_complete, int min_menace, int max_menace, const std::string& name) : power_to_complete_(power_to_complete), min_menace_(min_menace), max_menace_(max_menace), name_(name), status_(StageStatus::LOCKED) {} -// ===== IMPLEMENTACIÓN DE StageManager ===== +// Implementación de StageManager StageManager::StageManager() : current_power_(0), total_power_(0), current_stage_index_(0), power_collection_state_(PowerCollectionState::ENABLED), @@ -20,6 +22,17 @@ void StageManager::initialize() { reset(); } +void StageManager::initialize(const std::string& stages_file) { + stages_.clear(); + + // Intentar cargar desde archivo, si falla usar valores predeterminados + if (!loadStagesFromFile(stages_file)) { + createDefaultStages(); + } + + reset(); +} + void StageManager::reset() { current_power_ = 0; total_power_ = 0; @@ -29,7 +42,7 @@ void StageManager::reset() { } void StageManager::createDefaultStages() { - // Crear las 10 fases como en tu código original + // Crear las 10 fases predeterminadas con dificultad progresiva stages_.emplace_back(200, 7 + (4 * 1), 7 + (4 * 3), "Tutorial"); stages_.emplace_back(300, 7 + (4 * 2), 7 + (4 * 4), "Primeros pasos"); stages_.emplace_back(600, 7 + (4 * 3), 7 + (4 * 5), "Intensificación"); @@ -42,6 +55,69 @@ void StageManager::createDefaultStages() { stages_.emplace_back(950, 7 + (4 * 7), 7 + (4 * 10), "Maestría"); } +bool StageManager::loadStagesFromFile(const std::string& filename) { + std::ifstream file(filename); + if (!file.is_open()) { + return false; // No se pudo abrir el archivo + } + + std::string line; + int line_number = 0; + + while (std::getline(file, line)) { + line_number++; + + // Ignorar líneas vacías y comentarios (líneas que empiezan con #) + if (line.empty() || line[0] == '#') { + continue; + } + + // Parsear línea: power_to_complete,min_menace,max_menace,name + std::stringstream ss(line); + std::string token; + std::vector tokens; + + // Dividir por comas + while (std::getline(ss, token, ',')) { + // Eliminar espacios en blanco al inicio y final + token.erase(0, token.find_first_not_of(" \t")); + token.erase(token.find_last_not_of(" \t") + 1); + tokens.push_back(token); + } + + // Verificar que tenemos exactamente 4 campos + if (tokens.size() != 4) { + // Error de formato, continuar con la siguiente línea + continue; + } + + try { + // Convertir a enteros los primeros tres campos + int power_to_complete = std::stoi(tokens[0]); + int min_menace = std::stoi(tokens[1]); + int max_menace = std::stoi(tokens[2]); + std::string name = tokens[3]; + + // Validar valores + if (power_to_complete <= 0 || min_menace < 0 || max_menace < min_menace) { + continue; // Valores inválidos, saltar línea + } + + // Crear y añadir la fase + stages_.emplace_back(power_to_complete, min_menace, max_menace, name); + + } catch (const std::exception&) { + // Error de conversión, continuar con la siguiente línea + continue; + } + } + + file.close(); + + // Verificar que se cargó al menos una fase + return !stages_.empty(); +} + bool StageManager::advanceToNextStage() { if (!isCurrentStageCompleted() || current_stage_index_ >= stages_.size() - 1) { return false; @@ -58,7 +134,7 @@ bool StageManager::jumpToStage(size_t target_stage_index) { return false; } - // Calcular el poder total acumulado hasta la fase objetivo + // Calcular el poder acumulado hasta la fase objetivo int accumulated_power = 0; for (size_t i = 0; i < target_stage_index; ++i) { accumulated_power += stages_[i].getPowerToComplete(); @@ -66,8 +142,8 @@ bool StageManager::jumpToStage(size_t target_stage_index) { // Actualizar estado current_stage_index_ = target_stage_index; - current_power_ = 0; // Empezar la fase objetivo sin poder - total_power_ = accumulated_power; // Poder total como si hubiéramos completado las anteriores + current_power_ = 0; // Comenzar la fase objetivo sin poder + total_power_ = accumulated_power; // Poder total como si se hubieran completado las anteriores updateStageStatuses(); return true; @@ -118,7 +194,7 @@ bool StageManager::isGameCompleted() const { double StageManager::getProgressPercentage() const { if (stages_.empty()) return 0.0; - int total_power_needed = getTotalPowerNeededToCompleteGame(); // ⬅️ Usar el nuevo método + int total_power_needed = getTotalPowerNeededToCompleteGame(); if (total_power_needed == 0) return 100.0; return (static_cast(total_power_) / total_power_needed) * 100.0; @@ -139,7 +215,7 @@ double StageManager::getCurrentStageProgressFraction() const { return 1.0; } - // Retorna fracción entre 0.0 y 1.0 + // Devuelve una fracción entre 0.0 y 1.0 double fraction = static_cast(current_power_) / power_needed; return std::min(fraction, 1.0); } @@ -161,7 +237,7 @@ int StageManager::getTotalPowerNeededToCompleteGame() const { return total_power_needed; } -// ===== IMPLEMENTACIÓN DE IStageInfo (lo que ven Player y Balloon) ===== +// Implementación de la interfaz IStageInfo bool StageManager::canCollectPower() const { return power_collection_state_ == PowerCollectionState::ENABLED; } @@ -174,9 +250,10 @@ void StageManager::addPower(int amount) { current_power_ += amount; total_power_ += amount; + // Ejecutar callback si está registrado if (power_change_callback_) { - power_change_callback_(amount); -} + power_change_callback_(amount); + } // Verificar si se completó la fase actual if (isCurrentStageCompleted()) { @@ -198,12 +275,22 @@ int StageManager::getCurrentMenaceLevel() const { return current_stage->getMinMenace(); } -// ===== MÉTODOS PRIVADOS ===== +// Gestión de callbacks +void StageManager::setPowerChangeCallback(PowerChangeCallback callback) { + power_change_callback_ = callback; +} + +void StageManager::removePowerChangeCallback() { + power_change_callback_ = nullptr; +} + +// Métodos privados bool StageManager::validateStageIndex(size_t index) const { return index < stages_.size(); } void StageManager::updateStageStatuses() { + // Actualizar el estado de cada fase según su posición relativa a la actual for (size_t i = 0; i < stages_.size(); ++i) { if (i < current_stage_index_) { stages_[i].setStatus(StageStatus::COMPLETED); @@ -213,12 +300,4 @@ void StageManager::updateStageStatuses() { stages_[i].setStatus(StageStatus::LOCKED); } } -} - -void StageManager::setPowerChangeCallback(PowerChangeCallback callback) { - power_change_callback_ = callback; -} - -void StageManager::removePowerChangeCallback() { - power_change_callback_ = nullptr; } \ No newline at end of file diff --git a/source/stage.h b/source/stage.h index bf478d5..5106dd9 100644 --- a/source/stage.h +++ b/source/stage.h @@ -4,98 +4,108 @@ #include #include #include -#include // ⬅️ Para std::function +#include +// --- Estados posibles para la recolección de poder --- enum class PowerCollectionState { - ENABLED, - DISABLED + ENABLED, // Recolección habilitada + DISABLED // Recolección deshabilitada }; +// --- Estados posibles para una fase del juego --- enum class StageStatus { - LOCKED, - IN_PROGRESS, - COMPLETED + LOCKED, // Fase bloqueada + IN_PROGRESS, // Fase en progreso + COMPLETED // Fase completada }; +// --- Representa los datos de una fase del juego --- class StageData { private: - int power_to_complete_; - int min_menace_; - int max_menace_; - std::string name_; - StageStatus status_; + int power_to_complete_; // Poder necesario para completar la fase + int min_menace_; // Nivel mínimo de amenaza + int max_menace_; // Nivel máximo de amenaza + std::string name_; // Nombre de la fase + StageStatus status_; // Estado actual de la fase public: + // Constructor de una fase StageData(int power_to_complete, int min_menace, int max_menace, const std::string& name = ""); - // Getters + // --- Getters --- int getPowerToComplete() const { return power_to_complete_; } int getMinMenace() const { return min_menace_; } int getMaxMenace() const { return max_menace_; } const std::string& getName() const { return name_; } StageStatus getStatus() const { return status_; } - // Setters + // --- Setters --- void setStatus(StageStatus status) { status_ = status; } - // Utilidades + // --- Utilidades --- bool isCompleted() const { return status_ == StageStatus::COMPLETED; } }; -class StageManager : public IStageInfo { // ⬅️ Hereda de la interfaz +// --- Gestor principal del sistema de fases del juego --- +class StageManager : public IStageInfo { private: - std::vector stages_; - int current_power_; - int total_power_; - size_t current_stage_index_; - PowerCollectionState power_collection_state_; + std::vector stages_; // Lista de todas las fases + int current_power_; // Poder actual en la fase activa + int total_power_; // Poder total acumulado en todo el juego + size_t current_stage_index_; // Índice de la fase actual + PowerCollectionState power_collection_state_; // Estado de recolección de poder public: + using PowerChangeCallback = std::function; + StageManager(); - // Métodos principales para Game - void initialize(); - void reset(); - bool advanceToNextStage(); + // --- Métodos principales del juego --- + void initialize(); // Inicializa el gestor de fases + void initialize(const std::string& stages_file); // Inicializa con archivo personalizado + void reset(); // Reinicia el progreso del juego + bool advanceToNextStage(); // Avanza a la siguiente fase - // Gestión de poder - bool subtractPower(int amount); - void enablePowerCollection(); - void disablePowerCollection(); + // --- Gestión de poder --- + bool subtractPower(int amount); // Resta poder de la fase actual + void enablePowerCollection(); // Habilita la recolección de poder + void disablePowerCollection(); // Deshabilita la recolección de poder - // Navegación avanzada - bool jumpToStage(size_t target_stage_index); + // --- Navegación --- + bool jumpToStage(size_t target_stage_index); // Salta a una fase específica - // Consultas de estado - std::optional getCurrentStage() const; - std::optional getStage(size_t index) const; + // --- Consultas de estado --- + std::optional getCurrentStage() const; // Obtiene la fase actual + std::optional getStage(size_t index) const; // Obtiene una fase específica size_t getCurrentStageIndex() const { return current_stage_index_; } int getCurrentPower() const { return current_power_; } int getTotalPower() const { return total_power_; } - int getTotalPowerNeededToCompleteGame() const; // ⬅️ Nuevo método + int getTotalPowerNeededToCompleteGame() const; // Poder total necesario para completar el juego size_t getTotalStages() const { return stages_.size(); } - // Progreso - bool isCurrentStageCompleted() const; - bool isGameCompleted() const; - double getProgressPercentage() const; // Progreso total del juego + // --- Seguimiento de progreso --- + bool isCurrentStageCompleted() const; // Verifica si la fase actual está completada + bool isGameCompleted() const; // Verifica si el juego está completado + double getProgressPercentage() const; // Progreso total del juego (0-100%) double getCurrentStageProgressPercentage() const; // Progreso de la fase actual (0-100%) double getCurrentStageProgressFraction() const; // Progreso de la fase actual (0.0-1.0) - int getPowerNeededForCurrentStage() const; + int getPowerNeededForCurrentStage() const; // Poder restante para completar la fase actual - // ===== IMPLEMENTACIÓN DE IStageInfo ===== - // (Esto es lo que ven Player y Balloon) + // --- Gestión de callbacks --- + void setPowerChangeCallback(PowerChangeCallback callback); // Establece callback para cambios de poder + void removePowerChangeCallback(); // Elimina callback de cambios de poder + + // --- Implementación de la interfaz IStageInfo --- bool canCollectPower() const override; void addPower(int amount) override; int getCurrentMenaceLevel() const override; -using PowerChangeCallback = std::function; -void setPowerChangeCallback(PowerChangeCallback callback); -void removePowerChangeCallback(); private: -PowerChangeCallback power_change_callback_; + PowerChangeCallback power_change_callback_; // Callback para notificar cambios de poder - void createDefaultStages(); - bool validateStageIndex(size_t index) const; - void updateStageStatuses(); + // --- Métodos privados --- + void createDefaultStages(); // Crea las fases predeterminadas del juego + bool loadStagesFromFile(const std::string& filename); // Carga fases desde archivo + bool validateStageIndex(size_t index) const; // Valida que un índice de fase sea válido + void updateStageStatuses(); // Actualiza los estados de todas las fases }; \ No newline at end of file diff --git a/source/stage_interface.h b/source/stage_interface.h index 5c99936..dc6c308 100644 --- a/source/stage_interface.h +++ b/source/stage_interface.h @@ -1,14 +1,18 @@ #pragma once -// Interfaz simple para lo que necesitan Player y Balloon +/** + * Interfaz para acceso a información de fases. + * Proporciona una API mínima para componentes que necesitan interactuar con datos de fases + * sin requerir acceso a toda la funcionalidad de StageManager. + */ class IStageInfo { public: virtual ~IStageInfo() = default; - // Lo que necesita Player para recolectar poder + // Interfaz de recolección de poder virtual bool canCollectPower() const = 0; virtual void addPower(int amount) = 0; - // Lo que necesitan Player y Balloon para ajustar comportamiento + // Ajuste de comportamiento del gameplay virtual int getCurrentMenaceLevel() const = 0; }; \ No newline at end of file