// enemy_event_dispatcher.cpp - Implementació del dispatcher d'events d'enemic // © 2026 JailDesigner #include "game/systems/enemy_event_dispatcher.hpp" #include #include "core/defaults.hpp" #include "core/types.hpp" #include "game/entities/bullet.hpp" #include "game/entities/bullet_config.hpp" #include "game/entities/enemy_config.hpp" namespace Systems::EnemyEvents { namespace { constexpr uint8_t NO_SHOOTER = 0xFF; void doAddScore(Systems::Collision::Context& ctx, const Enemy& enemy, uint8_t shooter) { const int POINTS = enemy.getConfig().score; if (shooter != NO_SHOOTER) { ctx.score_per_player[shooter] += POINTS; } ctx.floating_score_manager.crear(POINTS, enemy.getCenter()); } void doCreateDebris(Systems::Collision::Context& ctx, const Enemy& enemy) { constexpr float SPEED_EXPLOSIO = 80.0F; const Vec2 INHERITED_VEL = enemy.getVelocityVector() * Defaults::Physics::Debris::ENEMY_VELOCITY_INHERITANCE; ctx.debris_manager.explode( enemy.getShape(), enemy.getCenter(), 0.0F, 1.0F, SPEED_EXPLOSIO, enemy.getBrightness(), INHERITED_VEL, 0.0F, 0.0F, Defaults::Sound::EXPLOSION, enemy.getConfig().colors.normal, Defaults::Physics::Debris::ENEMY_LIFETIME, Defaults::Physics::Debris::ENEMY_FRICTION, Defaults::Physics::Debris::ENEMY_SEGMENT_MULTIPLIER); } void doCreateFireworks(Systems::Collision::Context& ctx, const Enemy& enemy) { ctx.firework_manager.spawn(enemy.getCenter(), Defaults::FX::Firework::DEFAULT_COLOR, Defaults::FX::Firework::SPEED, Defaults::FX::Firework::N_POINTS, Defaults::FX::Firework::INITIAL_BRIGHTNESS, /*glow=*/true, enemy.getConfig().colors.wounded); } void doApplyImpulse(Enemy& enemy, const Bullet* bullet) { if (bullet == nullptr) { return; } const Vec2 IMPULSE = bullet->getBody().velocity * (bullet->getBody().mass * bullet->getConfig().physics.impact_momentum_factor); enemy.applyImpulse(IMPULSE); } } // namespace void dispatchEvent(Systems::Collision::Context& ctx, Enemy& enemy, EnemyEventType event, uint8_t shooter_id, const Bullet* bullet) { const auto& actions = enemy.getConfig().events.getActions(event); for (const auto& action : actions) { switch (action.type) { case EnemyActionType::SET_HURT: if (enemy.isWounded()) { // Segon hit sobre wounded → mort immediata (regla 2-hits). dispatchEvent(ctx, enemy, EnemyEventType::ON_DESTROY, shooter_id, bullet); enemy.destroy(); } else { enemy.hurt(shooter_id); } break; case EnemyActionType::DESTROY: dispatchEvent(ctx, enemy, EnemyEventType::ON_DESTROY, shooter_id, bullet); enemy.destroy(); break; case EnemyActionType::ADD_SCORE: doAddScore(ctx, enemy, shooter_id); break; case EnemyActionType::CREATE_DEBRIS: doCreateDebris(ctx, enemy); break; case EnemyActionType::CREATE_FIREWORKS: doCreateFireworks(ctx, enemy); break; case EnemyActionType::APPLY_IMPULSE: doApplyImpulse(enemy, bullet); break; } } } } // namespace Systems::EnemyEvents