// enemy_config.hpp - Configuració d'un tipus d'enemic carregada des de YAML // © 2026 JailDesigner // // Una instància per tipus (Pentagon/Square/Pinwheel), carregada un cop al // startup per EnemyRegistry i compartida entre totes les instàncies d'aquell // tipus. Estructura paral·lela a PlayerConfig. #pragma once #include #include #include #include "external/fkyaml_node.hpp" #include "game/entities/enemy.hpp" // EnemyType #include "game/entities/enemy_ai.hpp" #include "game/entities/enemy_event.hpp" struct EnemyConfig { struct ShapeCfg { std::string path; float scale; // multiplicador visual + hitbox sobre la mida nativa del .shp float collision_factor; // ajust opcional del hitbox respecte el cercle circumscrit (default 1.0) }; struct PhysicsCfg { float mass; float speed; float rotation_delta_min; float rotation_delta_max; float restitution; // rebot contra parets (1.0 = perfectament elàstic) float linear_damping; // fricció lineal (s^-1) float angular_damping; }; // Camps específics de cada AI. Els no aplicables a un tipus queden a 0.0F // i no s'usen — el dispatch viu a Enemy::behaviorXxx. struct BehaviorCfg { // Pentagon float zigzag_prob_per_second{0.0F}; float angle_change_max{0.0F}; // Square float tracking_strength{0.0F}; float tracking_interval{0.0F}; // Pinwheel float rotation_proximity_multiplier{0.0F}; float proximity_distance{0.0F}; }; // Animacions decoratives. Compartides estructuralment entre tots els tipus // però amb valors propis per personalitzar la "personalitat" visual de cada un. struct AnimationCfg { struct PulseCfg { float trigger_prob_per_second; // probabilitat per segon d'iniciar un pulse float duration_min; float duration_max; float amplitude_min; // amplitud d'escala (±) float amplitude_max; float frequency_min; // Hz float frequency_max; }; struct RotationAccelCfg { float trigger_prob_per_second; float duration_min; // segons de transició al nou speed float duration_max; float multiplier_min; // multiplicador sobre rotation_delta_base float multiplier_max; }; PulseCfg pulse; RotationAccelCfg rotation_accel; }; struct WoundedCfg { float duration; // segons en estat ferit abans d'explotar float blink_hz; // freqüència del parpelleig color normal ↔ wounded }; struct SpawnCfg { float invulnerability_duration; // segons d'invulnerabilitat post-spawn float invulnerability_brightness_start; // brightness inicial (corba LERP) float invulnerability_brightness_end; // brightness final float invulnerability_scale_start; // escala inicial (corba LERP, 0 = invisible) float invulnerability_scale_end; // escala final (1 = mida nativa) float safety_distance; // px mínim respecte al player al spawn }; struct ColorsCfg { SDL_Color normal; SDL_Color wounded; }; std::string name; EnemyType ai_type; ShapeCfg shape; PhysicsCfg physics; BehaviorCfg behavior; AnimationCfg animation; WoundedCfg wounded; SpawnCfg spawn; ColorsCfg colors; int score; EnemyEventConfig events; EnemyAiConfig ai; // Parseja un descriptor d'enemic. expected_ai_type valida que ai_type del // YAML coincideix amb el tipus que el caller espera (segons el directori). static auto fromYaml(const fkyaml::node& node, EnemyType expected_ai_type) -> std::optional; };