Files
dota_factory/src/lib/ecs/system/AiSystem.cpp

94 lines
3.1 KiB
C++

#include "AiSystem.h"
#include <limits>
#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 <typename Behavior>
void consider(EntityAdmin& admin, BehaviorKind kind)
{
admin.forEach<Behavior, SelectedBehaviorComponent>(
[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 BuildingSystem& buildings,
const DebrisSystem& debris)
{
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, debris);
m_deliverScrapEvaluator.evaluate(admin, buildings);
// 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, buildings);
}
void AiSystem::selectWinningBehaviors(EntityAdmin& admin)
{
TRACE();
admin.forEach<SelectedBehaviorComponent>(
[](entt::entity /*e*/, SelectedBehaviorComponent& selected)
{
selected.winner = BehaviorKind::None;
selected.bestScore = std::numeric_limits<float>::lowest();
});
// Highest priority first so ties resolve toward the more urgent behavior.
consider<RetreatBehavior>(admin, BehaviorKind::Retreat);
consider<AttackBehavior>(admin, BehaviorKind::Attack);
consider<RepairBehavior>(admin, BehaviorKind::Repair);
consider<SalvageScrapBehavior>(admin, BehaviorKind::SalvageScrap);
consider<DeliverScrapBehavior>(admin, BehaviorKind::DeliverScrap);
consider<RallyBehavior>(admin, BehaviorKind::Rally);
consider<StandbyBehavior>(admin, BehaviorKind::Standby);
consider<AdvanceBehavior>(admin, BehaviorKind::Advance);
}