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 IFighterTask::OnUnitDamaged(CCircuitUnit* unit, CEnemyUnit* attacker) { CCircuitAI* circuit = manager->GetCircuit(); int frame = circuit->GetLastFrame(); CCircuitDef* cdef = unit->GetCircuitDef(); Unit* u = unit->GetUnit(); const float healthPerc = u->GetHealth() / u->GetMaxHealth(); if (unit->GetShield() != nullptr) { const float minShield = circuit->GetSetupManager()->GetEmptyShield(); if ((healthPerc > cdef->GetRetreat()) && unit->IsShieldCharged(minShield)) { if (cdef->IsRoleHeavy() && (healthPerc < 0.9f)) { circuit->GetBuilderManager()->EnqueueRepair(IBuilderTask::Priority::NOW, unit); } return; } } else if ((healthPerc > cdef->GetRetreat()) && !unit->IsDisarmed(frame)) { if (cdef->IsRoleHeavy() && (healthPerc < 0.9f)) { circuit->GetBuilderManager()->EnqueueRepair(IBuilderTask::Priority::NOW, unit); } return; } else if (healthPerc < 0.2f) { // stuck units workaround: they don't shoot and don't see distant threat CRetreatTask* task = manager->GetCircuit()->GetMilitaryManager()->EnqueueRetreat(); manager->AssignTask(unit, task); return; } CThreatMap* threatMap = circuit->GetThreatMap(); const float range = cdef->GetMaxRange(); if ((target == nullptr) || !target->IsInLOS()) { CRetreatTask* task = circuit->GetMilitaryManager()->EnqueueRetreat(); manager->AssignTask(unit, task); return; } const AIFloat3& pos = unit->GetPos(frame); if ((target->GetPos().SqDistance2D(pos) > SQUARE(range)) || (threatMap->GetThreatAt(unit, pos) * 2 > threatMap->GetUnitThreat(unit))) { CRetreatTask* task = circuit->GetMilitaryManager()->EnqueueRetreat(); manager->AssignTask(unit, task); return; } cowards.insert(unit); }