#include "AdvanceExecutor.h" #include #include #include "AdvanceBehavior.h" #include "BehaviorKind.h" #include "Centroid.h" #include "EntityAdmin.h" #include "FactionComponent.h" #include "HealthComponent.h" #include "HqProxyComponent.h" #include "MovementIntentComponent.h" #include "PositionComponent.h" #include "SelectedBehaviorComponent.h" #include "StationBodyComponent.h" #include "tracing.h" void AdvanceExecutor::execute(EntityAdmin& admin) { TRACE(); // Centroid of each faction's alive defence stations. In the arena the HQ is // spawned as a station, so it is part of this centroid; in the main game the // enemy side has only its defence stations. Centroid enemyStations; Centroid playerStations; admin.forEach( [&enemyStations, &playerStations](entt::entity /*e*/, const StationBodyComponent& /*sb*/, const PositionComponent& pos, const FactionComponent& faction, const HealthComponent& health) { if (health.hp <= 0.0f) { return; } Centroid& centroid = faction.isEnemy ? enemyStations : playerStations; centroid.add(pos.value); }); // Fallback target per faction: the HQ proxy (main game only), used when a side // has lost all of its defence stations. Centroid enemyHq; Centroid playerHq; admin.forEach( [&enemyHq, &playerHq](entt::entity /*e*/, const HqProxyComponent& /*hq*/, const PositionComponent& pos, const FactionComponent& faction, const HealthComponent& health) { if (health.hp <= 0.0f) { return; } Centroid& centroid = faction.isEnemy ? enemyHq : playerHq; centroid.add(pos.value); }); const std::optional enemyStationCenter = enemyStations.value(); const std::optional playerStationCenter = playerStations.value(); const std::optional enemyHqCenter = enemyHq.value(); const std::optional playerHqCenter = playerHq.value(); admin.forEach( [&](entt::entity /*e*/, const AdvanceBehavior& /*advance*/, const SelectedBehaviorComponent& selected, const PositionComponent& pos, const FactionComponent& faction, MovementIntentComponent& intent) { if (selected.winner != BehaviorKind::Advance) { return; } // Aim at the center between the opposing side's defence stations; fall // back to the opposing HQ, then to an off-world point in the advance // direction so the ship keeps moving when no target structure exists. const std::optional& stationCenter = faction.isEnemy ? playerStationCenter : enemyStationCenter; const std::optional& hqCenter = faction.isEnemy ? playerHqCenter : enemyHqCenter; QVector2D target; if (stationCenter) { target = *stationCenter; } else if (hqCenter) { target = *hqCenter; } else { target = faction.isEnemy ? QVector2D(-10000.0f, pos.value.y()) : QVector2D(pos.value.x() + 1000.0f, pos.value.y()); } intent = MovementIntentComponent{true, target}; }); }