112 lines
4.5 KiB
C++
112 lines
4.5 KiB
C++
// player_config.cpp - Implementació del parser de PlayerConfig
|
|
// © 2026 JailDesigner
|
|
|
|
#include "game/entities/player_config.hpp"
|
|
|
|
#include <cstdint>
|
|
#include <exception>
|
|
#include <iostream>
|
|
#include <string>
|
|
|
|
namespace {
|
|
|
|
// Helper: extreu un SDL_Color d'una seqüència de 3 enters [r, g, b] del YAML.
|
|
// Retorna true si el format és vàlid.
|
|
auto parseColor(const fkyaml::node& node, SDL_Color& out) -> bool {
|
|
if (!node.is_sequence() || node.size() != 3) {
|
|
return false;
|
|
}
|
|
const auto R = node[0].get_value<uint32_t>();
|
|
const auto G = node[1].get_value<uint32_t>();
|
|
const auto B = node[2].get_value<uint32_t>();
|
|
out = SDL_Color{
|
|
.r = static_cast<uint8_t>(R),
|
|
.g = static_cast<uint8_t>(G),
|
|
.b = static_cast<uint8_t>(B),
|
|
.a = 255};
|
|
return true;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
auto PlayerConfig::fromYaml(const fkyaml::node& node) -> std::optional<PlayerConfig> {
|
|
try {
|
|
PlayerConfig cfg;
|
|
|
|
cfg.name = node.contains("name") ? node["name"].get_value<std::string>() : "player";
|
|
|
|
// shape
|
|
if (!node.contains("shape") || !node["shape"].contains("path")) {
|
|
std::cerr << "[PlayerConfig] Error: falta 'shape.path'" << '\n';
|
|
return std::nullopt;
|
|
}
|
|
const auto& shape = node["shape"];
|
|
cfg.shape.path = shape["path"].get_value<std::string>();
|
|
cfg.shape.scale = shape.contains("scale") ? shape["scale"].get_value<float>() : 1.0F;
|
|
cfg.shape.collision_factor = shape.contains("collision_factor")
|
|
? shape["collision_factor"].get_value<float>()
|
|
: 1.0F;
|
|
|
|
// physics
|
|
if (!node.contains("physics")) {
|
|
std::cerr << "[PlayerConfig] Error: falta 'physics'" << '\n';
|
|
return std::nullopt;
|
|
}
|
|
const auto& physics = node["physics"];
|
|
cfg.physics.mass = physics["mass"].get_value<float>();
|
|
cfg.physics.restitution = physics["restitution"].get_value<float>();
|
|
cfg.physics.linear_damping = physics["linear_damping"].get_value<float>();
|
|
cfg.physics.angular_damping = physics["angular_damping"].get_value<float>();
|
|
cfg.physics.rotation_speed = physics["rotation_speed"].get_value<float>();
|
|
cfg.physics.acceleration = physics["acceleration"].get_value<float>();
|
|
cfg.physics.max_velocity = physics["max_velocity"].get_value<float>();
|
|
cfg.physics.death_impact_factor = physics["death_impact_factor"].get_value<float>();
|
|
|
|
// invulnerability
|
|
if (!node.contains("invulnerability")) {
|
|
std::cerr << "[PlayerConfig] Error: falta 'invulnerability'" << '\n';
|
|
return std::nullopt;
|
|
}
|
|
const auto& invul = node["invulnerability"];
|
|
cfg.invulnerability.duration = invul["duration"].get_value<float>();
|
|
cfg.invulnerability.blink_visible = invul["blink_visible"].get_value<float>();
|
|
cfg.invulnerability.blink_invisible = invul["blink_invisible"].get_value<float>();
|
|
|
|
// hurt
|
|
if (!node.contains("hurt")) {
|
|
std::cerr << "[PlayerConfig] Error: falta 'hurt'" << '\n';
|
|
return std::nullopt;
|
|
}
|
|
cfg.hurt.duration = node["hurt"]["duration"].get_value<float>();
|
|
cfg.hurt.blink_hz = node["hurt"]["blink_hz"].get_value<float>();
|
|
|
|
// visual_thrust
|
|
if (!node.contains("visual_thrust")) {
|
|
std::cerr << "[PlayerConfig] Error: falta 'visual_thrust'" << '\n';
|
|
return std::nullopt;
|
|
}
|
|
cfg.visual_thrust.push_divisor = node["visual_thrust"]["push_divisor"].get_value<float>();
|
|
cfg.visual_thrust.scale_divisor = node["visual_thrust"]["scale_divisor"].get_value<float>();
|
|
|
|
// colors
|
|
if (!node.contains("colors") ||
|
|
!parseColor(node["colors"]["normal"], cfg.colors.normal) ||
|
|
!parseColor(node["colors"]["hurt"], cfg.colors.hurt)) {
|
|
std::cerr << "[PlayerConfig] Error: 'colors.normal' / 'colors.hurt' no són seqüències [r,g,b]" << '\n';
|
|
return std::nullopt;
|
|
}
|
|
|
|
// weapon
|
|
if (!node.contains("weapon")) {
|
|
std::cerr << "[PlayerConfig] Error: falta 'weapon'" << '\n';
|
|
return std::nullopt;
|
|
}
|
|
cfg.weapon.bullet_speed = node["weapon"]["bullet_speed"].get_value<float>();
|
|
|
|
return cfg;
|
|
} catch (const std::exception& e) {
|
|
std::cerr << "[PlayerConfig] Excepció parsejant: " << e.what() << '\n';
|
|
return std::nullopt;
|
|
}
|
|
}
|