void CDefendTask::FindTarget() { CCircuitAI* circuit = manager->GetCircuit(); auto enemies = std::move(circuit->GetCallback()->GetEnemyUnitsIn(GetPosition(), radius)); if (enemies.empty()) { enemies = std::move(circuit->GetCallback()->GetEnemyUnitsIn(circuit->GetSetupManager()->GetBasePos(), radius)); if (enemies.empty()) { SetTarget(nullptr); return; } } CEnemyUnit* bestTarget = nullptr; float minSqDist = std::numeric_limits<float>::max(); for (Unit* e : enemies) { if (e == nullptr) { continue; } CEnemyUnit* enemy = circuit->GetEnemyUnit(e); if (enemy != nullptr) { float sqDist = GetPosition().SqDistance2D(enemy->GetPos()); if (minSqDist > sqDist) { minSqDist = sqDist; bestTarget = enemy; } } delete e; } SetTarget(bestTarget); }
void CAttackTask::Execute(CCircuitUnit* unit, bool isUpdating) { Unit* u = unit->GetUnit(); CCircuitAI* circuit = manager->GetCircuit(); CTerrainManager* terrainManager = circuit->GetTerrainManager(); float minSqDist; CEnemyUnit* bestTarget = FindBestTarget(unit, minSqDist); if (bestTarget == nullptr) { if (!isUpdating) { float x = rand() % (terrainManager->GetTerrainWidth() + 1); float z = rand() % (terrainManager->GetTerrainHeight() + 1); position = AIFloat3(x, circuit->GetMap()->GetElevationAt(x, z), z); } } else { position = bestTarget->GetPos(); float range = u->GetMaxRange(); if (minSqDist < range * range) { u->Attack(bestTarget->GetUnit(), UNIT_COMMAND_OPTION_INTERNAL_ORDER, circuit->GetLastFrame() + FRAMES_PER_SEC * 300); return; } } u->Fight(position, UNIT_COMMAND_OPTION_INTERNAL_ORDER, circuit->GetLastFrame() + FRAMES_PER_SEC * 300); }
void CArtilleryTask::Execute(CCircuitUnit* unit, bool isUpdating) { IUnitAction* act = static_cast<IUnitAction*>(unit->End()); if (!act->IsAny(IUnitAction::Mask::MOVE | IUnitAction::Mask::FIGHT | IUnitAction::Mask::JUMP)) { return; } ITravelAction* travelAction = static_cast<ITravelAction*>(act); CCircuitAI* circuit = manager->GetCircuit(); int frame = circuit->GetLastFrame(); const AIFloat3& pos = unit->GetPos(frame); std::shared_ptr<F3Vec> pPath = std::make_shared<F3Vec>(); CEnemyUnit* bestTarget = FindTarget(unit, pos, *pPath); if (bestTarget != nullptr) { TRY_UNIT(circuit, unit, unit->GetUnit()->Attack(bestTarget->GetUnit(), UNIT_COMMAND_OPTION_RIGHT_MOUSE_KEY, frame + FRAMES_PER_SEC * 60); unit->GetUnit()->ExecuteCustomCommand(CMD_UNIT_SET_TARGET, {(float)bestTarget->GetId()}); )
CEnemyUnit* CAttackTask::FindBestTarget(CCircuitUnit* unit, float& minSqDist) { CCircuitAI* circuit = manager->GetCircuit(); CTerrainManager* terrainManager = circuit->GetTerrainManager(); CThreatMap* threatMap = circuit->GetThreatMap(); const AIFloat3& pos = unit->GetUnit()->GetPos(); STerrainMapArea* area = unit->GetArea(); float power = threatMap->GetUnitThreat(unit); int canTargetCat = unit->GetCircuitDef()->GetTargetCategory(); CEnemyUnit* bestTarget = nullptr; minSqDist = std::numeric_limits<float>::max(); threatMap->SetThreatType(unit); const CCircuitAI::EnemyUnits& enemies = circuit->GetEnemyUnits(); for (auto& kv : enemies) { CEnemyUnit* enemy = kv.second; if (enemy->IsHidden() || (threatMap->GetThreatAt(enemy->GetPos()) >= power) || !terrainManager->CanMoveToPos(area, enemy->GetPos())) { continue; } if (((canTargetCat & circuit->GetWaterCategory()) == 0) && (enemy->GetPos().y < -SQUARE_SIZE * 4)) { continue; } CCircuitDef* edef = enemy->GetCircuitDef(); if ((edef != nullptr) && ((edef->GetCategory() & canTargetCat) == 0)) { continue; } float sqDist = pos.SqDistance2D(enemy->GetPos()); if (sqDist < minSqDist) { bestTarget = enemy; minSqDist = sqDist; } } return bestTarget; }