void CAttackHandler::UpdateAir() {
	if (airUnits.size() == 0) return;
	/*
	if enemy is dead, attacking = false
	every blue moon, do an air raid on most valuable thingy
	*/
	assert(!(airIsAttacking && airTarget == -1));
	if (airIsAttacking &&  (airUnits.size() == 0 || ai->cheat->GetUnitDef(airTarget) == NULL)) {
		airTarget = -1;
		airIsAttacking = false;
	}
	if (ai->cb->GetCurrentFrame() % (60*30*5) == 0  //5 mins
			|| (ai->cb->GetCurrentFrame() % (30*30) == 0 && airUnits.size() > 8)) { //30 secs && 8+ units
		//L("AH: trying to attack with air units.");
		int numOfEnemies = ai->cheat->GetEnemyUnits(unitArray);
		int bestID = -1;
		float bestFound = -1.0;
		for (int i = 0; i < numOfEnemies; i++) {
			int enemy = unitArray[i];
			if (enemy != -1 && ai->cheat->GetUnitDef(enemy) != NULL && ai->cheat->GetUnitDef(enemy)->metalCost > bestFound) {
				bestID = enemy;
				bestFound = ai->cheat->GetUnitDef(enemy)->metalCost;
			}
		}
		//L("AH: selected the enemy: " << bestID);
		if (bestID != -1 && ai->cheat->GetUnitDef(bestID)) {
			//give the order
			for (list<int>::iterator it = airUnits.begin(); it != airUnits.end(); it++) {
				CUNIT* u = ai->MyUnits[*it];
				u->Attack(bestID);
			}
			airIsAttacking = true;
			airTarget = bestID;
			ai->cb->SendTextMsg("AH: air group is attacking", 0);
		}
	}

	//TODO: units currently being built. (while the others are off attacking)

	if (ai->cb->GetCurrentFrame() % 1800 == 0) {
		airPatrolOrdersGiven = false;
	}

	if (!airPatrolOrdersGiven && !airIsAttacking) {
		//L("AH: updating air patrol routes");
//		assert(false);
		//get / make up some outer base perimeter points
		vector<float3> outerMeans;
		const int num = 3;
		outerMeans.reserve(num);
		if (kMeansK > 1) {
			int counter = 0;
			counter += kMeansK / 8; //offsetting the outermost one
			for (int i = 0; i < num; i++) {
				outerMeans.push_back(kMeansBase[counter]);
				if (counter < kMeansK-1) counter++;
			}
		} else {
			//theres just 1 kmeans and we need three
			for (int i = 0; i < num; i++) {
				outerMeans.push_back(kMeansBase[0] + float3(250*i, 0, 0));
			}
		}
		assert(outerMeans.size() == num);
		//give the patrol orders to the outer means
		for (list<int>::iterator it = airUnits.begin(); it != airUnits.end(); it++) {
			CUNIT* u = ai->MyUnits[*it];
			u->Move(outerMeans[0] + float3(0,50,0)); //do this first in case theyre in the enemy base
			for (int i = 0; i < num; i++) {
				u->PatrolShift(outerMeans[i]);
			}
		}
		airPatrolOrdersGiven = true;
	}
}
Exemplo n.º 2
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);
				}
			}
		}
	}
}