81 lines
3.2 KiB
C++
81 lines
3.2 KiB
C++
#include "StandbyExecutor.h"
|
|
|
|
#include <optional>
|
|
|
|
#include <QVector2D>
|
|
|
|
#include "BehaviorKind.h"
|
|
#include "Centroid.h"
|
|
#include "EntityAdmin.h"
|
|
#include "FactionComponent.h"
|
|
#include "HealthComponent.h"
|
|
#include "MovementIntentComponent.h"
|
|
#include "PositionComponent.h"
|
|
#include "SelectedBehaviorComponent.h"
|
|
#include "ShipIdentityComponent.h"
|
|
#include "StandbyBehavior.h"
|
|
#include "StationBodyComponent.h"
|
|
#include "tracing.h"
|
|
|
|
void StandbyExecutor::execute(EntityAdmin& admin)
|
|
{
|
|
TRACE();
|
|
|
|
// Centroid of each faction's alive ships; a standing-by ship steers toward the
|
|
// center of its other same-faction ships so it stays among potential patients.
|
|
Centroid enemyShips;
|
|
Centroid playerShips;
|
|
admin.forEach<ShipIdentityComponent, PositionComponent, FactionComponent, HealthComponent>(
|
|
[&enemyShips, &playerShips](entt::entity /*e*/, const ShipIdentityComponent& /*si*/,
|
|
const PositionComponent& pos, const FactionComponent& faction,
|
|
const HealthComponent& health)
|
|
{
|
|
if (health.hp <= 0.0f) { return; }
|
|
Centroid& centroid = faction.isEnemy ? enemyShips : playerShips;
|
|
centroid.add(pos.value);
|
|
});
|
|
|
|
// Fallback per faction: the centroid of that side's own alive 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);
|
|
});
|
|
|
|
const std::optional<QVector2D> enemyStationCenter = enemyStations.value();
|
|
const std::optional<QVector2D> playerStationCenter = playerStations.value();
|
|
|
|
admin.forEach<StandbyBehavior, SelectedBehaviorComponent, PositionComponent,
|
|
FactionComponent, MovementIntentComponent>(
|
|
[&](entt::entity /*e*/, const StandbyBehavior& /*standby*/,
|
|
const SelectedBehaviorComponent& selected, const PositionComponent& pos,
|
|
const FactionComponent& faction, MovementIntentComponent& intent)
|
|
{
|
|
if (selected.winner != BehaviorKind::Standby) { return; }
|
|
|
|
const Centroid& allyShips = faction.isEnemy ? enemyShips : playerShips;
|
|
const std::optional<QVector2D>& friendlyStationCenter =
|
|
faction.isEnemy ? enemyStationCenter : playerStationCenter;
|
|
|
|
// Aim at the centroid of the other allied ships (excluding self), then
|
|
// fall back to the friendly stations, then hold position when alone.
|
|
QVector2D target = pos.value;
|
|
if (allyShips.count > 1)
|
|
{
|
|
target = (allyShips.sum - pos.value)
|
|
/ static_cast<float>(allyShips.count - 1);
|
|
}
|
|
else if (friendlyStationCenter)
|
|
{
|
|
target = *friendlyStationCenter;
|
|
}
|
|
intent = MovementIntentComponent{true, target};
|
|
});
|
|
}
|