allow one target per repair tool module
This commit is contained in:
@@ -29,6 +29,43 @@
|
||||
#include "StationBodyComponent.h"
|
||||
#include "ThreatResponseBehaviorComponent.h"
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Shared helpers for repair targeting
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
struct RepairableInfo
|
||||
{
|
||||
entt::entity entity;
|
||||
QVector2D position;
|
||||
bool isEnemy;
|
||||
bool isShip;
|
||||
float hp;
|
||||
float maxHp;
|
||||
};
|
||||
|
||||
static std::vector<RepairableInfo> buildRepairables(EntityAdmin& admin)
|
||||
{
|
||||
std::vector<RepairableInfo> repairables;
|
||||
|
||||
admin.forEach<ShipIdentityComponent, PositionComponent, FactionComponent, HealthComponent>(
|
||||
[&repairables](entt::entity e, const ShipIdentityComponent& /*si*/,
|
||||
const PositionComponent& pos, const FactionComponent& f,
|
||||
const HealthComponent& h)
|
||||
{
|
||||
repairables.push_back({e, pos.value, f.isEnemy, true, h.hp, h.maxHp});
|
||||
});
|
||||
|
||||
admin.forEach<StationBodyComponent, PositionComponent, FactionComponent, HealthComponent>(
|
||||
[&repairables](entt::entity e, const StationBodyComponent& /*sb*/,
|
||||
const PositionComponent& pos, const FactionComponent& f,
|
||||
const HealthComponent& h)
|
||||
{
|
||||
repairables.push_back({e, pos.value, f.isEnemy, false, h.hp, h.maxHp});
|
||||
});
|
||||
|
||||
return repairables;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// tickHomeReturnBehavior (priority 4)
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -182,33 +219,7 @@ void AiSystem::tickThreatResponseBehavior(EntityAdmin& admin, const BuildingSyst
|
||||
|
||||
void AiSystem::tickRepairBehavior(EntityAdmin& admin, BuildingSystem& buildings)
|
||||
{
|
||||
// Snapshot all entities with health for repair targeting.
|
||||
struct RepairableInfo
|
||||
{
|
||||
entt::entity entity;
|
||||
QVector2D position;
|
||||
bool isEnemy;
|
||||
bool isShip;
|
||||
float hp;
|
||||
float maxHp;
|
||||
};
|
||||
std::vector<RepairableInfo> repairables;
|
||||
|
||||
admin.forEach<ShipIdentityComponent, PositionComponent, FactionComponent, HealthComponent>(
|
||||
[&repairables](entt::entity e, const ShipIdentityComponent& /*si*/,
|
||||
const PositionComponent& pos, const FactionComponent& f,
|
||||
const HealthComponent& h)
|
||||
{
|
||||
repairables.push_back({e, pos.value, f.isEnemy, true, h.hp, h.maxHp});
|
||||
});
|
||||
|
||||
admin.forEach<StationBodyComponent, PositionComponent, FactionComponent, HealthComponent>(
|
||||
[&repairables](entt::entity e, const StationBodyComponent& /*sb*/,
|
||||
const PositionComponent& pos, const FactionComponent& f,
|
||||
const HealthComponent& h)
|
||||
{
|
||||
repairables.push_back({e, pos.value, f.isEnemy, false, h.hp, h.maxHp});
|
||||
});
|
||||
std::vector<RepairableInfo> repairables = buildRepairables(admin);
|
||||
|
||||
// Snapshot enemy ships for threat detection.
|
||||
struct EnemyInfo
|
||||
@@ -232,8 +243,6 @@ void AiSystem::tickRepairBehavior(EntityAdmin& admin, BuildingSystem& buildings)
|
||||
PositionComponent& pos, FactionComponent& /*faction*/,
|
||||
SensorRangeComponent& sensor, MovementIntentComponent& intent)
|
||||
{
|
||||
const float repairRange = rb.maxRepairRange;
|
||||
|
||||
// Flee if enemy nearby.
|
||||
bool enemyNearby = false;
|
||||
for (const EnemyInfo& enemy : enemies)
|
||||
@@ -318,23 +327,57 @@ void AiSystem::tickRepairBehavior(EntityAdmin& admin, BuildingSystem& buildings)
|
||||
|
||||
void AiSystem::tickRepairTools(EntityAdmin& admin)
|
||||
{
|
||||
const std::vector<RepairableInfo> repairables = buildRepairables(admin);
|
||||
|
||||
admin.forEach<RepairToolComponent, ModuleOwnerComponent>(
|
||||
[&](entt::entity /*e*/, RepairToolComponent& rt, const ModuleOwnerComponent& owner)
|
||||
{
|
||||
if (!admin.hasAll<RepairBehaviorComponent>(owner.owner)) { return; }
|
||||
|
||||
const RepairBehaviorComponent& rb =
|
||||
admin.get<RepairBehaviorComponent>(owner.owner);
|
||||
if (!rb.currentTarget) { return; }
|
||||
const PositionComponent& ownerPos =
|
||||
admin.get<PositionComponent>(owner.owner);
|
||||
|
||||
const entt::entity target = *rb.currentTarget;
|
||||
if (!admin.isValid(target) || !admin.hasAll<HealthComponent>(target)) { return; }
|
||||
// Try the ship's preferred nav target first.
|
||||
if (rb.currentTarget)
|
||||
{
|
||||
const entt::entity preferred = *rb.currentTarget;
|
||||
if (admin.isValid(preferred) && admin.hasAll<HealthComponent>(preferred)
|
||||
&& admin.hasAll<PositionComponent>(preferred))
|
||||
{
|
||||
HealthComponent& th = admin.get<HealthComponent>(preferred);
|
||||
const float dist =
|
||||
(admin.get<PositionComponent>(preferred).value
|
||||
- ownerPos.value).length();
|
||||
if (th.hp > 0.0f && th.hp < th.maxHp && dist <= rt.range)
|
||||
{
|
||||
rt.currentTarget = rb.currentTarget;
|
||||
th.hp = std::min(th.hp + rt.ratePerTick, th.maxHp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const PositionComponent& ownerPos = admin.get<PositionComponent>(owner.owner);
|
||||
const PositionComponent& targetPos = admin.get<PositionComponent>(target);
|
||||
const float dist = (targetPos.value - ownerPos.value).length();
|
||||
if (dist > rt.range) { return; }
|
||||
// Preferred target unavailable; scan for nearest damaged friendly in range.
|
||||
rt.currentTarget = std::nullopt;
|
||||
float bestDist = rt.range;
|
||||
for (const RepairableInfo& r : repairables)
|
||||
{
|
||||
if (r.isEnemy) { continue; }
|
||||
if (r.hp <= 0.0f || r.hp >= r.maxHp) { continue; }
|
||||
const float dist = (r.position - ownerPos.value).length();
|
||||
if (dist < bestDist)
|
||||
{
|
||||
bestDist = dist;
|
||||
rt.currentTarget = r.entity;
|
||||
}
|
||||
}
|
||||
|
||||
HealthComponent& targetHealth = admin.get<HealthComponent>(target);
|
||||
if (!rt.currentTarget) { return; }
|
||||
|
||||
HealthComponent& targetHealth =
|
||||
admin.get<HealthComponent>(*rt.currentTarget);
|
||||
targetHealth.hp = std::min(targetHealth.hp + rt.ratePerTick, targetHealth.maxHp);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user