Files
jaildoctors_dilemma/source/game/gameplay/room_loader.cpp
2025-11-19 08:09:19 +01:00

337 lines
12 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "room_loader.hpp"
#include <exception> // Para exception
#include <iostream> // Para cout, cerr
#include "external/fkyaml_node.hpp" // Para fkyaml::node
#include "core/resources/resource_helper.hpp" // Para Resource::Helper
#include "utils/defines.hpp" // Para TILE_SIZE
#include "utils/utils.hpp" // Para stringToColor
// Convierte room connection de YAML a formato interno
auto RoomLoader::convertRoomConnection(const std::string& value) -> std::string {
if (value == "null" || value.empty()) {
return "0";
}
// Si ya tiene .yaml, devolverlo tal cual; si no, añadirlo
if (value.size() > 5 && value.substr(value.size() - 5) == ".yaml") {
return value;
}
return value + ".yaml";
}
// Convierte string de autoSurface a int
auto RoomLoader::convertAutoSurface(const fkyaml::node& node) -> int {
if (node.is_integer()) {
return node.get_value<int>();
}
if (node.is_string()) {
const std::string value = node.get_value<std::string>();
if (value == "left") return -1;
if (value == "right") return 1;
}
return 0; // "none" o default
}
// Convierte un tilemap 2D a vector 1D flat
auto RoomLoader::flattenTilemap(const std::vector<std::vector<int>>& tilemap_2d) -> std::vector<int> {
std::vector<int> tilemap_flat;
tilemap_flat.reserve(512); // 16 rows × 32 cols
for (const auto& row : tilemap_2d) {
for (int tile : row) {
tilemap_flat.push_back(tile);
}
}
return tilemap_flat;
}
// Carga un archivo de room en formato YAML
auto RoomLoader::loadYAML(const std::string& file_path, bool verbose) -> Room::Data {
Room::Data room;
// Extract filename for logging
const std::string FILE_NAME = file_path.substr(file_path.find_last_of("\\/") + 1);
try {
// Load YAML file using ResourceHelper (supports both filesystem and pack)
auto file_data = Resource::Helper::loadFile(file_path);
if (file_data.empty()) {
std::cerr << "Error: Unable to load file " << FILE_NAME << '\n';
return room;
}
// Parse YAML from string
std::string yaml_content(file_data.begin(), file_data.end());
auto yaml = fkyaml::node::deserialize(yaml_content);
// --- Parse room configuration ---
if (yaml.contains("room")) {
const auto& room_node = yaml["room"];
// Extract room number from filename (e.g., "01.yaml" → "01")
room.number = FILE_NAME.substr(0, FILE_NAME.find_last_of('.'));
// Basic properties
if (room_node.contains("name")) {
room.name = room_node["name"].get_value<std::string>();
}
if (room_node.contains("bgColor")) {
room.bg_color = room_node["bgColor"].get_value<std::string>();
}
if (room_node.contains("border")) {
room.border_color = room_node["border"].get_value<std::string>();
}
if (room_node.contains("tileSetFile")) {
room.tile_set_file = room_node["tileSetFile"].get_value<std::string>();
}
// Room connections
if (room_node.contains("connections")) {
const auto& conn = room_node["connections"];
if (conn.contains("up")) {
room.upper_room = convertRoomConnection(conn["up"].get_value_or<std::string>("null"));
} else {
room.upper_room = "0";
}
if (conn.contains("down")) {
room.lower_room = convertRoomConnection(conn["down"].get_value_or<std::string>("null"));
} else {
room.lower_room = "0";
}
if (conn.contains("left")) {
room.left_room = convertRoomConnection(conn["left"].get_value_or<std::string>("null"));
} else {
room.left_room = "0";
}
if (conn.contains("right")) {
room.right_room = convertRoomConnection(conn["right"].get_value_or<std::string>("null"));
} else {
room.right_room = "0";
}
}
// Item colors
if (room_node.contains("itemColor1")) {
room.item_color1 = room_node["itemColor1"].get_value_or<std::string>("yellow");
} else {
room.item_color1 = "yellow";
}
if (room_node.contains("itemColor2")) {
room.item_color2 = room_node["itemColor2"].get_value_or<std::string>("magenta");
} else {
room.item_color2 = "magenta";
}
// Dirección de la cinta transportadora (left/none/right)
if (room_node.contains("conveyorBelt")) {
room.conveyor_belt_direction = convertAutoSurface(room_node["conveyorBelt"]);
} else {
room.conveyor_belt_direction = 0;
}
}
// --- Parse tilemap ---
if (yaml.contains("tilemap")) {
const auto& tilemap_node = yaml["tilemap"];
// Read 2D array
std::vector<std::vector<int>> tilemap_2d;
tilemap_2d.reserve(16);
for (const auto& row_node : tilemap_node) {
std::vector<int> row;
row.reserve(32);
for (const auto& tile_node : row_node) {
row.push_back(tile_node.get_value<int>());
}
tilemap_2d.push_back(row);
}
// Convert to 1D flat array
room.tile_map = flattenTilemap(tilemap_2d);
if (verbose) {
std::cout << "Loaded tilemap: " << room.tile_map.size() << " tiles\n";
}
} else {
std::cerr << "Warning: No tilemap found in " << FILE_NAME << '\n';
}
// --- Parse enemies ---
if (yaml.contains("enemies") && !yaml["enemies"].is_null()) {
const auto& enemies_node = yaml["enemies"];
for (const auto& enemy_node : enemies_node) {
Enemy::Data enemy;
// Animation path
if (enemy_node.contains("animation")) {
enemy.animation_path = enemy_node["animation"].get_value<std::string>();
}
// Position (in tiles, convert to pixels)
if (enemy_node.contains("position")) {
const auto& pos = enemy_node["position"];
if (pos.contains("x")) {
enemy.x = pos["x"].get_value<float>() * TILE_SIZE;
}
if (pos.contains("y")) {
enemy.y = pos["y"].get_value<float>() * TILE_SIZE;
}
}
// Velocity (already in pixels/second)
if (enemy_node.contains("velocity")) {
const auto& vel = enemy_node["velocity"];
if (vel.contains("x")) {
enemy.vx = vel["x"].get_value<float>();
}
if (vel.contains("y")) {
enemy.vy = vel["y"].get_value<float>();
}
}
// Boundaries (in tiles, convert to pixels)
// Soporta formato nuevo (position1/position2) y antiguo (x1/y1/x2/y2)
if (enemy_node.contains("boundaries")) {
const auto& bounds = enemy_node["boundaries"];
// Nuevo formato: position1 y position2
if (bounds.contains("position1")) {
const auto& pos1 = bounds["position1"];
if (pos1.contains("x")) {
enemy.x1 = pos1["x"].get_value<int>() * TILE_SIZE;
}
if (pos1.contains("y")) {
enemy.y1 = pos1["y"].get_value<int>() * TILE_SIZE;
}
}
if (bounds.contains("position2")) {
const auto& pos2 = bounds["position2"];
if (pos2.contains("x")) {
enemy.x2 = pos2["x"].get_value<int>() * TILE_SIZE;
}
if (pos2.contains("y")) {
enemy.y2 = pos2["y"].get_value<int>() * TILE_SIZE;
}
}
// Formato antiguo: x1/y1/x2/y2 (compatibilidad)
if (bounds.contains("x1")) {
enemy.x1 = bounds["x1"].get_value<int>() * TILE_SIZE;
}
if (bounds.contains("y1")) {
enemy.y1 = bounds["y1"].get_value<int>() * TILE_SIZE;
}
if (bounds.contains("x2")) {
enemy.x2 = bounds["x2"].get_value<int>() * TILE_SIZE;
}
if (bounds.contains("y2")) {
enemy.y2 = bounds["y2"].get_value<int>() * TILE_SIZE;
}
}
// Color
if (enemy_node.contains("color")) {
enemy.color = enemy_node["color"].get_value_or<std::string>("white");
} else {
enemy.color = "white";
}
// Optional fields
if (enemy_node.contains("flip")) {
enemy.flip = enemy_node["flip"].get_value_or<bool>(false);
} else {
enemy.flip = false;
}
if (enemy_node.contains("mirror")) {
enemy.mirror = enemy_node["mirror"].get_value_or<bool>(false);
} else {
enemy.mirror = false;
}
if (enemy_node.contains("frame")) {
enemy.frame = enemy_node["frame"].get_value_or<int>(-1);
} else {
enemy.frame = -1;
}
room.enemies.push_back(enemy);
}
if (verbose) {
std::cout << "Loaded " << room.enemies.size() << " enemies\n";
}
}
// --- Parse items ---
if (yaml.contains("items") && !yaml["items"].is_null()) {
const auto& items_node = yaml["items"];
for (const auto& item_node : items_node) {
Item::Data item;
// Tileset file
if (item_node.contains("tileSetFile")) {
item.tile_set_file = item_node["tileSetFile"].get_value<std::string>();
}
// Tile index
if (item_node.contains("tile")) {
item.tile = item_node["tile"].get_value<int>();
}
// Position (in tiles, convert to pixels)
if (item_node.contains("position")) {
const auto& pos = item_node["position"];
if (pos.contains("x")) {
item.x = pos["x"].get_value<float>() * TILE_SIZE;
}
if (pos.contains("y")) {
item.y = pos["y"].get_value<float>() * TILE_SIZE;
}
}
// Counter
if (item_node.contains("counter")) {
item.counter = item_node["counter"].get_value_or<int>(0);
} else {
item.counter = 0;
}
// Colors (assigned from room defaults)
item.color1 = stringToColor(room.item_color1);
item.color2 = stringToColor(room.item_color2);
room.items.push_back(item);
}
if (verbose) {
std::cout << "Loaded " << room.items.size() << " items\n";
}
}
if (verbose) {
std::cout << "Room loaded successfully: " << FILE_NAME << '\n';
}
} catch (const fkyaml::exception& e) {
std::cerr << "YAML parsing error in " << FILE_NAME << ": " << e.what() << '\n';
} catch (const std::exception& e) {
std::cerr << "Error loading room " << FILE_NAME << ": " << e.what() << '\n';
}
return room;
}