diff --git a/.github/workflows/test_check.yml b/.github/workflows/test_check.yml index 9676099..8637752 100644 --- a/.github/workflows/test_check.yml +++ b/.github/workflows/test_check.yml @@ -5,7 +5,7 @@ on: push: branches: [master] pull_request: - branches: [master] + types: [opened, ready_for_review, reopened] jobs: build-test: diff --git a/CMakeLists.txt b/CMakeLists.txt index 49c0947..18a4259 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,6 +21,7 @@ add_executable(${CMAKE_PROJECT_NAME} ${SRC_FILES}) target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE "${CMAKE_SOURCE_DIR}/include") target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE "${CMAKE_SOURCE_DIR}/include/dataStructures") target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE "${CMAKE_SOURCE_DIR}/include/characters") +target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE "${CMAKE_SOURCE_DIR}/include/engine") # Copia todos los archivos de la carpeta assets al directorio de ejecución add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD @@ -45,7 +46,8 @@ if (ENABLE_TESTS) target_include_directories(unit_tests PRIVATE "${CMAKE_SOURCE_DIR}/include") target_include_directories(unit_tests PRIVATE "${CMAKE_SOURCE_DIR}/include/dataStructures") - target_include_directories(unit_tests PRIVATE "${CMAKE_SOURCE_DIR}/include/characters") + target_include_directories(unit_tests PRIVATE "${CMAKE_SOURCE_DIR}/include/characters") + target_include_directories(unit_tests PRIVATE "${CMAKE_SOURCE_DIR}/include/engine") enable_testing() diff --git a/assets/system.conf b/assets/system.conf index 9b67eaf..587e774 100644 --- a/assets/system.conf +++ b/assets/system.conf @@ -16,6 +16,9 @@ enemyHealthMultiplier=1.3 ; Multiplicador de salud enemigo enemyLootMultiplier=1.5 ; Multiplicador de botín enemigo enemyExperienceMultiplier=1.5 ; Multiplicador de experiencia enemigo luckyFactor=1.2 ; Factor de suerte para el jugador +minEnemy=1 ; Cantidad minima de enemigos +maxEnemy=4 ; Cantidad maxima de enemigos +surrenderChance=0.10 ; Chances de que se rinda un grupo de asaltantes [resources] successRate=0.50 ; Probabilidad de éxito al recolectar recursos (0.0 - 1.0) @@ -24,9 +27,15 @@ badLuckChance=0.20 ; Probabilidad de mala suerte al recolectar durationFactor=1.5 ; Factor de duración de la recolección [shelter] -defenseFactor=1.5; Factor de defensa del refugio -attackFactor=1.2; Factor de ataque del refugio -visitantsRate=0.10; Tasa de visitantes al refugio +defenseFactor=1; Factor de defensa del refugio +attackFactor=1; Factor de ataque del refugio -# === FIN DEL ARCHIVO === +[events] +eventsPerSecond=1; Cantidad de eventor por segundo +rateRefugee=0.10; Tasa de visitantes del tipo refugiado +rateBrother=0.05; Tasa de visitantes del tipo hermanos +rateEnemy=0.50; Tasa de visitantes del tipo enemigo +rateCommerce=0.70; Tasa de visitantes del tipo comerciantes +rateCaravane=0.02; Tasa de visitantes del tipo caravana +# === FIN DEL ARCHIVO === diff --git a/include/characters/artefactoUnico.hpp b/include/characters/artefactoUnico.hpp index 9a52f73..aa73f8c 100644 --- a/include/characters/artefactoUnico.hpp +++ b/include/characters/artefactoUnico.hpp @@ -1,11 +1,13 @@ #ifndef ARTEFACTOUNICO_HPP #define ARTEFACTOUNICO_HPP -#include "engineData.hpp" -#include "entidadGenerica.hpp" +#include #include #include +#include "engine/engineData.hpp" +#include "entidadGenerica.hpp" + /** * @class ArtefactoUnico * @brief Representa un artefacto único dentro del universo de Refugio 33. @@ -16,7 +18,6 @@ class ArtefactoUnico : public EntidadGenerica { private: - std::string m_rarity; ///< Rareza del artefacto (por ejemplo: "Legendario", "Prototipo", "Desconocido") EngineData::UniqueArtifactType m_type; ///< Tipo de artefacto (por ejemplo: "Tecnología", "Arma", "Medicina", "Módulo de defensa") double m_durability; ///< Nivel de durabilidad restante del artefacto (de 0.0 a 100.0) @@ -25,16 +26,11 @@ class ArtefactoUnico : public EntidadGenerica /** * @brief Constructor del artefacto único * @param name Nombre del artefacto - * @param rarity Rareza del artefacto * @param type Tipo del artefacto * @param durability Durabilidad inicial */ - ArtefactoUnico(const std::string& name, - const std::string& rarity, - const EngineData::UniqueArtifactType type, - double durability) + explicit ArtefactoUnico(const std::string& name, const EngineData::UniqueArtifactType type, double durability) : EntidadGenerica(name) - , m_rarity(rarity) , m_type(type) , m_durability(durability) { @@ -46,22 +42,8 @@ class ArtefactoUnico : public EntidadGenerica void showInfo() const override { std::cout << "🧪 Artefacto: " << m_name << "\n" - << " - Tipo : " << typeToString(m_type) << "\n" - << " - Rareza : " << m_rarity << "\n" - << " - Durabilidad: " << m_durability << "%" << std::endl; - } - - std::string_view typeToString(EngineData::UniqueArtifactType type) const - { - switch (type) - { - case EngineData::UniqueArtifactType::WEAPON: return "Arma"; - case EngineData::UniqueArtifactType::ARMOR: return "Armadura"; - case EngineData::UniqueArtifactType::VEHICLE: return "Vehículo"; - case EngineData::UniqueArtifactType::RELIC: return "Reliquia"; - case EngineData::UniqueArtifactType::TECHNOLOGY: return "Tecnología"; - default: return "Desconocido"; - } + << " - Tipo : " << EngineData::valueToString(m_type) << "\n" + << " - Durabilidad: " << m_durability << "%" << '\n'; } /** @@ -71,8 +53,7 @@ class ArtefactoUnico : public EntidadGenerica void use(double amount) { m_durability -= amount; - if (m_durability < 0.0) - m_durability = 0.0; + m_durability = std::max(m_durability, 0.0); } /** diff --git a/include/characters/asaltante.hpp b/include/characters/asaltante.hpp index b9a01ac..d545521 100644 --- a/include/characters/asaltante.hpp +++ b/include/characters/asaltante.hpp @@ -1,9 +1,10 @@ #ifndef RAIDER_HPP #define RAIDER_HPP -#include "entidadGenerica.hpp" #include -#include + +#include "entidadGenerica.hpp" +#include "randomEventGenerator.hpp" /** * @class Raider @@ -15,22 +16,28 @@ class Raider : public EntidadGenerica { private: - int m_integrantes; ///< Cantidad de miembros en la banda - int m_poderFuego; ///< Nivel de ataque general - bool m_rendidos; ///< Indica si se han rendido - bool m_seUnieron; ///< Indica si fueron aceptados en el refugio + int m_integrantes; ///< Cantidad de miembros en la banda + double m_fireFactor; ///< Nivel de ataque general + bool m_rendidos {false}; ///< Indica si se han rendido + bool m_seUnieron {false}; ///< Indica si fueron aceptados en el refugio + double m_rendicionChance; ///< Probabilidad de rendición + RandomEventGenerator* m_randomgenerator {nullptr}; ///< Generador de eventos aleatorios public: /** * @brief Constructor * @param nombre Nombre del grupo raider */ - explicit Raider(const std::string& nombre) + explicit Raider(const std::string& nombre, + int integrantes, + RandomEventGenerator* randomGenerator, + double poderFuego, + double rendicionChance) : EntidadGenerica(nombre) - , m_integrantes(generarCantidad()) - , m_poderFuego(generarPoder()) - , m_rendidos(false) - , m_seUnieron(false) + , m_integrantes(integrantes) + , m_fireFactor(poderFuego) + , m_rendicionChance(rendicionChance) + , m_randomgenerator(randomGenerator) // 30% de posibilidad de rendirse { } @@ -41,7 +48,7 @@ class Raider : public EntidadGenerica { std::cout << "🔫 RAIDERS: " << m_name << "\n" << " - Miembros: " << m_integrantes << "\n" - << " - Poder de fuego: " << m_poderFuego << "\n" + << " - Factor de fuego: " << m_fireFactor << "\n" << " - ¿Rendidos?: " << (m_rendidos ? "Sí" : "No") << "\n" << " - ¿Se unieron al refugio?: " << (m_seUnieron ? "Sí" : "No") << "\n"; } @@ -51,17 +58,14 @@ class Raider : public EntidadGenerica */ void intentarRendicion() { - static std::mt19937 rng(std::random_device {}()); - std::bernoulli_distribution chance(0.3); // 30% de posibilidad de rendirse - - if (chance(rng)) + if (m_randomgenerator->chance(m_rendicionChance)) { m_rendidos = true; - std::cout << "💬 " << m_name << " >>> ¡Nos rendimos! ¡Déjennos vivir!" << std::endl; + std::cout << "💬 " << m_name << " >>> ¡Nos rendimos! ¡Déjennos vivir!" << '\n'; } else { - std::cout << "💬 " << m_name << " >>> ¡Nunca nos rendiremos!" << std::endl; + std::cout << "💬 " << m_name << " >>> ¡Nunca nos rendiremos!" << '\n'; } } @@ -73,11 +77,11 @@ class Raider : public EntidadGenerica if (m_rendidos) { m_seUnieron = true; - std::cout << "✅ Los raiders se han unido al refugio. Serán vigilados de cerca..." << std::endl; + std::cout << "✅ Los raiders se han unido al refugio. Serán vigilados de cerca..." << '\n'; return true; } - std::cout << "❌ No se puede aceptar a un grupo hostil sin rendirse." << std::endl; + std::cout << "❌ No se puede aceptar a un grupo hostil sin rendirse." << '\n'; return false; } @@ -86,7 +90,7 @@ class Raider : public EntidadGenerica */ int poderTotal() const { - return m_integrantes * m_poderFuego; + return static_cast(m_integrantes * m_fireFactor); } bool estanRendidos() const @@ -97,21 +101,6 @@ class Raider : public EntidadGenerica { return m_seUnieron; } - -private: - int generarCantidad() const - { - static std::mt19937 rng(std::random_device {}()); - std::uniform_int_distribution dist(10, 15); - return dist(rng); - } - - int generarPoder() const - { - static std::mt19937 rng(std::random_device {}()); - std::uniform_int_distribution dist(15, 30); - return dist(rng); - } }; #endif // RAIDER_HPP diff --git a/include/characters/caravan.hpp b/include/characters/caravan.hpp deleted file mode 100644 index a00ba9b..0000000 --- a/include/characters/caravan.hpp +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef CARAVAN_HPP -#define CARAVAN_HPP - -#include "artefactoUnico.hpp" -#include "entidadGenerica.hpp" -#include -#include -#include - -/** - * @class Caravana - * @brief Representa a los comerciantes itinerantes de artefactos únicos. - * - * La caravana viaja por el yermo ofreciendo artículos extremadamente raros a precios elevados. - */ -class Caravana : public EntidadGenerica -{ -private: - std::vector> m_stock; ///< Lista de artefactos únicos disponibles - bool m_confia; ///< Confianza en el refugio - -public: - /** - * @brief Constructor - * @param nombre Nombre de la caravana - * @param confia Indica si la caravana está dispuesta a comerciar - */ - Caravana(const std::string& nombre, bool confia) - : EntidadGenerica(nombre) - , m_confia(confia) - { - inicializarStock(); - } - - /** - * @brief Muestra el inventario de la caravana - */ - void showInfo() const override - { - std::cout << "🚚 Caravana: " << m_name << "\n"; - std::cout << " - Confianza: " << (m_confia ? "Sí" : "No") << "\n"; - std::cout << " - Artefactos disponibles:\n"; - for (const auto& item : m_stock) - { - item->show(); - } - } - - /** - * @brief Intenta comprar un artefacto - * @param nombre Nombre del artefacto - * @return Puntero al artefacto si se realizó la transacción, nullptr en caso contrario - */ - std::shared_ptr comprarArtefacto(const std::string& nombre) - { - if (!m_confia) - { - std::cout << "💬 " << m_name << " >>> No confiamos lo suficiente en tu refugio para hacer negocios." - << std::endl; - return nullptr; - } - - for (auto it = m_stock.begin(); it != m_stock.end(); ++it) - { - if ((*it)->nombre() == nombre) - { - std::cout << "💬 " << m_name << " >>> Excelente elección. Espero que lo uses bien." << std::endl; - auto item = *it; - m_stock.erase(it); - return item; - } - } - - std::cout << "💬 " << m_name << " >>> No tenemos ese artefacto en este momento." << std::endl; - return nullptr; - } - - /** - * @brief Simula una evaluación de confianza futura - */ - void evaluarConfianza() - { - m_confia = true; // Lógica temporal, puede depender del nivel del refugio - } - -private: - void inicializarStock() - { - m_stock.emplace_back(std::make_shared("Detector de Radiación", "Herramienta", "Épico", 250.0)); - m_stock.emplace_back(std::make_shared("Pistola Láser Táctica", "Arma", "Legendaria", 400.0)); - m_stock.emplace_back(std::make_shared("Batería de Fusión", "Energía", "Rara", 320.0)); - } -}; - -#endif // CARAVAN_HPP diff --git a/include/characters/caravana.hpp b/include/characters/caravana.hpp deleted file mode 100644 index 22bef5c..0000000 --- a/include/characters/caravana.hpp +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef CARAVAN_HPP -#define CARAVAN_HPP - -#include "artefactoUnico.hpp" -#include "entidadGenerica.hpp" -#include -#include -#include - -/** - * @class Caravana - * @brief Representa a los comerciantes itinerantes de artefactos únicos. - * - * La caravana viaja por el yermo ofreciendo artículos extremadamente raros a precios elevados. - */ -class Caravana : public EntidadGenerica -{ -private: - std::vector> m_stock; ///< Lista de artefactos únicos disponibles - bool m_confia; ///< Confianza en el refugio - -public: - /** - * @brief Constructor - * @param nombre Nombre de la caravana - * @param confia Indica si la caravana está dispuesta a comerciar - */ - Caravana(const std::string& nombre, bool confia); - /** - * @brief Muestra el inventario de la caravana - */ - void showInfo() const override; - - /** - * @brief Intenta comprar un artefacto - * @param nombre Nombre del artefacto - * @return Puntero al artefacto si se realizó la transacción, nullptr en caso contrario - */ - std::shared_ptr comprarArtefacto(const std::string& nombre); - - /** - * @brief Simula una evaluación de confianza futura - */ - void evaluarConfianza(); - -private: - void inicializarStock(); -}; - -#endif // CARAVAN_HPP diff --git a/include/characters/chracterVisitant.hpp b/include/characters/chracterVisitant.hpp deleted file mode 100644 index 022754b..0000000 --- a/include/characters/chracterVisitant.hpp +++ /dev/null @@ -1,51 +0,0 @@ -// -// Created by gvalenzuela on 3/30/25. -// - -#ifndef CHRACTERVISITANT_HPP -#define CHRACTERVISITANT_HPP - -#include "characters/artefactoUnico.hpp" -#include "characters/asaltante.hpp" -#include "characters/caravana.hpp" -#include "characters/enclave.hpp" -#include "characters/ghoul.hpp" -#include "characters/hermanosDeAcero.hpp" -#include "characters/mercader.hpp" -#include "characters/mercaderAgua.hpp" -#include "characters/mutantes.hpp" -#include "characters/refugiado.hpp" -#include "characters/refugio.hpp" -#include "characters/saqueador.hpp" - -using VisitanteVariant = std::variant< -Refugiado, -Mercader, -MercaderAgua, -Saqueador, -HermanoAcero, -Enclave, -Mutante, -Asaltante, -Ghoul, -Caravana ->; - -namespace NPC { - enum class VisitantCategory - { - REFUGEE, - BROTHER, - ENEMY, - MERCHANT, - CARAVAN - }; - - struct VisitantChance - { - VisitantCategory type; - double weight; - }; -}; - -#endif //CHRACTERVISITANT_HPP diff --git a/include/characters/enclave.hpp b/include/characters/enclave.hpp deleted file mode 100644 index 7fc4e0f..0000000 --- a/include/characters/enclave.hpp +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef ENCLAVE_HPP -#define ENCLAVE_HPP - -#include "entidadGenerica.hpp" -#include -#include - -/** - * @class Enclave - * @brief Representa una fuerza de combate de la facción ENCLAVE. - * - * Altamente equipada y letal, no se puede razonar con ellos. Atacan con fuerza total - * y su presencia representa un peligro inmediato para el refugio. - */ -class Enclave : public EntidadGenerica -{ -private: - int m_fuerza; ///< Cantidad de soldados (entre 10 y 50) - double m_potencia; ///< Nivel de potencia de fuego estimado (escala 1.0 a 5.0) - bool m_detectado; ///< Si han detectado el refugio - -public: - /** - * @brief Constructor - * @param nombre Nombre del escuadrón - */ - explicit Enclave(const std::string& nombre); - - /** - * @brief Muestra información de la escuadra ENCLAVE - */ - void showInfo() const override; - - /** - * @brief Simula la detección del refugio - */ - void detectarRefugio(); - - /** - * @brief Devuelve si la escuadra ya ha detectado el refugio - */ - bool haDetectado() const; - - /** - * @brief Devuelve la fuerza de combate - */ - int fuerza() const; - /** - * @brief Devuelve la potencia de ataque - */ - double potencia() const; - -private: - /** - * @brief Genera aleatoriamente una cantidad de soldados entre 10 y 50 - */ - int generarFuerza(); - /** - * @brief Genera aleatoriamente un valor de potencia entre 2.5 y 5.0 - */ - double generarPotencia() const; -}; - -#endif // ENCLAVE_HPP diff --git a/include/characters/entidadGenerica.hpp b/include/characters/entidadGenerica.hpp index 4b6da9f..3d77019 100644 --- a/include/characters/entidadGenerica.hpp +++ b/include/characters/entidadGenerica.hpp @@ -30,6 +30,12 @@ class EntidadGenerica */ virtual ~EntidadGenerica() = default; + // Rule of five: explicitly define or delete special member functions + EntidadGenerica(const EntidadGenerica&) = default; // Delete copy constructor + EntidadGenerica& operator=(const EntidadGenerica&) = default; // Delete copy assignment operator + EntidadGenerica(EntidadGenerica&&) noexcept = default; // Default move constructor + EntidadGenerica& operator=(EntidadGenerica&&) noexcept = default; // Default move assignment operator + /** * @brief Muestra la información del ente. Mostrando el nombre y otros atributos */ diff --git a/include/characters/ghoul.hpp b/include/characters/ghoul.hpp deleted file mode 100644 index 5afb8dd..0000000 --- a/include/characters/ghoul.hpp +++ /dev/null @@ -1,103 +0,0 @@ -#ifndef GHOUL_HPP -#define GHOUL_HPP - -#include "entidadGenerica.hpp" -#include -#include - -/** - * @class Ghoul - * @brief Representa una horda de ghouls salvajes. - * - * Los ghouls son mutantes desfigurados que actúan por instinto. - * Aunque débiles individualmente, en grupo son extremadamente peligrosos. - */ -class Ghoul : public EntidadGenerica -{ -private: - int m_cantidad; ///< Número de ghouls en la horda - int m_saludBase; ///< Salud individual promedio - int m_danyoBase; ///< Daño individual promedio - -public: - /** - * @brief Constructor - * @param nombre Nombre de la horda o designación - */ - explicit Ghoul(const std::string& nombre) - : EntidadGenerica(nombre) - , m_cantidad(generarCantidad()) - , m_saludBase(generarSalud()) - , m_danyoBase(generarDanyo()) - { - } - - /** - * @brief Muestra la información general de la horda - */ - void showInfo() const override - { - std::cout << "☣️ HORDA DE GHOULS: " << m_name << "\n" - << " - Individuos: " << m_cantidad << "\n" - << " - Salud por ghoul: " << m_saludBase << "\n" - << " - Daño por ghoul: " << m_danyoBase << "\n"; - } - - /** - * @brief Daño total que puede causar la horda - */ - int danyoTotal() const - { - return m_danyoBase * m_cantidad; - } - - /** - * @brief Simula una reducción del tamaño de la horda - * @param eliminados Cantidad de ghouls eliminados - */ - void eliminarGhouls(int eliminados) - { - m_cantidad -= eliminados; - if (m_cantidad <= 0) - { - m_cantidad = 0; - std::cout << "☠️ ¡La horda ha sido completamente aniquilada!" << std::endl; - } - else - { - std::cout << "⚠️ Han sido eliminados " << eliminados << " ghouls. Restan: " << m_cantidad << std::endl; - } - } - - /** - * @brief Devuelve si la horda sigue siendo una amenaza - */ - bool sigueActiva() const - { - return m_cantidad > 0; - } - -private: - int generarCantidad() const - { - static std::mt19937 rng(std::random_device {}()); - std::uniform_int_distribution dist(30, 100); - return dist(rng); - } - - int generarSalud() const - { - static std::mt19937 rng(std::random_device {}()); - std::uniform_int_distribution dist(10, 20); - return dist(rng); - } - - int generarDanyo() const - { - static std::mt19937 rng(std::random_device {}()); - std::uniform_int_distribution dist(1, 3); - return dist(rng); - } -}; - -#endif // GHOUL_HPP diff --git a/include/characters/hermanoDeAcero.hpp b/include/characters/hermanoDeAcero.hpp deleted file mode 100644 index 6bae38e..0000000 --- a/include/characters/hermanoDeAcero.hpp +++ /dev/null @@ -1,94 +0,0 @@ -#ifndef HERMANO_ACERO_HPP -#define HERMANO_ACERO_HPP - -#include "entidadGenerica.hpp" -#include - -/** - * @class HermanoAcero - * @brief Representa a un miembro de la Hermandad del Acero. - * - * Poseen entrenamiento militar avanzado y pueden usar artefactos únicos. - * Requieren muchos recursos y son estrictos con su permanencia en un refugio. - */ -class HermanoAcero : public EntidadGenerica -{ -private: - int m_entrenamiento; ///< Nivel de entrenamiento (impacta en defensa del refugio) - int m_suministros; ///< Recursos necesarios para mantenerlo - bool m_enRefugio; ///< Si actualmente vive en un refugio - int m_consumoMinimo; ///< Cuántos recursos necesita por turno - -public: - /** - * @brief Constructor - * @param nombre Nombre del miembro - * @param entrenamiento Nivel de habilidad (100 por defecto) - */ - HermanoAcero(const std::string& nombre, int entrenamiento = 100) - : EntidadGenerica(nombre) - , m_entrenamiento(entrenamiento) - , m_suministros(80) - , m_enRefugio(false) - , m_consumoMinimo(20) // el doble de lo estándar - { - } - - /** - * @brief Muestra información del hermano del acero - */ - void showInfo() const override - { - std::cout << "⚙️ Hermano del Acero: " << m_name << "\n" - << " - Nivel de entrenamiento: " << m_entrenamiento << "\n" - << " - Suministros actuales: " << m_suministros << "\n" - << " - En refugio: " << (m_enRefugio ? "Sí" : "No") << "\n"; - } - - /** - * @brief Intenta ingresar al refugio - * @param recursosDisponibles Recursos disponibles del refugio - * @return Recursos consumidos, o 0 si no fue aceptado - */ - int solicitarIngreso(int recursosDisponibles) - { - if (recursosDisponibles >= m_consumoMinimo) - { - m_enRefugio = true; - std::cout << "💬" << m_name << " >>> Por la tecnología, serviré a este refugio." << std::endl; - return m_consumoMinimo; - } - else - { - std::cout << "💬" << m_name << " >>> Sus recursos no están a la altura de la Hermandad." << std::endl; - return 0; - } - } - - /** - * @brief Consume recursos cada ciclo, si no hay suficientes abandona el refugio - */ - void consumir() - { - if (m_suministros >= m_consumoMinimo) - { - m_suministros -= m_consumoMinimo; - std::cout << "💬" << m_name << " >>> Reabastecido. Listo para defender." << std::endl; - } - else - { - m_enRefugio = false; - std::cout << "💬" << m_name << " >>> Sin suministros. Este refugio no merece protección." << std::endl; - } - } - - /** - * @brief Saber si está aún en el refugio - */ - bool estaEnRefugio() const - { - return m_enRefugio; - } -}; - -#endif // HERMANO_ACERO_HPP diff --git a/include/characters/hermanosDeAcero.hpp b/include/characters/hermanosDeAcero.hpp deleted file mode 100644 index 920862c..0000000 --- a/include/characters/hermanosDeAcero.hpp +++ /dev/null @@ -1,94 +0,0 @@ -#ifndef HERMANO_ACERO_HPP -#define HERMANO_ACERO_HPP - -#include "entidadGenerica.hpp" -#include - -/** - * @class HermanoAcero - * @brief Representa a un miembro de la Hermandad del Acero. - * - * Poseen entrenamiento militar avanzado y pueden usar artefactos únicos. - * Requieren muchos recursos y son estrictos con su permanencia en un refugio. - */ -class HermanoAcero : public EntidadGenerica -{ -private: - int m_entrenamiento; ///< Nivel de entrenamiento (impacta en defensa del refugio) - double m_suministros; ///< Recursos necesarios para mantenerlo - bool m_enRefugio; ///< Si actualmente vive en un refugio - int m_consumoMinimo; ///< Cuántos recursos necesita por turno - -public: - /** - * @brief Constructor - * @param nombre Nombre del miembro - * @param entrenamiento Nivel de habilidad (100 por defecto) - */ - HermanoAcero(const std::string& nombre, int entrenamiento = 100) - : EntidadGenerica(nombre) - , m_entrenamiento(entrenamiento) - , m_suministros(0.20f) // 20% de los suministros del refugio - , m_enRefugio(false) - , m_consumoMinimo(20) // el doble de lo estándar - { - } - - /** - * @brief Muestra información del hermano del acero - */ - void showInfo() const override - { - std::cout << "⚙️ Hermano del Acero: " << m_name << "\n" - << " - Nivel de entrenamiento: " << m_entrenamiento << "\n" - << " - Suministros actuales: " << m_suministros << "\n" - << " - En refugio: " << (m_enRefugio ? "Sí" : "No") << "\n"; - } - - /** - * @brief Intenta ingresar al refugio - * @param recursosDisponibles Recursos disponibles del refugio - * @return Recursos consumidos, o 0 si no fue aceptado - */ - int solicitarIngreso(int recursosDisponibles) - { - if (recursosDisponibles >= m_consumoMinimo) - { - m_enRefugio = true; - std::cout << "💬" << m_name << " >>> Por la tecnología, serviré a este refugio." << std::endl; - return m_consumoMinimo; - } - else - { - std::cout << "💬" << m_name << " >>> Sus recursos no están a la altura de la Hermandad." << std::endl; - return 0; - } - } - - /** - * @brief Consume recursos cada ciclo, si no hay suficientes abandona el refugio - */ - void consumir() - { - if (m_suministros >= m_consumoMinimo) - { - m_suministros -= m_consumoMinimo; - std::cout << "💬" << m_name << " >>> Reabastecido. Listo para defender." << std::endl; - } - else - { - m_enRefugio = false; - std::cout << "💬" << m_name << " >>> Sin suministros. Este refugio no merece protección." << std::endl; - } - } - - /** - * @brief Saber si está aún en el refugio - */ - bool estaEnRefugio() const - { - return m_enRefugio; - } -}; - -#endif // HERMANO_ACERO_HPP diff --git a/include/characters/mercader.hpp b/include/characters/mercader.hpp deleted file mode 100644 index 1f9ec8a..0000000 --- a/include/characters/mercader.hpp +++ /dev/null @@ -1,104 +0,0 @@ -#ifndef MERCADER_HPP -#define MERCADER_HPP - -#include "engineData.hpp" -#include "entidadGenerica.hpp" -#include -#include -#include - -/** - * @brief Función auxiliar para convertir enum Resources a string legible - */ -inline std::string resourceToString(EngineData::Resources res) -{ - switch (res) - { - case EngineData::Resources::FOOD: return "comida"; - case EngineData::Resources::WATER: return "agua"; - case EngineData::Resources::MEDICINE: return "medicina"; - case EngineData::Resources::AMMO: return "munición"; - case EngineData::Resources::WEAPONS: return "armas"; - case EngineData::Resources::ARMOR: return "armaduras"; - case EngineData::Resources::TOOLS: return "herramientas"; - case EngineData::Resources::MATERIALS: return "materiales"; - case EngineData::Resources::ELECTRONICS: return "electrónica"; - case EngineData::Resources::ALCHOHOL: return "alcohol"; - default: return "desconocido"; - } -} - -/** - * @class Mercader - * @brief Representa un comerciante general en el mundo post-apocalíptico. - * - * Los Mercaderes ofrecen diversos recursos a cambio de otros. No comercian con agua, y su stock puede variar. - */ -class Mercader : public EntidadGenerica -{ -private: - std::unordered_map m_inventario; ///< Inventario del mercader (recurso → cantidad) - bool m_esAmistoso; ///< Define si el comerciante ofrece descuentos o es neutral - -public: - /** - * @brief Constructor - * @param nombre Nombre del mercader - * @param esAmistoso Indica si es amigable (mejores precios) - */ - Mercader(const std::string& nombre, bool esAmistoso) - : EntidadGenerica(nombre) - , m_esAmistoso(esAmistoso) - { - // Inventario inicial básico (sin agua) - m_inventario[EngineData::Resources::TOOLS] = 10; - m_inventario[EngineData::Resources::AMMO] = 5; - m_inventario[EngineData::Resources::MEDICINE] = 3; - m_inventario[EngineData::Resources::MATERIALS] = 6; - } - - /** - * @brief Muestra información del mercader y su inventario - */ - void showInfo() const override - { - std::cout << "💰 Mercader: " << m_name << "\n" - << " - Inventario:\n"; - for (const auto& [item, cantidad] : m_inventario) - { - std::cout << " * " << resourceToString(item) << ": " << cantidad << "\n"; - } - } - - /** - * @brief Intenta comprar un recurso específico - * @param recurso Nombre del recurso - * @param cantidad Cantidad solicitada - * @return true si la operación es exitosa - */ - bool trade(const EngineData::Resources& recurso, int cantidad) - { - - std::cout << "💬" << m_name << ">>> Tengo lo que necesitas... a un excelente precio." << std::endl; - - if (recurso == EngineData::Resources::WATER) - { - - return false; - } - - if (m_inventario.find(recurso) != m_inventario.end() && m_inventario[recurso] >= cantidad) - { - m_inventario[recurso] -= cantidad; - std::cout << "💬" << m_name << ">>> Excelente compra!" << std::endl; - return true; - } - else - { - std::cout << "💬" << m_name << ">>> Probaremos la próxima vez... No tengo en stock" << std::endl; - return false; - } - } -}; - -#endif // MERCADER_HPP \ No newline at end of file diff --git a/include/characters/mercaderAgua.hpp b/include/characters/mercaderAgua.hpp deleted file mode 100644 index 5560447..0000000 --- a/include/characters/mercaderAgua.hpp +++ /dev/null @@ -1,96 +0,0 @@ -#ifndef MERCADERAGUA_HPP -#define MERCADERAGUA_HPP - -#include "entidadGenerica.hpp" -#include -#include - -/** - * @class MercaderAgua - * @brief Representa un comerciante especializado en el intercambio de agua por otros recursos. - * - * Los Mercaderes de Agua son la única facción que posee acceso constante a reservas potables. - * Son fundamentales para la supervivencia, pero sus precios son elevados. - */ -class MercaderAgua : public EntidadGenerica -{ -private: - int m_unidadesAgua; ///< Cantidad de unidades de agua que posee - double m_tasaCambio; ///< Tasa de cambio (ej: 1 unidad de agua = X unidades de otro recurso) - bool m_esConfiable; ///< Determina si el comerciante es justo o intenta estafar - -public: - /** - * @brief Constructor - * @param nombre Nombre del mercader - * @param agua Cantidad inicial de agua - * @param tasa Tasa de intercambio de agua - * @param confiable ¿Es confiable o especulador? - */ - MercaderAgua(const std::string& nombre, int agua, double tasa, bool confiable) - : EntidadGenerica(nombre) - , m_unidadesAgua(agua) - , m_tasaCambio(tasa) - , m_esConfiable(confiable) - { - } - - /** - * @brief Muestra la información del mercader - */ - void showInfo() const override - { - std::cout << "💧 Mercader de Agua: '" << m_name << "'\n" - << " - Agua disponible : " << m_unidadesAgua << " unidades\n" - << " - Tasa de cambio : 1 agua = " << m_tasaCambio << " recursos\n" - << " - Estado moral : " << (m_esConfiable ? "Confiable" : "Especulador") << "\n"; - - std::cout << "💬" << m_name << ">>> Tengo el agua más pura del Yermo..." << std::endl; - if (m_esConfiable) - { - std::cout << "Ofrezco un trato justo: 1 unidad de agua por " << m_tasaCambio << " unidades de recursos." - << std::endl; - } - else - { - std::cout << "Mmm... esos recursos no valen nada, pero si me das el doble, hablamos." << std::endl; - } - } - - /** - * @brief Rellenar agua - */ - void refillWater(int cantidad) - { - m_unidadesAgua += cantidad; - } - - /** - * @brief Intenta realizar una transacción - * @param recursosDisponibles Recursos que ofrece el jugador - * @return true si la transacción es exitosa - */ - bool trade(int recursosDisponibles) - { - double requerido = m_tasaCambio; - if (!m_esConfiable) - { - requerido *= 2; - } - - if (recursosDisponibles >= requerido && m_unidadesAgua > 0) - { - std::cout << "💬" << m_name << ">>> Bussinesssss" << std::endl; - m_unidadesAgua -= requerido; - return true; - } - else - { - std::cout << "💬" << m_name << ">>> Acaso crees que soy Santa Claus? Vuelve cuando tengas recursos" - << std::endl; - return false; - } - } -}; - -#endif // MERCADERAGUA_HPP diff --git a/include/characters/mutantes.hpp b/include/characters/mutantes.hpp deleted file mode 100644 index ed4803a..0000000 --- a/include/characters/mutantes.hpp +++ /dev/null @@ -1,110 +0,0 @@ -#ifndef MUTANTE_HPP -#define MUTANTE_HPP - -#include "entidadGenerica.hpp" -#include -#include - -/** - * @class Mutante - * @brief Representa un mutante hostil en el yermo. - * - * Los mutantes son enemigos formidables. Generalmente actúan solos o en pareja, - * poseen gran fuerza y resistencia, y rara vez pueden ser derrotados fácilmente. - */ -class Mutante : public EntidadGenerica -{ -private: - int m_salud; ///< Salud del mutante - int m_ataque; ///< Poder de ataque - bool m_enPareja; ///< Si está acompañado por otro mutante - -public: - /** - * @brief Constructor - * @param nombre Nombre del mutante - */ - explicit Mutante(const std::string& nombre) - : EntidadGenerica(nombre) - , m_salud(generarSalud()) - , m_ataque(generarAtaque()) - , m_enPareja(dobleAmenaza()) - { - } - - /** - * @brief Muestra la información del mutante - */ - void showInfo() const override - { - std::cout << "💀 MUTANTE: " << m_name << "\n" - << " - Salud: " << m_salud << "\n" - << " - Ataque: " << m_ataque << "\n" - << " - ¿Está acompañado?: " << (m_enPareja ? "Sí" : "No") << "\n"; - } - - /** - * @brief Devuelve el poder de ataque total del encuentro - */ - int poderTotal() const - { - return m_enPareja ? m_ataque * 2 : m_ataque; - } - - /** - * @brief Devuelve si el mutante está en pareja - */ - bool enPareja() const - { - return m_enPareja; - } - - /** - * @brief Simula el daño recibido por el mutante - * @param dmg Cantidad de daño - */ - void recibirDanyo(int dmg) - { - m_salud -= dmg; - if (m_salud <= 0) - { - std::cout << "☠️ " << m_name << " ha sido derrotado." << std::endl; - } - else - { - std::cout << "⚠️ " << m_name << " recibió " << dmg << " de daño. Salud restante: " << m_salud << std::endl; - } - } - - /** - * @brief Devuelve si el mutante sigue con vida - */ - bool estaVivo() const - { - return m_salud > 0; - } - -private: - int generarSalud() const - { - static std::mt19937 rng(std::random_device {}()); - std::uniform_int_distribution dist(150, 250); - return dist(rng); - } - - int generarAtaque() const - { - static std::mt19937 rng(std::random_device {}()); - std::uniform_int_distribution dist(30, 60); - return dist(rng); - } - - bool dobleAmenaza() const - { - static std::mt19937 rng(std::random_device {}()); - std::bernoulli_distribution coin(0.35); // 35% probabilidad de que venga en pareja - return coin(rng); - } -}; - -#endif // MUTANTE_HPP diff --git a/include/characters/npc.hpp b/include/characters/npc.hpp new file mode 100644 index 0000000..7b11886 --- /dev/null +++ b/include/characters/npc.hpp @@ -0,0 +1,35 @@ +#ifndef NPC_TYPES_HPP +#define NPC_TYPES_HPP + +#include "characters/asaltante.hpp" +#include "characters/refugiado.hpp" +#include +#include + +namespace NPC +{ + using VisitanteVariant = std::variant; + + /** + * @brief: Categorías posibles de visitantes para el sistema de eventos + */ + enum class VisitantCategory : uint8_t + { + REFUGEE, //< Visitantes refugiados + BROTHER, //< Hermanos de acero + ENEMY, //< Enemigos como mutantes, ghouls, enclave, saqueadores + MERCHANT, //< Mercaderes normales o de agua + CARAVAN //< Caravanas con artefactos únicos + }; + + /** + * @brief: Estructura que contiene la categoría y el peso de cada visitante + */ + struct VisitantChance + { + VisitantCategory type; ///< Tipo de visitante + double weight; ///< Peso del visitante + }; +} // namespace NPC + +#endif // NPC_TYPES_HPP diff --git a/include/characters/refugiado.hpp b/include/characters/refugiado.hpp index 83c3d07..a09f348 100644 --- a/include/characters/refugiado.hpp +++ b/include/characters/refugiado.hpp @@ -1,9 +1,17 @@ #ifndef REFUGIADO_HPP #define REFUGIADO_HPP +#include "engine/engineData.hpp" #include "entidadGenerica.hpp" +#include #include #include +#include +#include +#include + +uint8_t constexpr REFUGIADO_MAX_HEALTH {100}; ///< Máximo de salud +uint8_t constexpr REFUGIADO_MIN_HEALTH {80}; ///< Mínimo de salud /** * @class Refugiado @@ -12,25 +20,53 @@ * Los refugiados pueden unirse a un refugio. Necesitan recursos para mantenerse * y, de no tenerlos, buscarán otro refugio donde vivir. */ -class Refugiado : public EntidadGenerica +class Refugee : public EntidadGenerica { private: - int m_maxHealth; ///< Salud del - int m_health; ///< Salud actual del refugiado - int m_supplies; ///< Suministros que posee + int m_maxHealth; ///< Salud del + int m_health {m_maxHealth}; ///< Salud actual del refugiado + std::unordered_map m_bag; bool m_isFromVault; ///< Si proviene de un refugio Vault (más débil) + struct RefugiadoConsumibles + { + uint8_t m_consumeFood {0}; ///< Cantidad de comida consumida + uint8_t m_consumeWater {0}; ///< Cantidad de agua consumida + uint8_t m_consumeMedicine {0}; ///< Cantidad de medicina consumida + uint8_t m_consumeAmmo {0}; ///< Cantidad de municiones consumidas + uint8_t m_consumeTools {0}; ///< Cantidad de armas consumidas + }; + + struct VaultConsumibles + { + uint8_t m_consumeFood {0}; ///< Cantidad de comida consumida + uint8_t m_consumeWater {0}; ///< Cantidad de agua consumida + uint8_t m_consumeMedicine {0}; ///< Cantidad de medicina consumida + uint8_t m_consumeAmmo {0}; ///< Cantidad de municiones consumidas + uint8_t m_consumeTools {0}; ///< Cantidad de armas consumidas + uint8_t m_consumeAlchohol {0}; ///< Cantidad de alcohol consumido + uint8_t m_consumeElectronics {0}; ///< Cantidad de electrónica consumida + uint8_t m_consumeMaterials {0}; ///< Cantidad de materiales consumidos + }; + + std::variant m_consumeRefugee; + public: /** * @brief Constructor del refugiado * @param name Nombre del refugiado * @param isFromVault Indica si proviene de un Vault o de la superficie */ - Refugiado(const std::string& name, bool isFromVault = false) + explicit Refugee(const std::string& name, bool isFromVault, std::unordered_map bag) : EntidadGenerica(name) - , m_maxHealth(isFromVault ? 80 : 100) - , m_supplies(0) + , m_maxHealth(isFromVault ? REFUGIADO_MIN_HEALTH : REFUGIADO_MAX_HEALTH) + , m_bag(std::move(bag)) , m_isFromVault(isFromVault) + , m_consumeRefugee( + isFromVault + ? std::variant {std::in_place_type} + : std::variant {std::in_place_type}) + { } @@ -41,25 +77,98 @@ class Refugiado : public EntidadGenerica { std::cout << "👤 Refugiado: " << m_name << "\n" << " - Salud: " << m_health << "/" << m_maxHealth << "\n" - << " - Suministros: " << m_supplies << "\n" - << " - Origen: " << (m_isFromVault ? "VAULT" : "Superficie") << "\n"; + << " - Origen: " << (m_isFromVault ? "VAULT" : "Superficie") << "\n" + << " - Bolsa de recursos:\n"; + + for (const auto& [resource, quantity] : m_bag) + { + std::cout << "\t\t* " << EngineData::valueToString(resource) << ": " << static_cast(quantity) << "\n"; + } + } + + void setManteinanceSupplies(std::variant supplies) + { + if (m_isFromVault && std::holds_alternative(supplies)) + { + m_consumeRefugee = std::get(supplies); + } + else + { + m_consumeRefugee = std::get(supplies); + } } /** * @brief Consume suministros cada ciclo * @param cantidad Cantidad a consumir */ - void consumeSupplies(int cantidad) + void consumeSupplies(std::variant supplies) { - if (m_supplies >= cantidad) + bool keepInRefugee = true; + + if (m_isFromVault && std::holds_alternative(supplies)) + { + auto& vaultSupplies = std::get(supplies); + auto& refugeeNeeds = std::get(m_consumeRefugee); + + // Verifica y consume cada recurso, si alguno no alcanza, no se puede quedar + if (vaultSupplies.m_consumeFood < refugeeNeeds.m_consumeFood || + vaultSupplies.m_consumeWater < refugeeNeeds.m_consumeWater || + vaultSupplies.m_consumeMedicine < refugeeNeeds.m_consumeMedicine || + vaultSupplies.m_consumeAmmo < refugeeNeeds.m_consumeAmmo || + vaultSupplies.m_consumeTools < refugeeNeeds.m_consumeTools || + vaultSupplies.m_consumeAlchohol < refugeeNeeds.m_consumeAlchohol || + vaultSupplies.m_consumeElectronics < refugeeNeeds.m_consumeElectronics || + vaultSupplies.m_consumeMaterials < refugeeNeeds.m_consumeMaterials) + { + keepInRefugee = false; + } + else + { + vaultSupplies.m_consumeFood -= refugeeNeeds.m_consumeFood; + vaultSupplies.m_consumeWater -= refugeeNeeds.m_consumeWater; + vaultSupplies.m_consumeMedicine -= refugeeNeeds.m_consumeMedicine; + vaultSupplies.m_consumeAmmo -= refugeeNeeds.m_consumeAmmo; + vaultSupplies.m_consumeTools -= refugeeNeeds.m_consumeTools; + vaultSupplies.m_consumeAlchohol -= refugeeNeeds.m_consumeAlchohol; + vaultSupplies.m_consumeElectronics -= refugeeNeeds.m_consumeElectronics; + vaultSupplies.m_consumeMaterials -= refugeeNeeds.m_consumeMaterials; + } + } + else if (!m_isFromVault && std::holds_alternative(supplies)) + { + auto& suppliesBasic = std::get(supplies); + auto& needs = std::get(m_consumeRefugee); + + if (suppliesBasic.m_consumeFood < needs.m_consumeFood || + suppliesBasic.m_consumeWater < needs.m_consumeWater || + suppliesBasic.m_consumeMedicine < needs.m_consumeMedicine || + suppliesBasic.m_consumeAmmo < needs.m_consumeAmmo || + suppliesBasic.m_consumeTools < needs.m_consumeTools) + { + keepInRefugee = false; + } + else + { + suppliesBasic.m_consumeFood -= needs.m_consumeFood; + suppliesBasic.m_consumeWater -= needs.m_consumeWater; + suppliesBasic.m_consumeMedicine -= needs.m_consumeMedicine; + suppliesBasic.m_consumeAmmo -= needs.m_consumeAmmo; + suppliesBasic.m_consumeTools -= needs.m_consumeTools; + } + } + else + { + keepInRefugee = false; // tipo de recurso no coincide con lo que espera el refugiado + } + + if (keepInRefugee) { - m_supplies -= cantidad; - std::cout << "💬" << m_name << " >>> Gracias por mantenerme alimentado." << std::endl; + std::cout << "💬" << m_name << " >>> Gracias por mantenerme alimentado." << '\n'; } else { - m_supplies = 0; - std::cout << "💬" << m_name << " >>> No puedo quedarme sin recursos... buscaré otro lugar." << std::endl; + std::cout << "💬" << m_name << " >>> No puedo quedarme sin recursos... buscaré otro lugar." << '\n'; } } diff --git a/include/characters/refugio.hpp b/include/characters/refugio.hpp index e534a7d..8ebe7ac 100644 --- a/include/characters/refugio.hpp +++ b/include/characters/refugio.hpp @@ -1,15 +1,20 @@ #ifndef REFUGIO_HPP #define REFUGIO_HPP -#include "engine.hpp" -#include "engineData.hpp" -#include "entidadGenerica.hpp" -#include "list.hpp" -#include "wrapperVector.hpp" -#include #include #include +#include "engine/engineData.hpp" + +#include "dataStructures/list.hpp" +#include "dataStructures/wrapperVector.hpp" + +#include "characters/entidadGenerica.hpp" +#include "characters/npc.hpp" +#include "characters/refugiado.hpp" + +uint8_t constexpr REFUGIO_BASE_CAPACITY {10}; ///< Máximo de defensa + /** * @class Refugio * @brief Representa un refugio dentro del Yermo @@ -33,20 +38,17 @@ class Refugio : public EntidadGenerica }; private: - double m_defense; ///< Nivel de defensa del refugio - double m_attack; ///< Capacidad de ataque del refugio - wrapperVector m_refugees; ///< Lista de moradores dentro del refugio + double m_defense; ///< Nivel de defensa del refugio + double m_attack; ///< Capacidad de ataque del refugio + uint64_t m_maxCapacity { + REFUGIO_BASE_CAPACITY}; ///< Maxima capacidad del refugio, determinado por el nivel del jugador + std::vector m_refugees; ///< Lista de moradores dentro del refugio wrapperVector> m_resources; ///< Lista de recursos con su cantidad - DoublyLinkedList* m_visitants; ///< Lista de visitantes registrados + DoublyLinkedList* m_visitants; ///< Lista de visitantes registrados std::string m_leader; ///< Nombre del líder del refugio - void printRecursive(DoublyListNode* mNode); - - /** - * @brief Devuelve la faccion en formato de string para su impresion. - */ - std::string faccionToString(EngineData::Faction faccion) const; + void printRecursive(DoublyListNode* mNode); public: /** @@ -89,11 +91,10 @@ class Refugio : public EntidadGenerica bool consumeResource(const std::string& resource, float amount); /** - * @brief Registra un visitante en el refugio (nombre y facción) - * @param nombre Nombre del visitante - * @param faccion Facción del visitante + * @brief Registra un visitante en el refugio + * @param visitante Visitante a registrar */ - void registerVisitant(const std::string& nombre, EngineData::Faction faccion); + void registerVisitant(const NPC::VisitanteVariant& visitante); /** * @brief Muestra todos los visitantes registrados diff --git a/include/characters/saqueador.hpp b/include/characters/saqueador.hpp deleted file mode 100644 index 31822d0..0000000 --- a/include/characters/saqueador.hpp +++ /dev/null @@ -1,98 +0,0 @@ -#ifndef SAQUEADOR_HPP -#define SAQUEADOR_HPP - -#include "entidadGenerica.hpp" -#include -#include - -/** - * @class Saqueador - * @brief Representa un grupo de saqueadores en el mundo post-apocalíptico. - * - * Los saqueadores pueden presentarse como agresivos, sigilosos u oportunistas. - * Sus fuerzas varían entre 5 y 10 miembros. - */ -class Saqueador : public EntidadGenerica -{ -public: - enum class Estilo - { - AGRESIVO, - SIGILOSO, - OPORTUNISTA - }; - -private: - int m_numMiembros; ///< Número de integrantes del grupo - Estilo m_estilo; ///< Estilo de saqueo del grupo - -public: - /** - * @brief Constructor del saqueador - * @param nombre Nombre del grupo de saqueadores - * @param estilo Estilo de comportamiento del grupo - */ - Saqueador(const std::string& nombre, Estilo estilo) - : EntidadGenerica(nombre) - , m_estilo(estilo) - , m_numMiembros(randomGroupSize()) - { - } - - /** - * @brief Muestra la información del grupo de saqueadores - */ - void showInfo() const override - { - std::cout << "💀 Saqueadores: " << m_name << "\n" - << " - Estilo: " << estiloToString(m_estilo) << "\n" - << " - Miembros: " << m_numMiembros << "\n"; - } - - /** - * @brief Simula una amenaza del grupo - */ - void amenazar() const - { - switch (m_estilo) - { - case Estilo::AGRESIVO: - std::cout << "💬" << m_name << " >>> ¡Entréganos tus recursos o lo pagarán caro!" << std::endl; - break; - case Estilo::SIGILOSO: - std::cout << "💬" << m_name << " >>> Nadie nos vio entrar, nadie los verá salir..." << std::endl; - break; - case Estilo::OPORTUNISTA: - std::cout << "💬" << m_name << " >>> Solo estamos aquí por lo que sobra... si queda algo." << std::endl; - break; - } - } - -private: - /** - * @brief Devuelve una cantidad aleatoria de miembros entre 5 y 10 - */ - int randomGroupSize() const - { - static std::random_device rd; - static std::mt19937 gen(rd()); - std::uniform_int_distribution<> dist(5, 10); - return dist(gen); - } - - /** - * @brief Convierte el enum de estilo a string - */ - std::string estiloToString(Estilo estilo) const - { - switch (estilo) - { - case Estilo::AGRESIVO: return "Agresivo"; - case Estilo::SIGILOSO: return "Sigiloso"; - case Estilo::OPORTUNISTA: return "Oportunista"; - default: return "Desconocido"; - } - } -}; - -#endif // SAQUEADOR_HPP diff --git a/include/engine/engine.hpp b/include/engine/engine.hpp new file mode 100644 index 0000000..c4ddbd9 --- /dev/null +++ b/include/engine/engine.hpp @@ -0,0 +1,116 @@ +#ifndef ENGINE_HPP +#define ENGINE_HPP + +#include "engine/eventManager.hpp" +#include "engine/gameConsole.hpp" +#include "engine/visitorFactory.hpp" + +#include "gameSerializer.hpp" +#include "refugio.hpp" + +auto constexpr SAVE_FILE {"assets/save.txt"}; //< Nombre del archivo de guardado +auto constexpr CONFIG_FILE {"assets/system.conf"}; //< Nombre del archivo de configuración +auto constexpr CONSOLE_VERSION {"0.1.0"}; //< Versión de la consola + +class Refugio; + +/** + * @brief: Clase que inicializa el motor del juego + */ +class Engine +{ +public: + /** + * @brief: Inicializa el motor del juego + */ + void start(); + + /** + * @brief: Carga la configuración del juego + * @param: config Referencia a la configuración del juego + */ + + void engineConfig(const EngineData::GameConfig& config); + + /** + * @brief: Obtiene la configuración del juego actual + * @return: Referencia a la configuración del juego + */ + const EngineData::GameConfig& engineConfig() const; + + /** + * @brief: Carga el refugio del jugador + * @param: refugio Referencia al refugio del jugador + */ + void playerShelter(const Refugio& refugio); + + /** + * @brief: Carga la información del jugador + * @return: Referencia a la información del jugador + */ + const Refugio& playerShelter() const; + + /** + * @brief: Carga la información del jugador + * @param: player Referencia a la información del jugador + */ + void playerInfo(const EngineData::PlayerInfo& player); + + /** + * @brief: Carga la información del jugador + * @return: Referencia a la información del jugador + */ + const EngineData::PlayerInfo& playerInfo() const; + + double wrapperRandomDouble(double min, double max) + { + return m_randomGenerator.getDouble(min, max); + } + + template + const TData& wrapperRandomChoice(const std::vector& vec) + { + return m_randomGenerator.randomChoice(vec); + } + + bool checkEvent(); + + void processEvent(); + +private: + /** + * @brief: Inicializa los recursos del tablero + */ + void initResources(); + + /** + * @brief: Inicializa los elementos del tablero + */ + static void initEntities(); + + /** + * @brief: Inicializa la consola interativa + */ + void initConsole(); + + /** + * @brief: Carga la información de guardado + */ + void loadGame(); + + /** + * @brief: Carga la configuración del juego + */ + void loadConfig(); + + EngineData::PlayerInfo m_player; //< Información del jugador + RandomEventGenerator m_randomGenerator; //< Generador de eventos aleatorios + EngineData::GameConfig m_gameConfig; //< Configuración del juego + std::unique_ptr m_shelter; //< Refugio del jugador + std::unique_ptr m_console; + std::unique_ptr m_eventManager; + std::unique_ptr m_factory; + std::unique_ptr m_serializer; +}; + +#endif // ENGINE_HPP diff --git a/include/engine/engineData.hpp b/include/engine/engineData.hpp new file mode 100644 index 0000000..aac4e40 --- /dev/null +++ b/include/engine/engineData.hpp @@ -0,0 +1,184 @@ +#ifndef ENGINEDATA_HPP +#define ENGINEDATA_HPP + +#include +#include + +namespace EngineData +{ + + /** + * @brief: Información de la facción + */ + enum class Faction + { + WATER_MERCHANTS, //< Mercaderes de agua + MERCHANTS, //< Mercaderes + REFUGEES, //< Refugiados + LOOTERS, //< Saqueadores + STEEL_BROTHERS, //< Hermanos de acero + ENCLAVE, //< Enclave + MUTANTS, //< Mutantes + RAIDERS, //< Asaltantes + GHOULS, //< Ghouls + CARAVAN, //< Caravanas + UNKNOWN //< Desconocido + }; + + /** + * @brief: Información de los recursos + */ + enum class Resources + { + FOOD, //< Comida + WATER, //< Agua + MEDICINE, //< Medicina + AMMO, //< Municiones + WEAPONS, //< Armas + ARMOR, //< Armaduras + TOOLS, //< Herramientas + MATERIALS, //< Materiales + ELECTRONICS, //< Electrónica + ALCHOHOL, //< Alcohol + }; + + /** + * @brief: Información del artefacto único + */ + enum class UniqueArtifactType + { + WEAPON, //< Arma + ARMOR, //< Armadura + VEHICLE, //< Vehículo + RELIC, //< Reliquia + TECHNOLOGY, //< Tecnología + }; + + /** + * @brief: Información del jugador + */ + struct PlayerInfo + { + std::string_view name; + std::string_view level; + }; + + /** + * @brief: Información del juego + * @details: Contiene la configuración del juego, incluyendo las probabilidades de éxito y los multiplicadores + * para las diferentes acciones que el jugador puede realizar. + * @note: Las probabilidades deben estar en el rango de 0.0 a 1.0. Por defecto, se inicializan en 0.2 + */ + struct GameConfig + { + struct Exploration + { + double successRate; // Probabilidad de éxito al explorar (0.0 - 1.0) + double lootChance; // Posibilidad de encontrar recursos + double dangerChance; // Riesgo de evento hostil + } exploration; + + struct Fight + { + double criticalHitChance; // Probabilidad de golpe crítico (0.0 - 1.0) + double criticalHitMultiplier; // Multiplicador de daño por golpe crítico + double enemyAttackMultiplier; // Multiplicador de ataque enemigo + double enemyDefenseMultiplier; // Multiplicador de defensa enemigo + double enemyHealthMultiplier; // Multiplicador de salud enemigo + double enemyLootMultiplier; // Multiplicador de botín enemigo + double enemyExperienceMultiplier; // Multiplicador de experiencia enemigo + double luckyFactor; // Factor de suerte para el jugador + int minEnemy; + int maxEnemy; + double surrenderChance; // Probabilidad de rendición del enemigo + } fight; + + struct Resources + { + double successRate; + double lootChance; + double badLuckChance; + double durationFactor; + } resources; + + struct Shelter + { + double defenseFactor; + double attackFactor; + double visitantsRate; + } shelter; + + struct Events + { + int eventsPerSecond; // Frecuencia de eventos por segundo + double rateRefugee; // Tasa de aparición de refugiados + double rateBrother; // Tasa de aparición de hermanos + double rateEnemy; // Tasa de aparición de enemigos + double rateCommerce; // Tasa de aparición de comerciantes + double rateCaravane; // Tasa de aparición de caravanas + } events; + }; + + /** + * @brief: Convierte el enum de recursos a string + * @tparam: value Valor del enum + * @return: String con el nombre del recurso + */ + template + static std::string_view valueToString(const TData& value) + { + if constexpr (std::is_same_v) + { + switch (value) + { + case EngineData::Resources::FOOD: return "Comida"; + case EngineData::Resources::WATER: return "Agua"; + case EngineData::Resources::MEDICINE: return "Medicina"; + case EngineData::Resources::AMMO: return "Municiones"; + case EngineData::Resources::WEAPONS: return "Armas"; + case EngineData::Resources::ARMOR: return "Armadura"; + case EngineData::Resources::TOOLS: return "Herramientas"; + case EngineData::Resources::MATERIALS: return "Materiales"; + case EngineData::Resources::ELECTRONICS: return "Electrónica"; + case EngineData::Resources::ALCHOHOL: return "Alcohol"; + default: return "Unknown"; + } + } + else if constexpr (std::is_same_v) + { + switch (value) + { + case EngineData::Faction::WATER_MERCHANTS: return "Mercaderes de agua"; + case EngineData::Faction::MERCHANTS: return "Mercaderes"; + case EngineData::Faction::REFUGEES: return "Refugiados"; + case EngineData::Faction::LOOTERS: return "Saqueadores"; + case EngineData::Faction::STEEL_BROTHERS: return "Hermanos de acero"; + case EngineData::Faction::ENCLAVE: return "Enclave"; + case EngineData::Faction::MUTANTS: return "Mutantes"; + case EngineData::Faction::RAIDERS: return "Asaltantes"; + case EngineData::Faction::GHOULS: return "Ghouls"; + case EngineData::Faction::CARAVAN: return "Caravanas"; + default: return "Unknown"; + } + } + else if constexpr (std::is_same_v) + { + switch (value) + { + case EngineData::UniqueArtifactType::WEAPON: return "Arma"; + case EngineData::UniqueArtifactType::ARMOR: return "Armadura"; + case EngineData::UniqueArtifactType::VEHICLE: return "Vehículo"; + case EngineData::UniqueArtifactType::RELIC: return "Reliquia"; + case EngineData::UniqueArtifactType::TECHNOLOGY: return "Tecnología"; + default: return "Unknown"; + } + } + else + { + return "Unknown"; + } + } + +} // namespace EngineData + +#endif // ENGINEDATA_HPP diff --git a/include/engine/eventManager.hpp b/include/engine/eventManager.hpp new file mode 100644 index 0000000..df40813 --- /dev/null +++ b/include/engine/eventManager.hpp @@ -0,0 +1,51 @@ +#ifndef EVENT_MANAGER_HPP +#define EVENT_MANAGER_HPP + +class Engine; // Forward declaration of Engine +#include +#include +#include +#include +#include + +#include "visitorFactory.hpp" +class EventManager +{ +public: + // Inicia el hilo que genera eventos aleatorios. + void start(); + + // Detiene el hilo y limpia la cola. + void stop(); + + // Consulta si la cola está vacía. + bool isEmpty(); + + // Vacía la cola de eventos. + void clearQueue(); + + // Eventos + NPC::VisitanteVariant popEvent(); + + void setEngine(Engine* engine) + { + m_engine = engine; + } + + void setFactory(VisitorFactory* factory) + { + m_factory = factory; + } + +private: + std::atomic m_running {true}; + std::atomic m_eventCount {0}; // Contador de eventos generados + std::thread m_eventThread; + std::mutex m_eventMutex; + std::queue m_eventQueue; + std::condition_variable m_eventCv; + Engine* m_engine = nullptr; + VisitorFactory* m_factory = nullptr; +}; + +#endif // EVENT_MANAGER_HPP diff --git a/include/engine/gameConsole.hpp b/include/engine/gameConsole.hpp new file mode 100644 index 0000000..c68b6f4 --- /dev/null +++ b/include/engine/gameConsole.hpp @@ -0,0 +1,86 @@ + +#ifndef GAME_CONSOLE_HPP +#define GAME_CONSOLE_HPP + +class Engine; // Forward declaration of Engine +#include +#include +#include +#include + +#ifdef _WIN32 +#include +auto constexpr CLEAR_SCREEN {"cls"}; +#else +#include +auto constexpr CLEAR_SCREEN {"clear"}; +#endif + +/** + * @class GameConsole + * @brief Maneja los comandos de la consola (status, check, explore, etc.) y su interacción con el Engine. + * + * Esta clase proporciona una interfaz para interactuar con el motor del juego (Engine) a través de una consola. + * Permite procesar comandos de texto, mantener un historial de comandos y generar salidas relacionadas con + * las operaciones realizadas en el motor del juego. + */ +class GameConsole +{ +public: + void interativeLoop(); + + void setEngine(Engine* engine); + +private: + // Stores the history of commands + std::vector m_commandHistory; + + // Stores the output of the console + std::vector m_outputBuffer; + + // Helper method to execute a command + void executeCommand(const char& command); + + /** + * @brief: Muestra el banner de bienvenida + */ + void showBanner(); + + /** + * @brief: Muestra el menu principal + */ + void showMenu(); + + /** + * @brief: Limpia la pantalla antes de mostrar el menú + */ + void clearScreen(); + + Engine* m_engine = nullptr; + + bool m_keepRunning {true}; //< Variable para controlar el bucle de ejecución + /** + * @brief: Operaciones que puede realizar el jugador + */ + enum class Operation : uint8_t + { + SHOW_STATUS, //< Muestra el estado actual del refugio + SHOW_EVENTS, //< Muestra los eventos aleatorios + CHECK_EVENT, //< Muestra el evento actual + EXPLORE, //< Explora el mapa + FIGHT, //< Lucha contra un enemigo + EXIT, //< Salir del juego + SAVE, //< Guardar el juego + UNKNOWN //< Operación desconocida + }; + + std::unordered_map m_validOperations = {{'i', Operation::SHOW_STATUS}, + {'e', Operation::SHOW_EVENTS}, + {'c', Operation::CHECK_EVENT}, + {'x', Operation::EXPLORE}, + {'f', Operation::FIGHT}, + {'s', Operation::SAVE}, + {'q', Operation::EXIT}}; +}; + +#endif // GAME_CONSOLE_HPP diff --git a/include/engine/visitorFactory.hpp b/include/engine/visitorFactory.hpp new file mode 100644 index 0000000..18d686e --- /dev/null +++ b/include/engine/visitorFactory.hpp @@ -0,0 +1,29 @@ +#ifndef VISITORFACTORY_HPP +#define VISITORFACTORY_HPP + +class Engine; // Forward declaration of Engine + +#include "characters/npc.hpp" +#include "randomEventGenerator.hpp" +#include +#include + +class VisitorFactory +{ + static const std::vector NAMES; + static const std::vector SURNAMES; + static const std::vector GROUPS_ENEMIES; + static const std::vector MERCHANTS; + +public: + explicit VisitorFactory(RandomEventGenerator& rng, EngineData::GameConfig& config); + NPC::VisitanteVariant create(EngineData::Faction faction); + +private: + RandomEventGenerator* m_randomGenetor; + EngineData::GameConfig* m_config; + + std::unordered_map bagGenerator(bool isFromVault); +}; + +#endif // VISITORFACTORY_HPP diff --git a/include/gameSerializer.hpp b/include/gameSerializer.hpp index ef9bd14..080a235 100644 --- a/include/gameSerializer.hpp +++ b/include/gameSerializer.hpp @@ -2,8 +2,6 @@ #define GAME_SERIALIZER_HPP #include -#include "engine.hpp" - class Engine; // Forward declaration diff --git a/include/randomEventGenerator.hpp b/include/randomEventGenerator.hpp index 321524a..748619e 100644 --- a/include/randomEventGenerator.hpp +++ b/include/randomEventGenerator.hpp @@ -2,7 +2,6 @@ #define RANDOM_EVENT_GENERATOR_HPP #include -#include #include /** @@ -36,16 +35,16 @@ class RandomEventGenerator /** * @brief Devuelve un número flotante aleatorio entre [min, max] */ - float getFloat(float min, float max) + double getDouble(double min, double max) { - std::uniform_real_distribution dist(min, max); + std::uniform_real_distribution dist(min, max); return dist(m_rng); } /** * @brief Devuelve true con una probabilidad dada (0.0 a 1.0) */ - bool chance(float probability) + bool chance(double probability) { std::bernoulli_distribution dist(probability); return dist(m_rng); diff --git a/include/uiDef.hpp b/include/uiDef.hpp new file mode 100644 index 0000000..0438d9e --- /dev/null +++ b/include/uiDef.hpp @@ -0,0 +1,13 @@ +#ifndef UI_DEF_HPP +#define UI_DEF_HPP + +#define GREEN "\033[32m" +#define BLUE "\033[34m" +#define RED "\033[31m" +#define WHITE "\033[37m" +#define YELLOW "\033[33m" +#define RESET "\033[0m" + +#define BOLD "\033[1m" +#define UNDERLINE "\033[4m" +#endif // UI_DEF_HPP \ No newline at end of file diff --git a/src/caravana.cpp b/src/caravana.cpp deleted file mode 100644 index 09f470b..0000000 --- a/src/caravana.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include - - -Caravana::Caravana(const std::string& nombre, bool confia) - : EntidadGenerica(nombre) - , m_confia(confia) -{ - inicializarStock(); -} - - -void Caravana::showInfo() const -{ - std::cout << "🚚 Caravana: " << m_name << "\n"; - std::cout << " - Confianza: " << (m_confia ? "Sí" : "No") << "\n"; - std::cout << " - Artefactos disponibles:\n"; - for (const auto& item : this->m_stock) - { - item->showInfo(); - } -} - -std::shared_ptr Caravana::comprarArtefacto(const std::string& nombre) -{ - if (!m_confia) - { - std::cout << "💬 " << m_name << " >>> No confiamos lo suficiente en tu refugio para hacer negocios." - << std::endl; - return nullptr; - } - - for (auto it = m_stock.begin(); it != m_stock.end(); ++it) - { - if ((*it)->nombre() == nombre) - { - std::cout << "💬 " << m_name << " >>> Excelente elección. Espero que lo uses bien." << std::endl; - auto item = *it; - m_stock.erase(it); - return item; - } - } - - std::cout << "💬 " << m_name << " >>> No tenemos ese artefacto en este momento." << std::endl; - return nullptr; -} - -void Caravana::evaluarConfianza() -{ - this->m_confia = true; // Lógica temporal, puede depender del nivel del refugio -} - -void Caravana::inicializarStock() -{ - m_stock.emplace_back(std::make_shared("Detector de Radiación", "Épico", EngineData::UniqueArtifactType::TECHNOLOGY, 250.0)); - m_stock.emplace_back(std::make_shared("Pistola Láser Táctica", "Legendaria", EngineData::UniqueArtifactType::WEAPON, 400.0)); - m_stock.emplace_back(std::make_shared("Batería de Fusión", "Rara", EngineData::UniqueArtifactType::TECHNOLOGY, 320.0)); - -} \ No newline at end of file diff --git a/src/enclave.cpp b/src/enclave.cpp deleted file mode 100644 index fccee8a..0000000 --- a/src/enclave.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "enclave.hpp" - -Enclave::Enclave(const std::string& nombre) - : EntidadGenerica(nombre) - , m_fuerza(generarFuerza()) - , m_potencia(generarPotencia()) - , m_detectado(false) -{ -} - -void Enclave::showInfo() const -{ - std::cout << "💂🏻 ENCLAVE - Escuadrón: " << m_name << "\n" - << " - Soldados: " << m_fuerza << "\n" - << " - Potencia táctica: " << m_potencia << "\n" - << " - ¿Han detectado el refugio?: " << (m_detectado ? "Sí" : "No") << "\n"; -} - -void Enclave::detectarRefugio() -{ - m_detectado = true; - std::cout << "💬 " << m_name << " >>> Objetivo confirmado. Preparando ofensiva." << std::endl; -} - -bool Enclave::haDetectado() const -{ - return m_detectado; -} - -int Enclave::fuerza() const -{ - return m_fuerza; -} - -double Enclave::potencia() const -{ - return m_potencia; -} - -int Enclave::generarFuerza() -{ - static std::mt19937 rng(std::random_device {}()); - std::uniform_int_distribution dist(10, 50); - return dist(rng); -} - -double Enclave::generarPotencia() const -{ - static std::mt19937 rng(std::random_device {}()); - std::uniform_real_distribution dist(2.5, 5.0); - return dist(rng); -}; \ No newline at end of file diff --git a/src/engine.cpp b/src/engine.cpp deleted file mode 100644 index d66bbc3..0000000 --- a/src/engine.cpp +++ /dev/null @@ -1,392 +0,0 @@ -#include "engine.hpp" - -#include - -void Engine::start() -{ - m_randomGenerator = RandomEventGenerator(); - - loadConfig(); - - loadGame(); - - initResources(); - initEntities(); - interactiveConsole(); -} - -void Engine::initResources() -{ - std::cout << GREEN << "Inicializando recursos..." << RESET << std::endl; - std::this_thread::sleep_for(std::chrono::milliseconds(500)); -} - -void Engine::initEntities() -{ - std::cout << GREEN << "Inicializando entidades..." << RESET << std::endl; - std::this_thread::sleep_for(std::chrono::milliseconds(500)); -} - -void Engine::showBanner() -{ - std::cout << GREEN - << " :---. .---..---. :--:..---..---..:------:. . :-------.:-----: .-+=. " - << RESET << std::endl; - std::cout << GREEN - << " :@@@- =@@%.*@@@+ *@@#.:%@@-.@@@-.%@@@@@@%. . =@@@@@@@:*@@@@@+ =@@@@@* " - << RESET << std::endl; - std::cout << GREEN - << " +@@%..@@@=:%@@@@. *@@#.:%@@-.@@@-.::#@@%::. .:=@@@::.*@@%::..*@@@+::: . " - << RESET << std::endl; - std::cout << GREEN - << " :@@@==@@%.=@@@@@= *@@#.:%@@-.@@@- #@@#........ -@@@. *@@%::.-@@@- . " - << RESET << std::endl; - std::cout << GREEN - << " .*@@%%@@=.%@@+@@%. *@@#.:%@@-.@@@- #@@#.-@@@@@* -@@@. *@@@@@:=@@@. " - << RESET << std::endl; - std::cout << GREEN - << " .@@@@@%.-@@%.@@@- *@@#.:%@@-.@@@- . #@@#.:+++++- -@@@. *@@%==.-@@@: " - << RESET << std::endl; - std::cout << GREEN - << " =@@@@-.#@@@@@@@* *@@%.:@@@-.@@@-...#@@#. -@@@. *@@%....#@@@-... " - << RESET << std::endl; - std::cout << GREEN - << " .%@@%.:@@@:.-@@@:-@@@@@@@@..@@@@@@-#@@#. . -@@@. *@@@@@* .*@@@@@* " - << RESET << std::endl; - std::cout << GREEN - << " .=##=.=##+ .*##+..+%@@%=. .######:+##*. . :###. =#####= ..-#@%= . " - << RESET << std::endl; - std::cout << GREEN - << " . . . " - << RESET << std::endl; - std::cout << GREEN - << " . .. ..-+%@@@@@@%+-.. . " - << RESET << std::endl; - std::cout << GREEN - << " . . .=@@@@@@@@@@@@@@@@=. . . . . " - << RESET << std::endl; - std::cout << GREEN - << " . . ...*@@@@%-:. ..:-%@@@@*. " - << RESET << std::endl; - std::cout << GREEN - << " .-*@@@@@@@@@@@@@@@@@@@@@=. . .=@@@@@@@@@@@@@@@@@@@@@*-.. . " - << RESET << std::endl; - std::cout << GREEN - << " .-%@@@@@@@@@@@@@@@@@@@#. .-*##*-. . .#@@@@@@@@@@@@@@@@@@@%-. .. " - << RESET << std::endl; - std::cout << GREEN - << " ..............:@@@+. :%@@@@@@@@%: .+@@@:.............. " - << RESET << std::endl; - std::cout << GREEN - << " . . . .#@@%. ..=@@@@@@@@@@@@=. .%@@*. . . . " - << RESET << std::endl; - std::cout << GREEN - << " .:+%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+ :@@@@@@@@@@@@@%: . *@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%+:.. ." - << RESET << std::endl; - std::cout << GREEN - << " .*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+ :@@@@@@@@@@@@@@: . +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*. " - << RESET << std::endl; - std::cout << GREEN - << " ..:-+++++++++++++++++++++++++@@@*. .%@@@@@@@@@@@@%. .#@@@+++++++++++++++++++++++++-:.. " - << RESET << std::endl; - std::cout << GREEN - << " . .+@@@: ..%@@@@@@@@@@%.. :@@@+ " - << RESET << std::endl; - std::cout << GREEN - << " . .:=*%@@@@@@@@@@@@@@@%. .=%@@@@@@%-. .@@@@@@@@@@@@@@@@%*-.. " - << RESET << std::endl; - std::cout << GREEN - << " . :%@@@@@@@@@@@@@@@@@@@@@- . -@@@@@@@@@@@@@@@@@@@@@%: " - << RESET << std::endl; - std::cout << GREEN - << " .:=*###############@@@@=. .=@@@@###############*-:. . " - << RESET << std::endl; - std::cout << GREEN - << " . .. :#@@@@@#+=--=+#@@@@@#. . " - << RESET << std::endl; - std::cout << GREEN - << " . . .=%@@@@@@@@@@@@%=. " - << RESET << std::endl; - std::cout << GREEN - << " . . .. ...-=++=:... . " - << RESET << std::endl; -} - -void Engine::showMenu() -{ - std::cout << GREEN << "========== CONSOLA DE OPERACIONES VAULT-TEC v" << CONSOLE_VERSION << " ==========" << RESET - << std::endl; - std::cout << GREEN << "<> [i] status " << RESET << " - Mostrar estado del refugio" << std::endl; - std::cout << GREEN << "<> [e] events " << RESET << " - Ver historial de eventos" << std::endl; - std::cout << GREEN << "<> [c] check " << RESET << " - Verificar evento activo" << std::endl; - std::cout << GREEN << "<> [x] explore " << RESET << " - Realizar una exploración" << std::endl; - std::cout << GREEN << "<> [f] fight " << RESET << " - Enfrentar a un enemigo" << std::endl; - std::cout << GREEN << "<> [s] save " << RESET << " - Guardar el progreso" << std::endl; - std::cout << GREEN << "<> [q] exit " << RESET << " - Salir del sistema" << std::endl; - std::cout << GREEN << "====================================" << RESET << std::endl; -} - -void Engine::clearScreen() -{ - std::system(CLEAR_SCREEN); -} - -void Engine::interactiveConsole() -{ - bool keepRunning = true; - while (keepRunning) - { - showBanner(); - showMenu(); - std::string input; - std::cout << GREEN << "> " << RESET; - std::cin >> input; - - if (m_validOperations.find(input[0]) != m_validOperations.end()) - { - switch (m_validOperations.at(input[0])) - { - case Operation::SHOW_STATUS: - std::cout << "Mostrando detalles..." << std::endl; - std::this_thread::sleep_for(std::chrono::milliseconds(1000)); - break; - case Operation::EXIT: - std::cout << "Saliendo..." << std::endl; - keepRunning = false; - break; - default: std::cout << "Operación desconocida" << std::endl; break; - } - } - else - { - std::cout << "Operación desconocida" << std::endl; - } - clearScreen(); - } -} - -void Engine::engineConfig(const EngineData::GameConfig& config) -{ - m_gameConfig = config; -} - -const EngineData::GameConfig& Engine::engineConfig() const -{ - return m_gameConfig; -} - -void Engine::playerShelter(const Refugio& refugio) -{ - m_shelter = std::make_unique(refugio); -} - -const Refugio& Engine::playerShelter() const -{ - return *m_shelter; -} - -void Engine::playerInfo(const EngineData::PlayerInfo& player) -{ - m_player = player; -} - -const EngineData::PlayerInfo& Engine::playerInfo() const -{ - return m_player; -} - -void Engine::loadGame() -{ - // Verifica sino existe un archivo de guardado - if (std::filesystem::exists(SAVE_FILE)) - { - std::cout << GREEN << "\n\n[INFO] Restableciendo información desde servidores centrales..." << RESET - << std::endl; - if (!GameSerializer::load(*this, SAVE_FILE)) - { - std::cout << RED << "[ERROR] Corte de luz detectado. EPEC no responde." << RESET << std::endl; - std::cout << RED << "Por favor, reinicie el sistema y verifique que estén los cables conectados." << RESET - << std::endl; - exit(1); - } - } - else - { - std::cout << "\n\nNo se encontró información de guardado. Iniciando sistema después de masivo reinicio..." - << std::endl; - std::this_thread::sleep_for(std::chrono::milliseconds(500)); - std::cout << "\n\nAlgunos datos no están disponibles. Por favor, ingreselos" << std::endl; - std::cout << "Si no recuerda alguno, tome un descanso y vuelva a intentarlo." << std::endl; - std::cout << "Si no recuerda nada, por favor, reinicie el sistema." << std::endl; - std::cout << "Si no recuerda como reiniciar el sistema, por favor, largo de aqui." << std::endl; - - std::cout << "\n\nPresione ENTER para continuar..."; - - std::cin.get(); - - std::cout << "Ingrese su nombre: "; - std::string playerName; - std::getline(std::cin, playerName); - std::cout << "Ingrese el identificador unico provisto por VAULT TEC del refugio: "; - std::string vaultId; - std::getline(std::cin, vaultId); - - m_player.level = "1"; // Nivel inicial - m_player.name = playerName; - - // Crea el refugio - m_shelter = std::make_unique(vaultId, playerName); - - std::this_thread::sleep_for(std::chrono::milliseconds(500)); - - if (m_randomGenerator.chance(0.5f)) - { - std::cout << GREEN << "\n\n ===== SISTEMA VAULT CARGADO ====" << RESET << std::endl; - } - else - { - std::cout << RED << "\n\n ===== [ERROR] SISTEMA VAULT DAÑADO ====" << RESET << std::endl; - std::this_thread::sleep_for(std::chrono::milliseconds(500)); - std::cout << RED << "\n\n ===== [ERROR] SISTEMA VAULT DAÑADO ====" << RESET << std::endl; - std::this_thread::sleep_for(std::chrono::milliseconds(700)); - std::cout << RED << "\n\n ===== [ERROR] SISTEMA VAULT DAÑADO ====" << RESET << std::endl; - std::this_thread::sleep_for(std::chrono::milliseconds(1000)); - std::cout << YELLOW << "\n\n ===== [INFO] PATEANDO SERVIDOR CENTRAL ====" << RESET << std::endl; - std::this_thread::sleep_for(std::chrono::milliseconds(2000)); - std::cout << GREEN << "\n\n ===== SISTEMA VAULT CARGADO ====" << RESET << std::endl; - } - - // Guardar nueva información - GameSerializer::save(*this, SAVE_FILE); - } - - std::this_thread::sleep_for(std::chrono::milliseconds(1000)); -} - -void Engine::loadConfig() -{ - std::cout << GREEN << "\n\n[INFO] Cargando configuracion..." << RESET << std::endl; - if (!std::filesystem::exists(CONFIG_FILE)) - { - std::ofstream fileOut(CONFIG_FILE); - if (!fileOut) - { - std::cerr << RED << "[ERROR] No se pudo crear el archivo de configuración. Hubo... un... corte de luz?" - << RESET << std::endl; - return; - } - fileOut << R"(# === CONFIGURACIÓN DEL SISTEMA REFUGIO 33 === -# Este archivo define los parámetros de eventos, exploración y combates -# ¡Modifique bajo su propia responsabilidad! - -[exploration] -successRate=0.45 -lootChance=0.30 -dangerChance=0.25 - -[fight] -criticalHitChance=0.15 -criticalHitMultiplier=2.0 -enemyAttackMultiplier=1.5 -enemyDefenseMultiplier=1.2 -enemyHealthMultiplier=1.3 -enemyLootMultiplier=1.5 -enemyExperienceMultiplier=1.5 -luckyFactor=1.2 - -[resources] -successRate=0.50 -lootChance=0.40 -badLuckChance=0.20 -durationFactor=1.5 - -[shelter] -defenseFactor=1.5 -attackFactor=1.2 -visitantsRate=0.10 - -# === FIN DEL ARCHIVO === -)"; - fileOut.close(); - std::cout << GREEN << "[SUCCESS] Se generó el archivo de configuración por defecto.\n" << RESET; - } - - std::ifstream inFile(CONFIG_FILE); - if (!inFile) - { - std::cerr << RED << "[ERROR] No se pudo abrir el archivo de configuración. Que rompió?" << RESET << std::endl; - return; - } - - std::string line, section; - while (std::getline(inFile, line)) - { - if (line.empty() || line[0] == '#' || line[0] == ';') - continue; - if (line.front() == '[') - { - section = line; - continue; - } - - size_t eq = line.find('='); - if (eq == std::string::npos) - continue; - - std::string key = line.substr(0, eq); - std::string val = line.substr(eq + 1); - - double value = std::stod(val); - - if (section == "[exploration]") - { - if (key == "successRate") - m_gameConfig.exploration.successRate = value; - else if (key == "lootChance") - m_gameConfig.exploration.lootChance = value; - else if (key == "dangerChance") - m_gameConfig.exploration.dangerChance = value; - } - else if (section == "[fight]") - { - if (key == "criticalHitChance") - m_gameConfig.fight.criticalHitChance = value; - else if (key == "criticalHitMultiplier") - m_gameConfig.fight.criticalHitMultiplier = value; - else if (key == "enemyAttackMultiplier") - m_gameConfig.fight.enemyAttackMultiplier = value; - else if (key == "enemyDefenseMultiplier") - m_gameConfig.fight.enemyDefenseMultiplier = value; - else if (key == "enemyHealthMultiplier") - m_gameConfig.fight.enemyHealthMultiplier = value; - else if (key == "enemyLootMultiplier") - m_gameConfig.fight.enemyLootMultiplier = value; - else if (key == "enemyExperienceMultiplier") - m_gameConfig.fight.enemyExperienceMultiplier = value; - else if (key == "luckyFactor") - m_gameConfig.fight.luckyFactor = value; - } - else if (section == "[resources]") - { - if (key == "successRate") - m_gameConfig.resources.successRate = value; - else if (key == "lootChance") - m_gameConfig.resources.lootChance = value; - else if (key == "badLuckChance") - m_gameConfig.resources.badLuckChance = value; - else if (key == "durationFactor") - m_gameConfig.resources.durationFactor = value; - } - else if (section == "[shelter]") - { - if (key == "defenseFactor") - m_gameConfig.shelter.defenseFactor = value; - else if (key == "attackFactor") - m_gameConfig.shelter.attackFactor = value; - else if (key == "visitantsRate") - m_gameConfig.shelter.visitantsRate = value; - } - } - - std::cout << GREEN << "[SUCCESS] Configuración cargada correctamente desde el servidor de VAULT\n" << RESET; -} diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp new file mode 100644 index 0000000..e4ac6a3 --- /dev/null +++ b/src/engine/engine.cpp @@ -0,0 +1,378 @@ +#include "engine/engine.hpp" +#include "uiDef.hpp" +#include +#include + +void Engine::start() +{ + m_randomGenerator = RandomEventGenerator(); + + loadConfig(); + + loadGame(); + + initResources(); + + initEntities(); + + initConsole(); + + m_eventManager->stop(); +} + +void Engine::initResources() +{ + std::cout << GREEN << "Inicializando recursos..." << RESET << '\n'; + m_console = std::make_unique(); + m_console->setEngine(this); + + m_eventManager = std::make_unique(); + m_eventManager->setEngine(this); + + m_factory = std::make_unique(m_randomGenerator, m_gameConfig); + + m_eventManager->setFactory(m_factory.get()); + + m_eventManager->start(); + + std::this_thread::sleep_for(std::chrono::milliseconds(500)); +} + +void Engine::initEntities() +{ + std::cout << GREEN << "Inicializando entidades..." << RESET << '\n'; + std::this_thread::sleep_for(std::chrono::milliseconds(500)); +} + +void Engine::initConsole() +{ + m_console->interativeLoop(); +} + +void Engine::engineConfig(const EngineData::GameConfig& config) +{ + m_gameConfig = config; +} + +const EngineData::GameConfig& Engine::engineConfig() const +{ + return m_gameConfig; +} + +void Engine::playerShelter(const Refugio& refugio) +{ + m_shelter = std::make_unique(refugio); +} + +const Refugio& Engine::playerShelter() const +{ + return *m_shelter; +} + +void Engine::playerInfo(const EngineData::PlayerInfo& player) +{ + m_player = player; +} + +const EngineData::PlayerInfo& Engine::playerInfo() const +{ + return m_player; +} + +void Engine::loadGame() +{ + // Verifica sino existe un archivo de guardado + if (std::filesystem::exists(SAVE_FILE)) + { + std::cout << GREEN << "\n\n[INFO] Restableciendo información desde servidores centrales..." << RESET << '\n'; + if (!GameSerializer::load(*this, SAVE_FILE)) + { + std::cout << RED << "[ERROR] Corte de luz detectado. EPEC no responde." << RESET << '\n'; + std::cout << RED << "Por favor, reinicie el sistema y verifique que estén los cables conectados." << RESET + << '\n'; + exit(1); + } + } + else + { + std::cout << "\n\nNo se encontró información de guardado. Iniciando sistema después de masivo reinicio..." + << '\n'; + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + std::cout << "\n\nAlgunos datos no están disponibles. Por favor, ingreselos" << '\n'; + std::cout << "Si no recuerda alguno, tome un descanso y vuelva a intentarlo." << '\n'; + std::cout << "Si no recuerda nada, por favor, reinicie el sistema." << '\n'; + std::cout << "Si no recuerda como reiniciar el sistema, por favor, largo de aqui." << '\n'; + + std::cout << "\n\nPresione ENTER para continuar..."; + + std::cin.get(); + + std::cout << "Ingrese su nombre: "; + std::string playerName; + std::getline(std::cin, playerName); + std::cout << "Ingrese el identificador unico provisto por VAULT TEC del refugio: "; + std::string vaultId; + std::getline(std::cin, vaultId); + + m_player.level = "1"; // Nivel inicial + m_player.name = playerName; + + // Crea el refugio + m_shelter = std::make_unique(vaultId, playerName); + + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + + if (m_randomGenerator.chance(0.5f)) + { + std::cout << GREEN << "\n\n ===== SISTEMA VAULT CARGADO ====" << RESET << '\n'; + } + else + { + std::cout << RED << "\n\n ===== [ERROR] SISTEMA VAULT DAÑADO ====" << RESET << '\n'; + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + std::cout << RED << "\n\n ===== [ERROR] SISTEMA VAULT DAÑADO ====" << RESET << '\n'; + std::this_thread::sleep_for(std::chrono::milliseconds(700)); + std::cout << RED << "\n\n ===== [ERROR] SISTEMA VAULT DAÑADO ====" << RESET << '\n'; + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + std::cout << YELLOW << "\n\n ===== [INFO] PATEANDO SERVIDOR CENTRAL ====" << RESET << '\n'; + std::this_thread::sleep_for(std::chrono::milliseconds(2000)); + std::cout << GREEN << "\n\n ===== SISTEMA VAULT CARGADO ====" << RESET << '\n'; + } + + // Guardar nueva información + GameSerializer::save(*this, SAVE_FILE); + } + + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); +} + +void Engine::loadConfig() +{ + std::cout << GREEN << "\n\n[INFO] Cargando configuracion..." << RESET << '\n'; + if (!std::filesystem::exists(CONFIG_FILE)) + { + std::ofstream fileOut(CONFIG_FILE); + if (!fileOut) + { + std::cerr << RED << "[ERROR] No se pudo crear el archivo de configuración. Hubo... un... corte de luz?" + << RESET << '\n'; + return; + } + fileOut << R"(# === CONFIGURACIÓN DEL SISTEMA REFUGIO 33 === +# Este archivo define los parámetros de eventos, exploración y combates +# ¡Modifique bajo su propia responsabilidad! + +[exploration] +successRate=0.45 +lootChance=0.30 +dangerChance=0.25 + +[fight] +criticalHitChance=0.15 +criticalHitMultiplier=2.0 +enemyAttackMultiplier=1.5 +enemyDefenseMultiplier=1.2 +enemyHealthMultiplier=1.3 +enemyLootMultiplier=1.5 +enemyExperienceMultiplier=1.5 +luckyFactor=1.2 +minEnemy=1 +maxEnemy=10 +surrenderChance=0.10 + +[resources] +successRate=0.50 +lootChance=0.40 +badLuckChance=0.20 +durationFactor=1.5 + +[shelter] +defenseFactor=1.5 +attackFactor=1.2 + +[events] +eventsPerSecond=10 +rateRefugee=0.10 +rateBrother=0.05 +rateEnemy=0.50 +rateCommerce=0.70 +rateCaravane=0.02 + +# === FIN DEL ARCHIVO === +)"; + fileOut.close(); + std::cout << GREEN << "[SUCCESS] Se generó el archivo de configuración por defecto.\n" << RESET; + } + + std::ifstream inFile(CONFIG_FILE); + if (!inFile) + { + std::cerr << RED << "[ERROR] No se pudo abrir el archivo de configuración. Que rompió?" << RESET << '\n'; + return; + } + + std::string line; + std::string section; + while (std::getline(inFile, line)) + { + if (line.empty() || line[0] == '#' || line[0] == ';') + { + continue; + } + if (line.front() == '[') + { + section = line; + continue; + } + + size_t eq = line.find('='); + if (eq == std::string::npos) + { + continue; + } + + std::string key = line.substr(0, eq); + std::string val = line.substr(eq + 1); + + double value = std::stod(val); + + if (section == "[exploration]") + { + if (key == "successRate") + { + m_gameConfig.exploration.successRate = value; + } + else if (key == "lootChance") + { + m_gameConfig.exploration.lootChance = value; + } + else if (key == "dangerChance") + { + m_gameConfig.exploration.dangerChance = value; + } + } + else if (section == "[fight]") + { + if (key == "criticalHitChance") + { + m_gameConfig.fight.criticalHitChance = value; + } + else if (key == "criticalHitMultiplier") + { + m_gameConfig.fight.criticalHitMultiplier = value; + } + else if (key == "enemyAttackMultiplier") + { + m_gameConfig.fight.enemyAttackMultiplier = value; + } + else if (key == "enemyDefenseMultiplier") + { + m_gameConfig.fight.enemyDefenseMultiplier = value; + } + else if (key == "enemyHealthMultiplier") + { + m_gameConfig.fight.enemyHealthMultiplier = value; + } + else if (key == "enemyLootMultiplier") + { + m_gameConfig.fight.enemyLootMultiplier = value; + } + else if (key == "enemyExperienceMultiplier") + { + m_gameConfig.fight.enemyExperienceMultiplier = value; + } + else if (key == "luckyFactor") + { + m_gameConfig.fight.luckyFactor = value; + } + else if (key == "minEnemy") + { + m_gameConfig.fight.minEnemy = static_cast(value); + } + else if (key == "maxEnemy") + { + m_gameConfig.fight.maxEnemy = static_cast(value); + } + else if (key == "surrenderChance") + { + m_gameConfig.fight.surrenderChance = value; + } + } + else if (section == "[resources]") + { + if (key == "successRate") + { + m_gameConfig.resources.successRate = value; + } + else if (key == "lootChance") + { + m_gameConfig.resources.lootChance = value; + } + else if (key == "badLuckChance") + { + m_gameConfig.resources.badLuckChance = value; + } + else if (key == "durationFactor") + { + m_gameConfig.resources.durationFactor = value; + } + } + else if (section == "[shelter]") + { + if (key == "defenseFactor") + { + m_gameConfig.shelter.defenseFactor = value; + } + else if (key == "attackFactor") + { + m_gameConfig.shelter.attackFactor = value; + } + } + else if (section == "[events]") + { + if (key == "eventsPerSecond") + { + m_gameConfig.events.eventsPerSecond = static_cast(value); + } + else if (key == "rateRefugee") + { + m_gameConfig.events.rateRefugee = value; + } + else if (key == "rateBrother") + { + m_gameConfig.events.rateBrother = value; + } + else if (key == "rateEnemy") + { + m_gameConfig.events.rateEnemy = value; + } + else if (key == "rateCommerce") + { + m_gameConfig.events.rateCommerce = value; + } + else if (key == "rateCaravane") + { + m_gameConfig.events.rateCaravane = value; + } + } + } + + std::cout << GREEN << "[SUCCESS] Configuración cargada correctamente desde el servidor de VAULT\n" << RESET; +} + +bool Engine::checkEvent() +{ + return !m_eventManager->isEmpty(); +} + +void Engine::processEvent() +{ + if (m_eventManager->isEmpty()) + { + std::cout << YELLOW << "[INFO] No hay eventos disponibles." << RESET << '\n'; + return; + } + + auto event = m_eventManager->popEvent(); + m_shelter->registerVisitant(event); +} diff --git a/src/engine/eventManager.cpp b/src/engine/eventManager.cpp new file mode 100644 index 0000000..79e736c --- /dev/null +++ b/src/engine/eventManager.cpp @@ -0,0 +1,119 @@ +#include "engine/eventManager.hpp" +#include "engine/engine.hpp" +#include "engineData.hpp" +#include + +auto constexpr DELAY {30}; ///< Delay en segundos para el hilo de eventos + +void EventManager::start() +{ + constexpr size_t MAX_QUEUE_SIZE = 10; + double intervalSeconds = 1.0 / m_engine->engineConfig().events.eventsPerSecond; + + m_eventThread = std::thread( + [this, intervalSeconds]() + { + while (m_running.load()) + { + { + std::unique_lock lock(m_eventMutex); + if (m_eventQueue.size() >= MAX_QUEUE_SIZE) + { + lock.unlock(); // Libera el mutex a drede para evitar el deadlock + std::this_thread::sleep_for(std::chrono::seconds(DELAY)); + continue; + } + } + + wrapperVector visitants; + visitants.push_back({NPC::VisitantCategory::REFUGEE, m_engine->engineConfig().events.rateRefugee}); + visitants.push_back({NPC::VisitantCategory::ENEMY, m_engine->engineConfig().events.rateEnemy}); + + double totalWeight = 0.0; + for (const auto& v : visitants) + { + totalWeight += v.weight; + } + + double roll = m_engine->wrapperRandomDouble(0.0, totalWeight); + double cumulative = 0.0; + + for (const auto& visitant : visitants) + { + cumulative += visitant.weight; + if (roll <= cumulative) + { + EngineData::Faction faction {EngineData::Faction::UNKNOWN}; + + switch (visitant.type) + { + case NPC::VisitantCategory::REFUGEE: faction = EngineData::Faction::REFUGEES; break; + case NPC::VisitantCategory::ENEMY: + { + std::vector enemies = {EngineData::Faction::RAIDERS}; + faction = m_engine->wrapperRandomChoice(enemies); + break; + } + } + + auto npc = m_factory->create(faction); + + { + std::lock_guard lock(m_eventMutex); + if (m_eventQueue.size() < MAX_QUEUE_SIZE) + { + m_eventQueue.emplace(std::move(npc)); + m_eventCount.fetch_add(1); + m_eventCv.notify_one(); + } + } + + break; // Salir del loop de elección de visitante + } + } + + std::this_thread::sleep_for(std::chrono::duration(intervalSeconds)); + } + }); +} + +void EventManager::stop() +{ + m_running.store(false); + if (m_eventThread.joinable()) + { + m_eventThread.join(); + } + + clearQueue(); +} + +bool EventManager::isEmpty() +{ + std::lock_guard lock(m_eventMutex); + return m_eventQueue.empty(); +} + +NPC::VisitanteVariant EventManager::popEvent() +{ + std::unique_lock lock(m_eventMutex); + m_eventCv.wait(lock, [this] { return !m_eventQueue.empty() || !m_running.load(); }); + + if (m_eventQueue.empty()) + { + throw std::runtime_error("EventManager is not running"); + } + + auto event = m_eventQueue.front(); + m_eventQueue.pop(); + return event; +} + +void EventManager::clearQueue() +{ + std::lock_guard lock(m_eventMutex); + while (!m_eventQueue.empty()) + { + m_eventQueue.pop(); + } +} diff --git a/src/engine/gameConsole.cpp b/src/engine/gameConsole.cpp new file mode 100644 index 0000000..7b07c0a --- /dev/null +++ b/src/engine/gameConsole.cpp @@ -0,0 +1,165 @@ +#include "engine/gameConsole.hpp" +#include "engine/engine.hpp" // Include the full definition of Engine +#include "uiDef.hpp" + +void GameConsole::showBanner() +{ + std::cout << GREEN + << " :---. .---..---. :--:..---..---..:------:. . :-------.:-----: .-+=. " + << RESET << '\n'; + std::cout << GREEN + << " :@@@- =@@%.*@@@+ *@@#.:%@@-.@@@-.%@@@@@@%. . =@@@@@@@:*@@@@@+ =@@@@@* " + << RESET << '\n'; + std::cout << GREEN + << " +@@%..@@@=:%@@@@. *@@#.:%@@-.@@@-.::#@@%::. .:=@@@::.*@@%::..*@@@+::: . " + << RESET << '\n'; + std::cout << GREEN + << " :@@@==@@%.=@@@@@= *@@#.:%@@-.@@@- #@@#........ -@@@. *@@%::.-@@@- . " + << RESET << '\n'; + std::cout << GREEN + << " .*@@%%@@=.%@@+@@%. *@@#.:%@@-.@@@- #@@#.-@@@@@* -@@@. *@@@@@:=@@@. " + << RESET << '\n'; + std::cout << GREEN + << " .@@@@@%.-@@%.@@@- *@@#.:%@@-.@@@- . #@@#.:+++++- -@@@. *@@%==.-@@@: " + << RESET << '\n'; + std::cout << GREEN + << " =@@@@-.#@@@@@@@* *@@%.:@@@-.@@@-...#@@#. -@@@. *@@%....#@@@-... " + << RESET << '\n'; + std::cout << GREEN + << " .%@@%.:@@@:.-@@@:-@@@@@@@@..@@@@@@-#@@#. . -@@@. *@@@@@* .*@@@@@* " + << RESET << '\n'; + std::cout << GREEN + << " .=##=.=##+ .*##+..+%@@%=. .######:+##*. . :###. =#####= ..-#@%= . " + << RESET << '\n'; + std::cout << GREEN + << " . . . " + << RESET << '\n'; + std::cout << GREEN + << " . .. ..-+%@@@@@@%+-.. . " + << RESET << '\n'; + std::cout << GREEN + << " . . .=@@@@@@@@@@@@@@@@=. . . . . " + << RESET << '\n'; + std::cout << GREEN + << " . . ...*@@@@%-:. ..:-%@@@@*. " + << RESET << '\n'; + std::cout << GREEN + << " .-*@@@@@@@@@@@@@@@@@@@@@=. . .=@@@@@@@@@@@@@@@@@@@@@*-.. . " + << RESET << '\n'; + std::cout << GREEN + << " .-%@@@@@@@@@@@@@@@@@@@#. .-*##*-. . .#@@@@@@@@@@@@@@@@@@@%-. .. " + << RESET << '\n'; + std::cout << GREEN + << " ..............:@@@+. :%@@@@@@@@%: .+@@@:.............. " + << RESET << '\n'; + std::cout << GREEN + << " . . . .#@@%. ..=@@@@@@@@@@@@=. .%@@*. . . . " + << RESET << '\n'; + std::cout << GREEN + << " .:+%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+ :@@@@@@@@@@@@@%: . *@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%+:.. ." + << RESET << '\n'; + std::cout << GREEN + << " .*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+ :@@@@@@@@@@@@@@: . +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*. " + << RESET << '\n'; + std::cout << GREEN + << " ..:-+++++++++++++++++++++++++@@@*. .%@@@@@@@@@@@@%. .#@@@+++++++++++++++++++++++++-:.. " + << RESET << '\n'; + std::cout << GREEN + << " . .+@@@: ..%@@@@@@@@@@%.. :@@@+ " + << RESET << '\n'; + std::cout << GREEN + << " . .:=*%@@@@@@@@@@@@@@@%. .=%@@@@@@%-. .@@@@@@@@@@@@@@@@%*-.. " + << RESET << '\n'; + std::cout << GREEN + << " . :%@@@@@@@@@@@@@@@@@@@@@- . -@@@@@@@@@@@@@@@@@@@@@%: " + << RESET << '\n'; + std::cout << GREEN + << " .:=*###############@@@@=. .=@@@@###############*-:. . " + << RESET << '\n'; + std::cout << GREEN + << " . .. :#@@@@@#+=--=+#@@@@@#. . " + << RESET << '\n'; + std::cout << GREEN + << " . . .=%@@@@@@@@@@@@%=. " + << RESET << '\n'; + std::cout << GREEN + << " . . .. ...-=++=:... . " + << RESET << '\n'; +} + +void GameConsole::showMenu() +{ + std::cout << GREEN << "========== CONSOLA DE OPERACIONES VAULT-TEC v" << CONSOLE_VERSION << " ==========" << RESET + << '\n'; + std::cout << GREEN << "<> [i] status " << RESET << " - Mostrar estado del refugio" << '\n'; + std::cout << GREEN << "<> [e] events " << RESET << " - Ver historial de eventos" << '\n'; + std::cout << GREEN << "<> [c] check " << RESET << " - Verificar evento activo" << '\n'; + std::cout << GREEN << "<> [x] explore " << RESET << " - Realizar una exploración" << '\n'; + std::cout << GREEN << "<> [f] fight " << RESET << " - Enfrentar a un enemigo" << '\n'; + std::cout << GREEN << "<> [s] save " << RESET << " - Guardar el progreso" << '\n'; + std::cout << GREEN << "<> [q] exit " << RESET << " - Salir del sistema" << '\n'; + std::cout << GREEN << "====================================" << RESET << '\n'; +} + +void GameConsole::clearScreen() +{ + std::system(CLEAR_SCREEN); +} + +void GameConsole::setEngine(Engine* engine) +{ + m_engine = engine; +} + +void GameConsole::executeCommand(const char& command) +{ + m_commandHistory.push_back(command); + + if (m_validOperations.find(command) != m_validOperations.end()) + { + switch (m_validOperations.at(command)) + { + case Operation::SHOW_STATUS: + std::cout << GREEN << "=== [INFO] Cargando información del refugio ===" << RESET << '\n'; + m_engine->playerShelter().showInfo(); + break; + case Operation::CHECK_EVENT: + std::cout << GREEN << "=== [INFO] Cargando sistema de eventos ===" << RESET << '\n'; + if (m_engine->checkEvent()) + { + std::cout << GREEN << "=== [INFO] Un nuevo evento requiere de su atención ===" << RESET << '\n'; + m_engine->processEvent(); + } + else + { + std::cout << GREEN << "=== [INFO] No hay novedades... Sonria :) ===" << RESET << '\n'; + } + break; + case Operation::EXIT: + std::cout << "Saliendo..." << '\n'; + m_keepRunning = false; + break; + default: std::cout << "Operación desconocida" << '\n'; break; + } + } + else + { + std::cout << "Operación desconocida" << '\n'; + } + std::cin.ignore(); + std::cin.get(); +} + +void GameConsole::interativeLoop() +{ + while (m_keepRunning) + { + showBanner(); + showMenu(); + std::string input; + std::cout << GREEN << "> " << RESET; + std::cin >> input; + + executeCommand(input[0]); + } +} diff --git a/src/gameSerializer.cpp b/src/engine/gameSerializer.cpp similarity index 99% rename from src/gameSerializer.cpp rename to src/engine/gameSerializer.cpp index b94cb86..f0f1a4f 100644 --- a/src/gameSerializer.cpp +++ b/src/engine/gameSerializer.cpp @@ -1,5 +1,7 @@ #include "gameSerializer.hpp" #include "engine.hpp" +#include "uiDef.hpp" + #include #include #include diff --git a/src/engine/visitorFactory.cpp b/src/engine/visitorFactory.cpp new file mode 100644 index 0000000..5bc4d9f --- /dev/null +++ b/src/engine/visitorFactory.cpp @@ -0,0 +1,90 @@ +#include "engine/visitorFactory.hpp" +#include "asaltante.hpp" + +#include +#include + +const std::vector VisitorFactory::NAMES = { + "Lucas", "Valentina", "Mateo", "Camila", "Santiago", "Julieta", "Benjamín", "Martina", "Joaquín", "Catalina", + "Tomás", "Emma", "Franco", "Isabella", "Thiago", "Renata", "Ignacio", "Mía", "Bruno", "Lola"}; + +const std::vector VisitorFactory::SURNAMES = { + "Fernández", "Gómez", "Rodríguez", "López", "Martínez", "Pérez", "González", "Romero", "Sosa", "Torres", + "Álvarez", "Ruiz", "Ramírez", "Flores", "Acosta", "Ortiz", "Silva", "Molina", "Castro", "Núñez"}; + +const std::vector VisitorFactory::GROUPS_ENEMIES = { + "El Lince", "Cuchillo", "Sombra", "Rata", "Machete", "El Tuerto", "Ruger", "Veneno", "Kilo", "Toro", + "Jaque", "Hueso", "Chispa", "Ruido", "Filo", "El Ciego", "Piedra", "Trapo", "Garrote", "Ladrido"}; + +const std::vector VisitorFactory::MERCHANTS = {"Don Eric", "El turco", + "El Sapo", "Maese Gutiérrez", + "Tito Ramires", "Nina la audaz", + "El foragido", "Candelario", + "Rubén el Viejo", "Salomé", + "Don Atún", "Capitán Fierro", + "Manolo Bidón", "Paco el Tranquilo", + "Zulema", "Yolanda", + "Valerio", "Iván de los Precios", + "Florinda", "Greta"}; + +VisitorFactory::VisitorFactory(RandomEventGenerator& rng, EngineData::GameConfig& config) + : m_randomGenetor(&rng) + , m_config(&config) +{ +} + +NPC::VisitanteVariant VisitorFactory::create(EngineData::Faction faction) +{ + static const std::unordered_map> + FACTORY_MAP = { + {EngineData::Faction::RAIDERS, + [](VisitorFactory* self) + { + auto name = self->m_randomGenetor->randomChoice(GROUPS_ENEMIES); + auto cantidad = + self->m_randomGenetor->getInt(self->m_config->fight.minEnemy, self->m_config->fight.minEnemy); + auto poderFuego = self->m_randomGenetor->getDouble(0.0, self->m_config->fight.enemyAttackMultiplier); + return Raider( + name, cantidad, self->m_randomGenetor, poderFuego, self->m_config->fight.surrenderChance); + }}, + {EngineData::Faction::REFUGEES, + [](VisitorFactory* self) + { + auto name = self->m_randomGenetor->randomChoice(NAMES); + auto surname = self->m_randomGenetor->randomChoice(SURNAMES); + auto fullName = name + " " + surname; + bool isFromVault = self->m_randomGenetor->chance(0.5); + auto bag = self->bagGenerator(isFromVault); + return Refugee(fullName, isFromVault, bag); + }}, + }; + + auto itMap = FACTORY_MAP.find(faction); + if (itMap != FACTORY_MAP.end()) + { + return itMap->second(this); + } + + throw std::runtime_error("Facción no válida"); +} + +std::unordered_map VisitorFactory::bagGenerator(bool isFromVault) +{ + { + std::unordered_map bag = { + {EngineData::Resources::FOOD, static_cast(m_randomGenetor->getInt(1, 5))}, + {EngineData::Resources::WATER, static_cast(m_randomGenetor->getInt(1, 5))}, + {EngineData::Resources::MEDICINE, static_cast(m_randomGenetor->getInt(0, 2))}, + {EngineData::Resources::AMMO, static_cast(m_randomGenetor->getInt(0, 3))}, + {EngineData::Resources::TOOLS, static_cast(m_randomGenetor->getInt(0, 2))}}; + + if (isFromVault) + { + bag[EngineData::Resources::ELECTRONICS] = static_cast(m_randomGenetor->getInt(0, 1)); + bag[EngineData::Resources::MATERIALS] = static_cast(m_randomGenetor->getInt(0, 2)); + bag[EngineData::Resources::ALCHOHOL] = static_cast(m_randomGenetor->getInt(0, 1)); + } + + return bag; + } +} diff --git a/src/main.cpp b/src/main.cpp index ea0fbe3..9b348f8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,7 +2,8 @@ #include #include -#include "engine.hpp" +#include "uiDef.hpp" +#include "engine/engine.hpp" auto constexpr HELP_FILE {"assets/help.txt"}; //< Nombre del archivo de ayuda diff --git a/src/refugio.cpp b/src/refugio.cpp index 39258be..40c1faf 100644 --- a/src/refugio.cpp +++ b/src/refugio.cpp @@ -1,4 +1,7 @@ #include "refugio.hpp" +#include "asaltante.hpp" +#include "refugiado.hpp" +#include Refugio::Refugio(const std::string& name, const std::string& leader) : EntidadGenerica(name) @@ -11,10 +14,10 @@ void Refugio::showInfo() const std::cout << "🏠 Refugio: " << m_name << "\t A cargo de: " << m_leader << "\n"; std::cout << "\t🛡️ Defensa: " << m_defense << "\n"; std::cout << "\t⚔️ Ataque: " << m_attack << "\n"; - std::cout << "👥 Moradores: "; - for (int refugee = 0; refugee < m_refugees.size(); refugee++) + std::cout << "👥 Moradores: " << "\n"; + for (const auto& refugee : m_refugees) { - std::cout << "\t - " << m_refugees.at(refugee) << std::endl; + refugee.showInfo(); } std::cout << "\n"; std::cout << "\t📦 Recursos: \n"; @@ -41,18 +44,30 @@ bool Refugio::consumeResource(const std::string& resource, float amount) return false; } -void Refugio::registerVisitant(const std::string& nombre, const EngineData::Faction faccion) +void Refugio::registerVisitant(const NPC::VisitanteVariant& visitante) { - if (!isSafeFaction(faccion)) - { -// std::cout << "Acceso denegado: La facción " << faccionToString(faccion) << " no es segura para el refugio." - // << std::endl; - return; - } + std::visit( + [this](const auto& visitor) + { + using VisitorType = std::decay_t; - Visitante nuevoVisitante {nombre, faccion}; - m_visitants->push_front(nuevoVisitante); - std::cout << "Visitante: " << nombre << " registrado existosamente en el refugio." << std::endl; + if constexpr (std::is_same_v) + { + std::cout << " 🔺 VAULT detecta problemas... " << '\n'; + visitor.showInfo(); + } + else if constexpr (std::is_same_v) + { + visitor.showInfo(); + m_refugees.push_back(visitor); + } + else + { + std::cout << "👀 Visitante sin comportamiento definido." << '\n'; + throw std::runtime_error("Visitante sin comportamiento definido"); + } + }, + visitante); } void Refugio::showVisits() @@ -61,16 +76,15 @@ void Refugio::showVisits() printRecursive(m_visitants->get_head()); } -void Refugio::printRecursive(DoublyListNode* mNode) +void Refugio::printRecursive(DoublyListNode* mNode) { if (!mNode) { - std::cout << "Fin del registro!" << std::endl; + std::cout << "Fin del registro!" << '\n'; return; } } - bool Refugio::isSafeFaction(const EngineData::Faction faccion) const { return (faccion == EngineData::Faction::REFUGEES || faccion == EngineData::Faction::WATER_MERCHANTS ||