#include "AiSystem.h" #include "FactoryQueries.h" #include #include "GameConfig.h" #include "AdvanceBehavior.h" #include "AttackBehavior.h" #include "BehaviorKind.h" #include "DeliverScrapBehavior.h" #include "EntityAdmin.h" #include "RallyBehavior.h" #include "RepairBehavior.h" #include "RetreatBehavior.h" #include "SalvageScrapBehavior.h" #include "SelectedBehaviorComponent.h" #include "StandbyBehavior.h" #include "tracing.h" namespace { // Records a behavior's score for its owning ship, keeping the highest seen. // Considered high-priority first, so strict '>' breaks ties toward priority. template void consider(EntityAdmin& admin, BehaviorKind kind) { admin.forEach( [kind](entt::entity /*e*/, const Behavior& behavior, SelectedBehaviorComponent& selected) { if (behavior.score > selected.bestScore) { selected.bestScore = behavior.score; selected.winner = kind; } }); } } AiSystem::AiSystem(const GameConfig& config) : m_attackEvaluator(config.world.targeting) { } void AiSystem::tick(EntityAdmin& admin, const FactoryState& state) { TRACE(); // Phase 1: evaluators score behaviors and set their target data. m_advanceEvaluator.evaluate(admin); m_standbyEvaluator.evaluate(admin); m_rallyEvaluator.evaluate(admin); m_retreatEvaluator.evaluate(admin); m_attackEvaluator.evaluate(admin); m_repairEvaluator.evaluate(admin); m_salvageScrapEvaluator.evaluate(admin); m_deliverScrapEvaluator.evaluate(admin, state); // Phase 2: pick the highest-scoring behavior per ship. selectWinningBehaviors(admin); // Phase 3: executors run for the winning behavior. m_advanceExecutor.execute(admin); m_standbyExecutor.execute(admin); m_rallyExecutor.execute(admin); m_retreatExecutor.execute(admin); m_attackExecutor.execute(admin); m_repairExecutor.execute(admin); m_salvageScrapExecutor.execute(admin); m_deliverScrapExecutor.execute(admin, state); } void AiSystem::selectWinningBehaviors(EntityAdmin& admin) { TRACE(); admin.forEach( [](entt::entity /*e*/, SelectedBehaviorComponent& selected) { selected.winner = BehaviorKind::None; selected.bestScore = std::numeric_limits::lowest(); }); // Highest priority first so ties resolve toward the more urgent behavior. consider(admin, BehaviorKind::Retreat); consider(admin, BehaviorKind::Attack); consider(admin, BehaviorKind::Repair); consider(admin, BehaviorKind::SalvageScrap); consider(admin, BehaviorKind::DeliverScrap); consider(admin, BehaviorKind::Rally); consider(admin, BehaviorKind::Standby); consider(admin, BehaviorKind::Advance); }