395 lines
14 KiB
C++
395 lines
14 KiB
C++
#include "asset.h"
|
|
#include "balloon.h" // Para BalloonType, BalloonSize, BALLOON_SIZE, BALLOON_VELX_NEGATIVE, BALLOON_VELX_POSITIVE
|
|
#include "balloon_formations.h"
|
|
#include "param.h" // Para Param, ParamGame, param
|
|
#include "utils.h" // Para Zone, BLOCK
|
|
#include <array> // Para array
|
|
#include <fstream>
|
|
#include <map>
|
|
#include <sstream>
|
|
#include <string>
|
|
|
|
void BalloonFormations::initFormations() {
|
|
// Calcular posiciones base
|
|
const int DEFAULT_POS_Y = param.game.play_area.rect.h - BALLOON_SPAWN_HEIGHT;
|
|
|
|
const int X4_0 = param.game.play_area.rect.x;
|
|
const int X4_100 = param.game.play_area.rect.w - BALLOON_SIZE.at(3);
|
|
const int X3_0 = param.game.play_area.rect.x;
|
|
const int X3_100 = param.game.play_area.rect.w - BALLOON_SIZE.at(2);
|
|
const int X2_0 = param.game.play_area.rect.x;
|
|
const int X2_100 = param.game.play_area.rect.w - BALLOON_SIZE.at(1);
|
|
const int X1_0 = param.game.play_area.rect.x;
|
|
const int X1_50 = param.game.play_area.center_x - (BALLOON_SIZE.at(0) / 2);
|
|
const int X1_100 = param.game.play_area.rect.w - BALLOON_SIZE.at(0);
|
|
|
|
// Variables calculadas para posiciones especiales
|
|
const int QUARTER1_X4 = param.game.play_area.first_quarter_x - (BALLOON_SIZE.at(3) / 2);
|
|
const int QUARTER3_X4 = param.game.play_area.third_quarter_x - (BALLOON_SIZE.at(3) / 2);
|
|
|
|
// Mapa de variables para reemplazar en el archivo
|
|
std::map<std::string, float> variables = {
|
|
{"X1_0", X1_0},
|
|
{"X1_50", X1_50},
|
|
{"X1_100", X1_100},
|
|
{"X2_0", X2_0},
|
|
{"X2_100", X2_100},
|
|
{"X3_0", X3_0},
|
|
{"X3_100", X3_100},
|
|
{"X4_0", X4_0},
|
|
{"X4_100", X4_100},
|
|
{"QUARTER1_X4", QUARTER1_X4},
|
|
{"QUARTER3_X4", QUARTER3_X4},
|
|
{"DEFAULT_POS_Y", DEFAULT_POS_Y},
|
|
{"BALLOON_SIZE_0", BALLOON_SIZE.at(0)},
|
|
{"BALLOON_SIZE_1", BALLOON_SIZE.at(1)},
|
|
{"BALLOON_SIZE_2", BALLOON_SIZE.at(2)},
|
|
{"BALLOON_SIZE_3", BALLOON_SIZE.at(3)},
|
|
{"RIGHT", BALLOON_VELX_POSITIVE},
|
|
{"LEFT", BALLOON_VELX_NEGATIVE}};
|
|
|
|
balloon_formation_.reserve(NUMBER_OF_BALLOON_FORMATIONS);
|
|
|
|
if (!loadFormationsFromFile(Asset::get()->get("balloon_formations.txt"), variables)) {
|
|
// Fallback: cargar formaciones por defecto si falla la carga del archivo
|
|
loadDefaultFormations();
|
|
}
|
|
}
|
|
|
|
auto BalloonFormations::loadFormationsFromFile(const std::string& filename, const std::map<std::string, float>& variables) -> bool {
|
|
std::ifstream file(filename);
|
|
if (!file.is_open()) {
|
|
return false;
|
|
}
|
|
|
|
std::string line;
|
|
int current_formation = -1;
|
|
std::vector<BalloonFormationParams> current_params;
|
|
|
|
while (std::getline(file, line)) {
|
|
// Eliminar espacios en blanco al inicio y final
|
|
line = trim(line);
|
|
|
|
// Saltar líneas vacías y comentarios
|
|
if (line.empty() || line.at(0) == '#') {
|
|
continue;
|
|
}
|
|
|
|
// Verificar si es una nueva formación
|
|
if (line.substr(0, 10) == "formation:") {
|
|
// Guardar formación anterior si existe
|
|
if (current_formation >= 0 && !current_params.empty()) {
|
|
balloon_formation_.emplace_back(current_params.size(), current_params);
|
|
}
|
|
|
|
// Iniciar nueva formación
|
|
current_formation = std::stoi(line.substr(10));
|
|
current_params.clear();
|
|
continue;
|
|
}
|
|
|
|
// Procesar línea de parámetros de balloon
|
|
if (current_formation >= 0) {
|
|
auto params = parseBalloonLine(line, variables);
|
|
if (params.has_value()) {
|
|
current_params.push_back(params.value());
|
|
}
|
|
}
|
|
}
|
|
|
|
// Guardar última formación
|
|
if (current_formation >= 0 && !current_params.empty()) {
|
|
balloon_formation_.emplace_back(current_params.size(), current_params);
|
|
}
|
|
|
|
// Crear variantes flotantes (formaciones 50-99)
|
|
createFloaterVariants();
|
|
|
|
// Añadir formación de prueba
|
|
addTestFormation();
|
|
|
|
file.close();
|
|
return true;
|
|
}
|
|
|
|
auto BalloonFormations::parseBalloonLine(const std::string& line, const std::map<std::string, float>& variables) -> std::optional<BalloonFormationParams> {
|
|
std::istringstream iss(line);
|
|
std::string token;
|
|
std::vector<std::string> tokens;
|
|
|
|
// Dividir por comas
|
|
while (std::getline(iss, token, ',')) {
|
|
tokens.push_back(trim(token));
|
|
}
|
|
|
|
if (tokens.size() != 7) {
|
|
return std::nullopt;
|
|
}
|
|
|
|
try {
|
|
int x = evaluateExpression(tokens.at(0), variables);
|
|
int desp = evaluateExpression(tokens.at(1), variables);
|
|
int y = evaluateExpression(tokens.at(2), variables);
|
|
float vel_x = evaluateExpression(tokens.at(3), variables);
|
|
|
|
BalloonType type = (tokens.at(4) == "BALLOON") ? BalloonType::BALLOON : BalloonType::FLOATER;
|
|
|
|
BalloonSize size;
|
|
if (tokens.at(5) == "SIZE1") {
|
|
size = BalloonSize::SIZE1;
|
|
desp = desp * (BALLOON_SIZE.at(0) + 1);
|
|
} else if (tokens.at(5) == "SIZE2") {
|
|
size = BalloonSize::SIZE2;
|
|
desp = desp * (BALLOON_SIZE.at(1) + 1);
|
|
} else if (tokens.at(5) == "SIZE3") {
|
|
size = BalloonSize::SIZE3;
|
|
desp = desp * (BALLOON_SIZE.at(2) + 1);
|
|
} else if (tokens.at(5) == "SIZE4") {
|
|
size = BalloonSize::SIZE4;
|
|
desp = desp * (BALLOON_SIZE.at(3) + 1);
|
|
} else {
|
|
return std::nullopt;
|
|
}
|
|
|
|
int creation_time = CREATION_TIME + evaluateExpression(tokens.at(6), variables);
|
|
|
|
return BalloonFormationParams(x + desp, y, vel_x, type, size, creation_time);
|
|
} catch (const std::exception&) {
|
|
return std::nullopt;
|
|
}
|
|
}
|
|
|
|
auto BalloonFormations::evaluateExpression(const std::string& expr, const std::map<std::string, float>& variables) -> float {
|
|
std::string trimmed_expr = trim(expr);
|
|
|
|
// Si es un número directo
|
|
if ((std::isdigit(trimmed_expr.at(0)) != 0) || (trimmed_expr.at(0) == '-' && trimmed_expr.length() > 1)) {
|
|
return std::stoi(trimmed_expr);
|
|
}
|
|
|
|
// Si es una variable simple
|
|
if (variables.find(trimmed_expr) != variables.end()) {
|
|
return variables.at(trimmed_expr);
|
|
}
|
|
|
|
// Evaluación de expresiones simples (suma, resta, multiplicación)
|
|
return evaluateSimpleExpression(trimmed_expr, variables);
|
|
}
|
|
|
|
auto BalloonFormations::evaluateSimpleExpression(const std::string& expr, const std::map<std::string, float>& variables) -> float {
|
|
// Buscar operadores (+, -, *, /)
|
|
for (size_t i = 1; i < expr.length(); ++i) {
|
|
char op = expr.at(i);
|
|
if (op == '+' || op == '-' || op == '*' || op == '/') {
|
|
std::string left = trim(expr.substr(0, i));
|
|
std::string right = trim(expr.substr(i + 1));
|
|
|
|
int left_val = evaluateExpression(left, variables);
|
|
int right_val = evaluateExpression(right, variables);
|
|
|
|
switch (op) {
|
|
case '+':
|
|
return left_val + right_val;
|
|
case '-':
|
|
return left_val - right_val;
|
|
case '*':
|
|
return left_val * right_val;
|
|
case '/':
|
|
return right_val != 0 ? left_val / right_val : 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Si no se encuentra operador, intentar como variable o número
|
|
return variables.find(expr) != variables.end() ? variables.at(expr) : std::stoi(expr);
|
|
}
|
|
|
|
auto BalloonFormations::trim(const std::string& str) -> std::string {
|
|
size_t start = str.find_first_not_of(" \t\r\n");
|
|
if (start == std::string::npos) {
|
|
return "";
|
|
}
|
|
size_t end = str.find_last_not_of(" \t\r\n");
|
|
return str.substr(start, end - start + 1);
|
|
}
|
|
|
|
void BalloonFormations::createFloaterVariants() {
|
|
balloon_formation_.resize(100);
|
|
|
|
// Crear variantes flotantes de las primeras 50 formaciones
|
|
for (size_t k = 0; k < 50 && k < balloon_formation_.size(); k++) {
|
|
std::vector<BalloonFormationParams> floater_params;
|
|
floater_params.reserve(balloon_formation_.at(k).number_of_balloons);
|
|
|
|
for (int i = 0; i < balloon_formation_.at(k).number_of_balloons; i++) {
|
|
const auto& original = balloon_formation_.at(k).init.at(i);
|
|
floater_params.emplace_back(
|
|
original.x, original.y, original.vel_x, BalloonType::FLOATER, original.size, original.creation_counter);
|
|
}
|
|
|
|
balloon_formation_.at(k + 50) = BalloonFormationUnit(
|
|
balloon_formation_.at(k).number_of_balloons, floater_params);
|
|
}
|
|
}
|
|
|
|
void BalloonFormations::addTestFormation() {
|
|
std::vector<BalloonFormationParams> test_params = {
|
|
{10, -BLOCK, 0, BalloonType::FLOATER, BalloonSize::SIZE1, 200},
|
|
{50, -BLOCK, 0, BalloonType::FLOATER, BalloonSize::SIZE2, 200},
|
|
{90, -BLOCK, 0, BalloonType::FLOATER, BalloonSize::SIZE3, 200},
|
|
{140, -BLOCK, 0, BalloonType::FLOATER, BalloonSize::SIZE4, 200}};
|
|
|
|
balloon_formation_.at(99) = BalloonFormationUnit(4, test_params);
|
|
}
|
|
|
|
void BalloonFormations::loadDefaultFormations() {
|
|
// Código de fallback con algunas formaciones básicas hardcodeadas
|
|
// para que el juego funcione aunque falle la carga del archivo
|
|
|
|
const int DEFAULT_POS_Y = param.game.play_area.rect.h - BALLOON_SPAWN_HEIGHT;
|
|
const int X4_0 = param.game.play_area.rect.x;
|
|
const int X4_100 = param.game.play_area.rect.w - BALLOON_SIZE.at(3);
|
|
|
|
// Formación básica #00
|
|
std::vector<BalloonFormationParams> basic_formation = {
|
|
BalloonFormationParams(X4_0, DEFAULT_POS_Y, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE4, CREATION_TIME),
|
|
BalloonFormationParams(X4_100, DEFAULT_POS_Y, BALLOON_VELX_NEGATIVE, BalloonType::BALLOON, BalloonSize::SIZE4, CREATION_TIME)};
|
|
balloon_formation_.emplace_back(2, basic_formation);
|
|
}
|
|
|
|
// Inicializa los conjuntos de formaciones
|
|
void BalloonFormations::initFormationPools() {
|
|
// Reserva espacio para cada pool de formaciones
|
|
balloon_formation_pool_.resize(NUMBER_OF_SETS_PER_POOL);
|
|
|
|
// Set #0
|
|
balloon_formation_pool_.at(0) = {
|
|
&balloon_formation_.at(0),
|
|
&balloon_formation_.at(1),
|
|
&balloon_formation_.at(2),
|
|
&balloon_formation_.at(3),
|
|
&balloon_formation_.at(4),
|
|
&balloon_formation_.at(5),
|
|
&balloon_formation_.at(6),
|
|
&balloon_formation_.at(7),
|
|
&balloon_formation_.at(8),
|
|
&balloon_formation_.at(9)};
|
|
|
|
// Set #1
|
|
balloon_formation_pool_.at(1) = {
|
|
&balloon_formation_.at(10),
|
|
&balloon_formation_.at(11),
|
|
&balloon_formation_.at(12),
|
|
&balloon_formation_.at(13),
|
|
&balloon_formation_.at(14),
|
|
&balloon_formation_.at(15),
|
|
&balloon_formation_.at(16),
|
|
&balloon_formation_.at(17),
|
|
&balloon_formation_.at(18),
|
|
&balloon_formation_.at(19)};
|
|
|
|
// Set #2
|
|
balloon_formation_pool_.at(2) = {
|
|
&balloon_formation_.at(0),
|
|
&balloon_formation_.at(1),
|
|
&balloon_formation_.at(2),
|
|
&balloon_formation_.at(3),
|
|
&balloon_formation_.at(4),
|
|
&balloon_formation_.at(55),
|
|
&balloon_formation_.at(56),
|
|
&balloon_formation_.at(57),
|
|
&balloon_formation_.at(58),
|
|
&balloon_formation_.at(59)};
|
|
|
|
// Set #3
|
|
balloon_formation_pool_.at(3) = {
|
|
&balloon_formation_.at(50),
|
|
&balloon_formation_.at(51),
|
|
&balloon_formation_.at(52),
|
|
&balloon_formation_.at(53),
|
|
&balloon_formation_.at(54),
|
|
&balloon_formation_.at(5),
|
|
&balloon_formation_.at(6),
|
|
&balloon_formation_.at(7),
|
|
&balloon_formation_.at(8),
|
|
&balloon_formation_.at(9)};
|
|
|
|
// Set #4
|
|
balloon_formation_pool_.at(4) = {
|
|
&balloon_formation_.at(60),
|
|
&balloon_formation_.at(61),
|
|
&balloon_formation_.at(62),
|
|
&balloon_formation_.at(63),
|
|
&balloon_formation_.at(64),
|
|
&balloon_formation_.at(65),
|
|
&balloon_formation_.at(66),
|
|
&balloon_formation_.at(67),
|
|
&balloon_formation_.at(68),
|
|
&balloon_formation_.at(69)};
|
|
|
|
// Set #5
|
|
balloon_formation_pool_.at(5) = {
|
|
&balloon_formation_.at(10),
|
|
&balloon_formation_.at(61),
|
|
&balloon_formation_.at(12),
|
|
&balloon_formation_.at(63),
|
|
&balloon_formation_.at(14),
|
|
&balloon_formation_.at(65),
|
|
&balloon_formation_.at(16),
|
|
&balloon_formation_.at(67),
|
|
&balloon_formation_.at(18),
|
|
&balloon_formation_.at(69)};
|
|
|
|
// Set #6
|
|
balloon_formation_pool_.at(6) = {
|
|
&balloon_formation_.at(60),
|
|
&balloon_formation_.at(11),
|
|
&balloon_formation_.at(62),
|
|
&balloon_formation_.at(13),
|
|
&balloon_formation_.at(64),
|
|
&balloon_formation_.at(15),
|
|
&balloon_formation_.at(66),
|
|
&balloon_formation_.at(17),
|
|
&balloon_formation_.at(68),
|
|
&balloon_formation_.at(19)};
|
|
|
|
// Set #7
|
|
balloon_formation_pool_.at(7) = {
|
|
&balloon_formation_.at(20),
|
|
&balloon_formation_.at(21),
|
|
&balloon_formation_.at(22),
|
|
&balloon_formation_.at(23),
|
|
&balloon_formation_.at(24),
|
|
&balloon_formation_.at(65),
|
|
&balloon_formation_.at(66),
|
|
&balloon_formation_.at(67),
|
|
&balloon_formation_.at(68),
|
|
&balloon_formation_.at(69)};
|
|
|
|
// Set #8
|
|
balloon_formation_pool_.at(8) = {
|
|
&balloon_formation_.at(70),
|
|
&balloon_formation_.at(71),
|
|
&balloon_formation_.at(72),
|
|
&balloon_formation_.at(73),
|
|
&balloon_formation_.at(74),
|
|
&balloon_formation_.at(15),
|
|
&balloon_formation_.at(16),
|
|
&balloon_formation_.at(17),
|
|
&balloon_formation_.at(18),
|
|
&balloon_formation_.at(19)};
|
|
|
|
// Set #9
|
|
balloon_formation_pool_.at(9) = {
|
|
&balloon_formation_.at(20),
|
|
&balloon_formation_.at(21),
|
|
&balloon_formation_.at(22),
|
|
&balloon_formation_.at(23),
|
|
&balloon_formation_.at(24),
|
|
&balloon_formation_.at(70),
|
|
&balloon_formation_.at(71),
|
|
&balloon_formation_.at(72),
|
|
&balloon_formation_.at(73),
|
|
&balloon_formation_.at(74)};
|
|
}
|