Example #1
0
bool CUnitHandler::FactoryBuilderAdd(BuilderTracker* builderTracker) {
	assert(builderTracker->buildTaskId == 0);
	assert(builderTracker->taskPlanId == 0);
	assert(builderTracker->factoryId == 0);

	for (std::list<Factory>::iterator i = Factories.begin(); i != Factories.end(); i++) {
		CUNIT* u = ai->GetUnit(i->id);

		// don't assist hubs (or factories that cannot be assisted)
		if ((u->def())->canBeAssisted && !u->isHub()) {
			float totalBuilderCost = 0.0f;

			// HACK: get the sum of the heuristic costs of every
			// builder that is already assisting this factory
			for (std::list<int>::iterator j = i->supportbuilders.begin(); j != i->supportbuilders.end(); j++) {
				if ((ai->GetUnit(*j)->def())->isCommander) {
					continue;
				}

				totalBuilderCost += ai->math->GetUnitCost(*j);
			}

			// if this sum is less than the heuristic cost of the
			// factory itself, add the builder to this factory
			//
			// this is based purely on the metal and energy costs
			// of all involved parties, and silently expects that
			// building _another_ factory would always be better
			// than assisting it further
			if (totalBuilderCost < (ai->math->GetUnitCost(i->id) * BUILDERFACTORYCOSTRATIO * 2.5f)) {
				builderTracker->factoryId = i->id;
				i->supportbuilders.push_back(builderTracker->builderID);
				i->supportBuilderTrackers.push_back(builderTracker);
				ai->GetUnit(builderTracker->builderID)->Guard(i->id);
				return true;
			}
		}
	}

	return false;
}
Example #2
0
bool CUnitHandler::FactoryBuilderAdd(int builderID) {
	CUNIT* unit = ai->GetUnit(builderID);
	BuilderTracker* builderTracker = GetBuilderTracker(builderID);
	return ((unit->def()->canAssist) && FactoryBuilderAdd(builderTracker));
}
bool CAttackHandler::UnitReadyFilter(int unit) {
	CUNIT u = *ai->MyUnits[unit];
	bool result = u.def() != NULL && !ai->cb->UnitBeingBuilt(unit) && ai->cb->GetUnitHealth(unit) > ai->cb->GetUnitMaxHealth(unit)*0.8f;
	return result;
}
bool CAttackHandler::UnitGroundAttackFilter(int unit) {
	CUNIT u = *ai->MyUnits[unit];
	bool result = u.def() != NULL && u.def()->canmove && u.category() == CAT_G_ATTACK;
	return result;
}
void CAttackHandler::UpdateKMeans() {
	const int arrowDuration = 300;
	{//want local variable definitions
		//get positions of all friendly units and put them in a vector (completed buildings only)
		int numFriendlies = 0;
		vector<float3> friendlyPositions;
		int friendlies[MAXUNITS];
		numFriendlies = ai->cb->GetFriendlyUnits(friendlies);
		for (int i = 0; i < numFriendlies; i++) {
			int unit = friendlies[i];
			CUNIT* u = ai->MyUnits[unit];
			//its a building, it has hp, and its mine (0)
			if (this->UnitBuildingFilter(u->def()) && this->UnitReadyFilter(unit) && u->owner() == 0) {
				friendlyPositions.push_back(u->pos());
			}
		}
		//hack to make it at least 1 unit, should only happen when you have no base:
		if (friendlyPositions.size() < 1) {
			//it has to be a proper position, unless there are no proper positions.
			if (numFriendlies > 0 && ai->cb->GetUnitDef(friendlies[0]) && ai->MyUnits[friendlies[0]]->owner() == 0) friendlyPositions.push_back(ai->cb->GetUnitPos(friendlies[0]));
			else friendlyPositions.push_back(float3(RANDINT % (ai->cb->GetMapWidth()*8), 1000, RANDINT % (ai->cb->GetMapHeight()*8))); //when everything is dead
		}
		//calculate a new K. change the formula to adjust max K, needs to be 1 minimum.
		this->kMeansK = int(min((float)(KMEANS_BASE_MAX_K), 1.0f + sqrtf((float)numFriendlies+0.01f)));
		//iterate k-means algo over these positions and move the means
		this->kMeansBase = KMeansIteration(this->kMeansBase, friendlyPositions, this->kMeansK);
		//now, draw these means on the map
		int lineWidth = 25;
		int lineWidth2 = 3;
//		for (int i = 0; i < kMeansK; i++) {
//			//ai->cb->CreateLineFigure(kMeansBase[i]+float3(0,400,0), kMeansBase[i], lineWidth, 1, arrowDuration, RANDINT % 59549847);
//		}
	}
	
	//update enemy position k-means
	//get positions of all enemy units and put them in a vector (completed buildings only)
	int numEnemies = 0;
	vector<float3> enemyPositions;
	int enemies[MAXUNITS];
	numEnemies = ai->cheat->GetEnemyUnits(enemies);
	for (int i = 0; i < numEnemies; i++) {
		const UnitDef *ud = ai->cheat->GetUnitDef(enemies[i]);
		if (this->UnitBuildingFilter(ud)) { // && this->UnitReadyFilter(unit)) {
			enemyPositions.push_back(ai->cheat->GetUnitPos(enemies[i]));
//			//L("AttackHandler debug: added enemy building position for k-means " << i);
		}
	}
	//hack to make it at least 1 unit, should only happen when you have no base:
	if (enemyPositions.size() < 1) {
		//it has to be a proper position, unless there are no proper positions.
		if (numEnemies > 0 && ai->cheat->GetUnitDef(enemies[0])) enemyPositions.push_back(ai->cheat->GetUnitPos(enemies[0]));
		else enemyPositions.push_back(float3(RANDINT % (ai->cb->GetMapWidth()*8), 1000, RANDINT % (ai->cb->GetMapHeight()*8))); //when everything is dead
	}
	//calculate a new K. change the formula to adjust max K, needs to be 1 minimum.
	this->kMeansEnemyK = int(min(float(KMEANS_ENEMY_MAX_K), 1.0f + sqrtf((float)numEnemies+0.01f)));
//		//L("AttackHandler: doing k-means k:" << kMeansK << " numPositions=" << numFriendlies);
	//iterate k-means algo over these positions and move the means
	this->kMeansEnemyBase = KMeansIteration(this->kMeansEnemyBase, enemyPositions, this->kMeansEnemyK);
	//now, draw these means on the map
	int lineWidth = 25;
//	for (int i = 0; i < kMeansEnemyK; i++) {
//		//L("AttackHandler debug: painting k-means for enemy nr " << i);
//		//ai->cb->CreateLineFigure(kMeansEnemyBase[i]+float3(300,300,0), kMeansEnemyBase[i], lineWidth, 1, arrowDuration, (RANDINT % 49584985));
//	}

	//base k-means and enemy base k-means are updated.	
	//approach: add up (max - distance) to enemies
	vector<float> proximity;
	proximity.resize(kMeansK, 0.0000001f);
	const float mapDiagonal = sqrt(pow((float)ai->cb->GetMapHeight()*8,2) + pow((float)ai->cb->GetMapWidth()*8,2) + 1.0f);

	for (int f = 0; f < kMeansK; f++) {
		for (int e = 0; e < kMeansEnemyK; e++) {
			proximity[f] += mapDiagonal - kMeansBase[f].distance2D(kMeansEnemyBase[e]);
		}
	}

	//sort kMeans by the proximity score
	float3 tempPos;
	float temp;
	for (int i = 1; i < kMeansK; i++) { //how many are completed
		for (int j = 0; j < i; j++) { //compare to / switch with
			if (proximity[i] > proximity[j]) { //switch
				tempPos = kMeansBase[i];
				kMeansBase[i] = kMeansBase[j];
				kMeansBase[j] = tempPos;
				temp = proximity[i];
				proximity[i] = proximity[j];
				proximity[j] = temp;
			}
		}
	}
	//okay, so now we have a kMeans list sorted by distance to enemies, 0 being risky and k being safest.

	//now, draw these means on the map
	for (int i = 1; i < kMeansK; i++) {
		//ai->cb->CreateLineFigure(kMeansBase[i-1]+float3(0,100,0), kMeansBase[i]+float3(0,100,0), lineWidth, 1, arrowDuration, (RANDINT % 59549847));
	}
}
Example #6
0
void CAttackGroup::AttackEnemy(int enemySelected, int numUnits, float range, int frameSpread) {
	const float3& enemyPos = ai->ccb->GetUnitPos(ai->unitIDs[enemySelected]);

	assert(CloakedFix(ai->unitIDs[enemySelected]));
	isShooting = true;

	assert(numUnits >= 0);

	for (unsigned int i = 0; i < (unsigned int)numUnits; i++) {
		CUNIT* unit = ai->GetUnit(units[i]);
		const UnitDef* udef = ai->cb->GetUnitDef(unit->uid);

		if (udef == NULL || unit->maneuverCounter-- > 0) {
			// our unit does not exist (?) or is it currently maneuvering
			continue;
		}

		// TODO: add a routine finding best (not just closest) target
		// TODO: in some cases, force-fire on position
		// TODO: add canAttack
		unit->Attack(ai->unitIDs[enemySelected]);

		// TODO: this should be the max-range of the lowest-ranged weapon
		// the unit has assuming you want to rush in with the heavy stuff
		assert(range >= ai->cb->GetUnitMaxRange(unit->uid));

		// SINGLE UNIT MANEUVERING: testing the possibility of retreating to max
		// range if target is too close, EXCEPT FOR FLAMETHROWER-EQUIPPED units
		float3 myPos = ai->cb->GetUnitPos(unit->uid);

		const float maxRange = ai->ut->GetMaxRange(udef);
		const float losDiff = (maxRange - udef->losRadius);
	//	const float myRange = (losDiff > 0.0f)? (maxRange + udef->losRadius) * 0.5f: maxRange;
		const float myRange = (losDiff > 0.0f)? maxRange * 0.75f: maxRange;

		const bool b6 = (myPos.y < (ai->cb->GetElevation(myPos.x, myPos.z) + 25.0f));
		const bool b7 = (myRange - UNIT_MIN_MANEUVER_RANGE_DELTA) > myPos.distance2D(enemyPos);

		if (!udef->canfly || (b6 && b7)) {
			std::vector<float3> tempPath;

			// note 1: we don't need a path, just a position
			// note 2: should avoid other immediate friendly units and/or immediate enemy units + radius
			// maybe include the height parameter in the search? probably not possible
			// doesn't this mean pathing might happen every second? outer limit should harsher than inner
			const float3 unitPos = ai->ccb->GetUnitPos(ai->unitIDs[enemySelected]);


			//!! TODO:
			//!!     for deterministic reproduction, should be able to
			//!!     set the random seed for the RNG's to a fixed value
			ai->pather->FindBestPathToRadius(tempPath, myPos, myRange, unitPos);

			if (!tempPath.empty()) {
				const float3& moveHere = tempPath.back();
				const float dist = myPos.distance2D(moveHere);

				// TODO: Penetrators are now broken
				// is the position between the proposed destination and the
				// enemy higher than the average of mine and his height?
				const float v1 = ((moveHere.y + enemyPos.y) * 0.5f) + UNIT_MAX_MANEUVER_HEIGHT_DIFFERENCE_UP;
				const float v2 = ai->cb->GetElevation((moveHere.x + enemyPos.x) * 0.5f, (moveHere.z + enemyPos.z) * 0.5f);

				if (v1 <= v2) {
					// nope
					continue;
				}

				const float a = float(UNIT_MIN_MANEUVER_TIME) / frameSpread;
				const float b = (dist / unit->def()->speed);
				const float c = ceilf(std::max(a, b));

				// assume the pathfinder returns correct Y values
				// REMEMBER that this will suck for planes
				if (dist > std::max((UNIT_MIN_MANEUVER_RANGE_PERCENTAGE * myRange), float(UNIT_MIN_MANEUVER_DISTANCE))) {
					unit->maneuverCounter = int(c);
					unit->Move(moveHere);
				}
			}
		}
	}
}