bool AttackTask::onValidate() { CGroup *group = firstGroup(); if (targetAlt >= 0) { if (ai->cbc->IsUnitCloaked(targetAlt) || !group->canAttack(targetAlt)) { group->stop(); } } const UnitDef *eud = ai->cbc->GetUnitDef(target); if (eud == NULL) return false; if (!isMoving) { if (ai->cbc->IsUnitCloaked(target)) return false; return true; } if (!group->canAttack(target)) return false; // don't chase scout groups too long if they are out of base... bool scoutGroup = (group->cats&SCOUTER).any(); if (!scoutGroup && lifeTime() > 20.0f) { const unitCategory ecats = UC(eud->id); if ((ecats&SCOUTER).any() && !ai->defensematrix->isPosInBounds(pos)) return false; } float targetDistance = pos.distance2D(group->pos()); if (targetDistance > 1000.0f) return true; // too far to panic if (ai->cbc->IsUnitCloaked(target)) return false; bool isBaseThreat = ai->defensematrix->isPosInBounds(pos); // if there is no threat to our base then prevent useless attack for groups // which are not too cheap if (!isBaseThreat && (group->costMetal / group->units.size()) >= 100.0f) { float threatRange; if (scoutGroup) threatRange = 300.0f; else threatRange = 0.0f; if (group->getThreat(pos, threatRange) > group->strength) return false; } return true; }
bool MergeTask::reelectMasterGroup() { if (groups.size() <= 1) return false; bool reelect = true; if (masterGroup && !isRetreating) { float threat = masterGroup->getThreat(pos, masterGroup->radius()); // if threat is 2x smaller than group strength then do nothing if (threat <= EPS || (masterGroup->strength / threat) > 2.0f) reelect = false; } if (reelect) { float minThreat = std::numeric_limits<float>::max(); float maxDistance = std::numeric_limits<float>::min(); CGroup *bestGroup = NULL; std::list<CGroup*>::iterator it; for (it = groups.begin(); it != groups.end(); ++it) { CGroup *g = *it; float3 gpos = g->pos(); float threat = g->getThreat(gpos, g->radius()); float distance = ai->defensematrix->distance2D(gpos); if (distance > maxDistance) maxDistance = distance; if (threat < minThreat) { bestGroup = g; minThreat = threat; isRetreating = (distance + EPS) < maxDistance; } } if (bestGroup && (masterGroup == NULL || masterGroup->key != bestGroup->key)) { masterGroup = bestGroup; pos = bestGroup->pos(true); for (it = groups.begin(); it != groups.end(); ++it) { CGroup *g = *it; ai->pathfinder->remove(*g); if (!ai->pathfinder->addGroup(*g)) return false; } } } return (masterGroup != NULL); }
float3 CEconomy::getBestSpot(CGroup& group, std::list<float3>& resources, std::map<int, float3>& tracker, bool metal) { bool staticBuilder = (group.cats&STATIC).any(); bool canBuildUnderWater = (group.cats&(SEA|SUB|AIR)).any(); bool canBuildAboveWater = (group.cats&(LAND|AIR)).any(); float bestDist = std::numeric_limits<float>::max(); float3 bestSpot = ERRORVECTOR; float3 gpos = group.pos(); float radius; if (metal) radius = ai->cb->GetExtractorRadius(); else radius = 16.0f; std::list<float3>::iterator i; std::map<int, float3>::iterator j; for (i = resources.begin(); i != resources.end(); ++i) { if (i->y < 0.0f) { if (!canBuildUnderWater) continue; } else { if (!canBuildAboveWater) continue; } bool taken = false; for (j = tracker.begin(); j != tracker.end(); ++j) { if (i->distance2D(j->second) < radius) { taken = true; break; } } if (taken) continue; // already taken or scheduled by current AI int numUnits = ai->cb->GetFriendlyUnits(&ai->unitIDs[0], *i, 1.1f * radius); for (int u = 0; u < numUnits; u++) { const int uid = ai->unitIDs[u]; const UnitDef *ud = ai->cb->GetUnitDef(uid); if (metal) taken = (UC(ud->id) & MEXTRACTOR).any(); else taken = ud->needGeo; if (taken) break; } if (taken) continue; // already taken by ally team float dist = gpos.distance2D(*i); if (staticBuilder) { if (dist > group.buildRange) continue; // spot is out of range } /* // NOTE: getPathLength() also considers static units float dist = ai->pathfinder->getPathLength(group, *i); if (dist < 0.0f) continue; // spot is out of build range or unreachable */ // TODO: actually any spot with any threat should be skipped; // to implement this effectively we need to refactor tasks, cause // builder during approaching should scan target place for threat // periodically; currently it does not, so skipping dangerous spot // has no real profit dist += 1000.0f * group.getThreat(*i, 300.0f); if (dist < bestDist) { bestDist = dist; bestSpot = *i; } } if (bestSpot != ERRORVECTOR) // TODO: improper place for this tracker[group.key] = bestSpot; return bestSpot; }