Esempio n. 1
0
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;
}
Esempio n. 2
0
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);
}
Esempio n. 3
0
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;
}