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 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); } } }
CCircuitUnit* CBRepairTask::FindUnitToAssist(CCircuitUnit* unit) { CCircuitUnit* target = nullptr; Unit* su = unit->GetUnit(); const AIFloat3& pos = su->GetPos(); float maxSpeed = su->GetMaxSpeed(); float radius = unit->GetCircuitDef()->GetBuildDistance() + maxSpeed * FRAMES_PER_SEC * 30; CCircuitAI* circuit = manager->GetCircuit(); circuit->UpdateFriendlyUnits(); auto units = std::move(circuit->GetCallback()->GetFriendlyUnitsIn(pos, radius)); for (auto u : units) { if ((u != nullptr) && u->GetHealth() < u->GetMaxHealth() && u->GetVel().Length() <= maxSpeed * 1.5f) { target = circuit->GetFriendlyUnit(u); if (target != nullptr) { break; } } } utils::free_clear(units); return target; }
void IBuilderTask::Execute(CCircuitUnit* unit) { Unit* u = unit->GetUnit(); u->ExecuteCustomCommand(CMD_PRIORITY, {static_cast<float>(priority)}); CCircuitAI* circuit = manager->GetCircuit(); if (target != nullptr) { Unit* tu = target->GetUnit(); u->Build(target->GetCircuitDef()->GetUnitDef(), tu->GetPos(), tu->GetBuildingFacing(), UNIT_COMMAND_OPTION_INTERNAL_ORDER, circuit->GetLastFrame() + FRAMES_PER_SEC * 60); return; } CTerrainManager* terrainManager = circuit->GetTerrainManager(); UnitDef* buildUDef = buildDef->GetUnitDef(); if (buildPos != -RgtVector) { if (circuit->GetMap()->IsPossibleToBuildAt(buildUDef, buildPos, facing)) { u->Build(buildUDef, buildPos, facing, UNIT_COMMAND_OPTION_INTERNAL_ORDER, circuit->GetLastFrame() + FRAMES_PER_SEC * 60); return; } else { terrainManager->RemoveBlocker(buildDef, buildPos, facing); // FIXME: If enemy blocked position then reset will have no effect // terrain->ResetBuildFrame(); } } circuit->GetThreatMap()->SetThreatType(unit); // FIXME: Replace const 999.0f with build time? if (circuit->IsAllyAware() && (cost > 999.0f)) { // circuit->UpdateFriendlyUnits(); auto friendlies = std::move(circuit->GetCallback()->GetFriendlyUnitsIn(position, cost)); for (Unit* au : friendlies) { CCircuitUnit* alu = circuit->GetFriendlyUnit(au); if (alu == nullptr) { continue; } if ((*alu->GetCircuitDef() == *buildDef) && au->IsBeingBuilt()) { const AIFloat3& pos = au->GetPos(); if (terrainManager->CanBuildAt(unit, pos)) { u->Build(buildUDef, pos, au->GetBuildingFacing(), UNIT_COMMAND_OPTION_INTERNAL_ORDER, circuit->GetLastFrame() + FRAMES_PER_SEC * 60); utils::free_clear(friendlies); return; } } } utils::free_clear(friendlies); } // Alter/randomize position AIFloat3 pos; if (isShake) { AIFloat3 offset((float)rand() / RAND_MAX - 0.5f, 0.0f, (float)rand() / RAND_MAX - 0.5f); pos = position + offset * SQUARE_SIZE * 16; } else { pos = position; } const float searchRadius = 200.0f * SQUARE_SIZE; FindBuildSite(unit, pos, searchRadius); if (buildPos != -RgtVector) { terrainManager->AddBlocker(buildDef, buildPos, facing); u->Build(buildUDef, buildPos, facing, UNIT_COMMAND_OPTION_INTERNAL_ORDER, circuit->GetLastFrame() + FRAMES_PER_SEC * 60); } else { // TODO: Select new proper BasePos, like near metal cluster. int terWidth = terrainManager->GetTerrainWidth(); int terHeight = terrainManager->GetTerrainHeight(); float x = terWidth / 4 + rand() % (int)(terWidth / 2 + 1); float z = terHeight / 4 + rand() % (int)(terHeight / 2 + 1); AIFloat3 pos(x, circuit->GetMap()->GetElevationAt(x, z), z); circuit->GetSetupManager()->SetBasePos(pos); // Fallback to Guard/Assist/Patrol manager->FallbackTask(unit); } }
void CBReclaimTask::Update() { if (!isMetal) { return; } CCircuitAI* circuit = manager->GetCircuit(); if (circuit->GetEconomyManager()->IsMetalFull()) { manager->AbortTask(this); } else if (!units.empty()) { /* * Update reclaim position */ // FIXME: Works only with 1 task per worker CCircuitUnit* unit = *units.begin(); int frame = circuit->GetLastFrame(); const AIFloat3& pos = unit->GetPos(frame); auto enemies = std::move(circuit->GetCallback()->GetEnemyUnitsIn(pos, 300.0f)); if (!enemies.empty()) { for (Unit* enemy : enemies) { if ((enemy != nullptr) && enemy->IsBeingBuilt()) { unit->GetUnit()->ReclaimUnit(enemy, UNIT_COMMAND_OPTION_INTERNAL_ORDER, frame + FRAMES_PER_SEC * 60); utils::free_clear(enemies); return; } } utils::free_clear(enemies); } auto features = std::move(circuit->GetCallback()->GetFeaturesIn(pos, 500.0f)); if (!features.empty()) { CTerrainManager* terrainManager = circuit->GetTerrainManager(); circuit->GetThreatMap()->SetThreatType(unit); AIFloat3 reclPos; float minSqDist = std::numeric_limits<float>::max(); Resource* metalRes = circuit->GetEconomyManager()->GetMetalRes(); for (Feature* feature : features) { AIFloat3 featPos = feature->GetPosition(); terrainManager->CorrectPosition(featPos); // Impulsed flying feature if (!terrainManager->CanBuildAt(unit, featPos)) { continue; } FeatureDef* featDef = feature->GetDef(); float reclaimValue = featDef->GetContainedResource(metalRes)/* * feature->GetReclaimLeft()*/; delete featDef; if (reclaimValue < 1.0f) { continue; } float sqDist = pos.SqDistance2D(featPos); if (sqDist < minSqDist) { reclPos = featPos; minSqDist = sqDist; } } if (minSqDist < std::numeric_limits<float>::max()) { const float radius = 8.0f; // unit->GetCircuitDef()->GetBuildDistance(); unit->GetUnit()->ReclaimInArea(reclPos, radius, UNIT_COMMAND_OPTION_INTERNAL_ORDER, frame + FRAMES_PER_SEC * 60); } utils::free_clear(features); } } }