void CSReclaimTask::Update() { CCircuitAI* circuit = manager->GetCircuit(); if (circuit->GetEconomyManager()->IsMetalFull()) { manager->AbortTask(this); } else if ((++updCount % 4 == 0) && !units.empty()) { // Check for damaged units CBuilderManager* builderManager = circuit->GetBuilderManager(); CAllyUnit* repairTarget = nullptr; circuit->UpdateFriendlyUnits(); auto us = std::move(circuit->GetCallback()->GetFriendlyUnitsIn(position, radius * 0.9f)); for (Unit* u : us) { CAllyUnit* candUnit = circuit->GetFriendlyUnit(u); if ((candUnit == nullptr) || builderManager->IsReclaimed(candUnit)) { continue; } if (!u->IsBeingBuilt() && (u->GetHealth() < u->GetMaxHealth())) { repairTarget = candUnit; break; } } utils::free_clear(us); if (repairTarget != nullptr) { // Repair task IBuilderTask* task = circuit->GetFactoryManager()->EnqueueRepair(IBuilderTask::Priority::NORMAL, repairTarget); decltype(units) tmpUnits = units; for (CCircuitUnit* unit : tmpUnits) { manager->AssignTask(unit, task); } manager->AbortTask(this); } } }
void CRetreatTask::OnUnitIdle(CCircuitUnit* unit) { CCircuitAI* circuit = manager->GetCircuit(); int frame = circuit->GetLastFrame(); CFactoryManager* factoryManager = circuit->GetFactoryManager(); AIFloat3 haven = (repairer != nullptr) ? repairer->GetPos(frame) : factoryManager->GetClosestHaven(unit); if (haven == -RgtVector) { haven = circuit->GetSetupManager()->GetBasePos(); } if (unit->GetCircuitDef()->IsPlane()) { // force rearm/repair | CMD_FIND_PAD unit->GetUnit()->Fight(haven, UNIT_COMMAND_OPTION_RIGHT_MOUSE_KEY, frame + FRAMES_PER_SEC * 60); return; } const float maxDist = factoryManager->GetAssistDef()->GetBuildDistance(); const AIFloat3& unitPos = unit->GetPos(frame); if (unitPos.SqDistance2D(haven) > maxDist * maxDist) { // TODO: push MoveAction into unit? to avoid enemy fire unit->GetUnit()->MoveTo(haven, UNIT_COMMAND_OPTION_RIGHT_MOUSE_KEY, frame + FRAMES_PER_SEC * 1); // TODO: Add fail counter? } else { // TODO: push WaitAction into unit // unit->GetUnit()->ExecuteCustomCommand(CMD_PRIORITY, {0.0f}); AIFloat3 pos = unitPos; const float size = SQUARE_SIZE * 16; CTerrainManager* terrainManager = circuit->GetTerrainManager(); float centerX = terrainManager->GetTerrainWidth() / 2; float centerZ = terrainManager->GetTerrainHeight() / 2; pos.x += (pos.x > centerX) ? size : -size; pos.z += (pos.z > centerZ) ? size : -size; AIFloat3 oldPos = pos; terrainManager->CorrectPosition(pos); if (oldPos.SqDistance2D(pos) > SQUARE_SIZE * SQUARE_SIZE) { pos = unitPos; pos.x += (pos.x > centerX) ? -size : size; pos.z += (pos.z > centerZ) ? -size : size; } CTerrainManager::TerrainPredicate predicate = [unitPos](const AIFloat3& p) { return unitPos.SqDistance2D(p) > SQUARE(SQUARE_SIZE * 8); }; pos = terrainManager->FindBuildSite(unit->GetCircuitDef(), pos, maxDist, UNIT_COMMAND_BUILD_NO_FACING, predicate); unit->GetUnit()->PatrolTo(pos); IUnitAction* act = static_cast<IUnitAction*>(unit->End()); if (act->IsAny(IUnitAction::Mask::MOVE | IUnitAction::Mask::FIGHT)) { static_cast<ITravelAction*>(act)->SetFinished(true); } } }
void CRetreatTask::CheckRepairer(CCircuitUnit* unit) { CCircuitAI* circuit = manager->GetCircuit(); int frame = circuit->GetLastFrame(); CPathFinder* pathfinder = circuit->GetPathfinder(); AIFloat3 startPos = (*units.begin())->GetPos(frame); AIFloat3 endPos; float range; bool isRepairer = (repairer != nullptr); if (isRepairer) { endPos = repairer->GetPos(frame); range = pathfinder->GetSquareSize(); } else { CFactoryManager* factoryManager = circuit->GetFactoryManager(); endPos = factoryManager->GetClosestHaven(unit); if (endPos == -RgtVector) { endPos = circuit->GetSetupManager()->GetBasePos(); } range = factoryManager->GetAssistDef()->GetBuildDistance() * 0.6f + pathfinder->GetSquareSize(); } circuit->GetTerrainManager()->CorrectPosition(startPos); pathfinder->SetMapData(unit, circuit->GetThreatMap(), frame); float prevCost = pathfinder->PathCost(startPos, endPos, range); if (isRepairer && repairer->GetCircuitDef()->IsMobile()) { prevCost /= 4; } endPos = unit->GetPos(frame); float nextCost = pathfinder->PathCost(startPos, endPos, range); if (unit->GetCircuitDef()->IsMobile()) { nextCost /= 4; } if (prevCost > nextCost) { SetRepairer(unit); } }
void CRetreatTask::Execute(CCircuitUnit* unit) { IUnitAction* act = static_cast<IUnitAction*>(unit->End()); if (!act->IsAny(IUnitAction::Mask::MOVE | IUnitAction::Mask::FIGHT)) { return; } ITravelAction* travelAction = static_cast<ITravelAction*>(act); CCircuitAI* circuit = manager->GetCircuit(); int frame = circuit->GetLastFrame(); CPathFinder* pathfinder = circuit->GetPathfinder(); AIFloat3 startPos = unit->GetPos(frame); AIFloat3 endPos; float range; if (repairer != nullptr) { endPos = repairer->GetPos(frame); range = pathfinder->GetSquareSize(); } else { CFactoryManager* factoryManager = circuit->GetFactoryManager(); endPos = factoryManager->GetClosestHaven(unit); if (endPos == -RgtVector) { endPos = circuit->GetSetupManager()->GetBasePos(); } range = factoryManager->GetAssistDef()->GetBuildDistance() * 0.6f + pathfinder->GetSquareSize(); } std::shared_ptr<F3Vec> pPath = std::make_shared<F3Vec>(); pathfinder->SetMapData(unit, circuit->GetThreatMap(), frame); pathfinder->MakePath(*pPath, startPos, endPos, range); if (pPath->empty()) { pPath->push_back(endPos); } travelAction->SetPath(pPath); unit->Update(circuit); }