92 lines
3.6 KiB
C++
92 lines
3.6 KiB
C++
#include "AdvanceExecutor.h"
|
|
|
|
#include <optional>
|
|
|
|
#include <QVector2D>
|
|
|
|
#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<StationBodyComponent, PositionComponent, FactionComponent, HealthComponent>(
|
|
[&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<HqProxyComponent, PositionComponent, FactionComponent, HealthComponent>(
|
|
[&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<QVector2D> enemyStationCenter = enemyStations.value();
|
|
const std::optional<QVector2D> playerStationCenter = playerStations.value();
|
|
const std::optional<QVector2D> enemyHqCenter = enemyHq.value();
|
|
const std::optional<QVector2D> playerHqCenter = playerHq.value();
|
|
|
|
admin.forEach<AdvanceBehavior, SelectedBehaviorComponent, PositionComponent,
|
|
FactionComponent, MovementIntentComponent>(
|
|
[&](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<QVector2D>& stationCenter =
|
|
faction.isEnemy ? playerStationCenter : enemyStationCenter;
|
|
const std::optional<QVector2D>& 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};
|
|
});
|
|
}
|