⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 attackgroup.cpp

📁 这是整套横扫千军3D版游戏的源码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
#include "AttackGroup.h"

#define UNIT_STUCK_MOVE_DISTANCE 2.0f
// not moving for 5 * 60 frames = stuck
#define UNIT_STUCK_COUNTER_MANEUVER_LIMIT 5
// gives it (STUCK_COUNTER_LIMIT - STUCK_COUNTER_MANEUVER_LIMIT) * 60 seconds to move (longer than UNIT_STUCK_MOVE_DISTANCE (7 sec))
#define UNIT_STUCK_COUNTER_LIMIT 15
// stuck maneuver distance should be the movement map res since threat is not really relevant when maneuvering from a stuck pos
#define UNIT_STUCK_MANEUVER_DISTANCE (THREATRES * 8)
// the max amount of difference in height there may be at the position to maneuver to (don't retreat into a hole)
#define UNIT_MAX_MANEUVER_HEIGHT_DIFFERENCE_UP 20
// minimum of offset between my maxrange and the enemys position before considering moving
#define UNIT_MIN_MANEUVER_RANGE_DELTA (THREATRES * 8)
// minimum amount to maneuver when getting to max range
#define UNIT_MIN_MANEUVER_DISTANCE (THREATRES * 4)
// second requirement, minimum percentage of my range to move when getting to max range (too stop slow long range from dancing around)
#define UNIT_MIN_MANEUVER_RANGE_PERCENTAGE 0.2f
// minimum time to maneuver (frames), used for setting maneuvercounter (in case the speed / dist formula is weird)
#define UNIT_MIN_MANEUVER_TIME 15

#define UNIT_DESTINATION_SLACK (THREATRES * 4.0f * 1.4f)
#define GROUP_DESTINATION_SLACK THREATRES * 8
#define GROUP_MEDIAN_UNIT_SELECTION_SLACK 10.0f



CR_BIND(CAttackGroup, (NULL, 0));
CR_REG_METADATA(CAttackGroup, (
	CR_MEMBER(ai),
	CR_MEMBER(units),
	CR_MEMBER(groupID),
	CR_MEMBER(isMoving),
	CR_MEMBER(pathIterator),
	CR_MEMBER(lowestAttackRange),
	CR_MEMBER(highestAttackRange),
	CR_MEMBER(isShooting),
	CR_MEMBER(movementCounterForStuckChecking),
	CR_RESERVED(16)
));



CAttackGroup::CAttackGroup() {
	this->ai = NULL;
	this->groupID = 0;
	this->pathIterator = 0;
	this->lowestAttackRange = 100000;
	this->highestAttackRange = 1;
	this->movementCounterForStuckChecking = 0;
	this->defending = false;
	this->isMoving = false;
	this->isShooting = false;
	this->attackPosition = ZEROVECTOR;
	this->attackRadius = 1;
}

CAttackGroup::CAttackGroup(AIClasses* ai, int groupID_in) {
	this->ai = ai;
	this->groupID = groupID_in;
	this->pathIterator = 0;
	this->lowestAttackRange = 100000;
	this->highestAttackRange = 1;
	this->movementCounterForStuckChecking = 0;
	this->defending = false;
	this->isMoving = false;
	this->isShooting = false;
	this->attackPosition = ZEROVECTOR;
	this->attackRadius = 1;
}

CAttackGroup::~CAttackGroup() {
}


void CAttackGroup::Log() {
}


void CAttackGroup::AddUnit(int unitID) {
	if (ai->cb->GetUnitDef(unitID)) {
		// add to my structure
		units.push_back(unitID);
		// set its group ID:
		ai->MyUnits[unitID]->groupID = this->groupID;
		// update the attack range properties of this group
		this->lowestAttackRange = min(this->lowestAttackRange, this->ai->ut->GetMaxRange(ai->cb->GetUnitDef(unitID)));
		this->highestAttackRange = max(this->highestAttackRange, this->ai->ut->GetMaxRange(ai->cb->GetUnitDef(unitID)));
	}
	else {
		bool dead_unit_added_to_group = false;
		assert(dead_unit_added_to_group);
	}
}

bool CAttackGroup::RemoveUnit(int unitID) {
	bool found = false;
	vector<int>::iterator it;

	for (it = units.begin(); it != units.end(); it++) {
		if (*it == unitID) {
			found = true;
			// L("AttackGroup: erasing unit with id:" << unitID);
			break;
		}
	}

	if (found) {
		units.erase(it);
		// L("AttackGroup: about to attempt to reset the group ID of a removed unit");
		if (ai->cb->GetUnitDef(unitID) != NULL) {
			ai->MyUnits[unitID]->groupID = 0;
			// L("AttackGroup: groupid = 0 ==> success");
			// L("AttackGroup: this unit's stuck counter was " << ai->MyUnits[unitID]->stuckCounter);
		}
	}

	assert(found);

	// update lowestAttackRange and highestAttackRange
	this->lowestAttackRange = 10000.0f;
	this->highestAttackRange = 1.0f;

	for (unsigned int i = 0; i < units.size(); i++) {
		int unitID = units[i];
		if (ai->cb->GetUnitDef(unitID) != NULL) {
			this->lowestAttackRange = min(this->lowestAttackRange, this->ai->ut->GetMaxRange(ai->cb->GetUnitDef(unitID)));
			this->highestAttackRange = max(this->highestAttackRange, this->ai->ut->GetMaxRange(ai->cb->GetUnitDef(unitID)));
		}
	}

	return found;
}



void CAttackGroup::MoveTo(float3 newPosition) {
	newPosition = newPosition;
}

int CAttackGroup::Size() {
	// LONG DEAD-UNIT TEST
	int unitCounter = 0;
	int numUnits = units.size();
	int invalid = -2;

	for (int i = 0; i < numUnits; i++) {
		int unit = units[i];

		if (ai->cb->GetUnitDef(unit) != NULL) {
			unitCounter++;
		}
		else {
			invalid = unit;
		}
	}

	if (numUnits != unitCounter) {
		// size mismatch in group
	}

	return units.size();
}


int CAttackGroup::GetGroupID() {
	return groupID;
}

int CAttackGroup::GetWorstMoveType() {
	return PATHTOUSE;
}

vector<int>* CAttackGroup::GetAllUnits() {
	return &(this->units);
}


// combined unit power of the group
float CAttackGroup::Power() {
	float sum = 0.00001f;

	for (vector<int>::iterator it = units.begin(); it != units.end(); it++) {
		if (ai->cb->GetUnitDef(*it) != NULL) {
			sum += ai->cb->GetUnitPower(*it);
		}
	}

	return sum;
}



int CAttackGroup::PopStuckUnit() {
	// removes a stuck unit from the group if there is one, and puts a marker on the map
	for (vector<int>::iterator it = units.begin(); it != units.end(); it++) {
		if (ai->MyUnits[*it]->stuckCounter > UNIT_STUCK_COUNTER_LIMIT) {
			int id = *it;
			// mark it
			char text[512];
			sprintf(text, "stuck %i: %i, dropping from group: %i. isMoving = %i", id, ai->MyUnits[*it]->stuckCounter, groupID, isMoving);
			sprintf(text, "humanName: %s", ai->MyUnits[*it]->def()->humanName.c_str());

			ai->MyUnits[*it]->stuckCounter = 0;
			units.erase(it);
			return id;
		}
	}

	return -1;
}



bool CAttackGroup::CloakedFix(int enemy) {
	const UnitDef* ud = ai->cheat->GetUnitDef(enemy);

	return ((ud != NULL) && !(ud->canCloak && ud->startCloaked && (ai->cb->GetUnitPos(enemy) == ZEROVECTOR)));
}



float3 CAttackGroup::GetGroupPos() {
	// what's the group's position (for distance checking when selecting targets)
	int unitCounter = 0;
	float3 groupPosition = float3(0, 0, 0);
	int numUnits = units.size();

	for (int i = 0; i < numUnits; i++) {
		int unit = units[i];

		if (ai->cb->GetUnitDef(unit) != NULL) {
			unitCounter++;
			groupPosition += ai->cb->GetUnitPos(unit);
		}
	}

	if (unitCounter > 0) {
		groupPosition /= unitCounter;
		// find the unit closest to the center (since the actual center might be on a hill or something)
		float closestSoFar = FLT_MAX;
		int closestUnitID = -1;
		float temp;
		int unit;

		for (int i = 0; i < numUnits; i++) {
			unit = units[i];
			// is it closer. consider also low unit counts, then the first will be used since it's < and not <= (assuming sufficient float accuracy)
			if (ai->cb->GetUnitDef(unit) != NULL && (temp = groupPosition.distance2D(ai->cb->GetUnitPos(unit))) < closestSoFar - GROUP_MEDIAN_UNIT_SELECTION_SLACK) {
				closestSoFar = temp;
				closestUnitID = unit;
			}
		}

		assert(closestUnitID != -1);
		groupPosition = ai->cb->GetUnitPos(closestUnitID);
	}
	else {
		// L("AttackGroup: empty attack group when calcing group pos!");
		return ERRORVECTOR;
	}

	return groupPosition;
}



// returns enemies in my attack area
list<int> CAttackGroup::GetAssignedEnemies() {
	list<int> takenEnemies;

	if (!defending) {
		int numTaken = ai->cheat->GetEnemyUnits(unitArray, attackPosition, attackRadius);
	
		for (int i = 0; i < numTaken; i++) {
			int takenEnemy = unitArray[i];
			takenEnemies.push_back(takenEnemy);
		}
	}

	return takenEnemies;
}

void CAttackGroup::AssignTarget(vector<float3> path, float3 position, float radius) {
	this->attackPosition = position;
	this->attackRadius = radius;
	this->pathToTarget = path;
	this->isMoving = true;
	this->isShooting = false;
	this->pathIterator = 0;
	this->defending = false;
}




// attack routine (the "find new enemy" part)
void CAttackGroup::FindDefenseTarget(float3 groupPosition, int frameNr) {
	char tx[512];
	sprintf(tx, "AG: FindDefenseTarget(), group %i, frame %i, numUnits %i",
		this->groupID, frameNr, this->units.size());

	// KLOOTNOTE: numEnemies will be zero if no enemies in LOS or radar when
	// non-cheat callback used, rely on AttackHandler to pick "global" targets
	// and on this function for "local" ones
	// int numEnemies = ai->cheat->GetEnemyUnits(unitArray);
	int numEnemies = ai->cb->GetEnemyUnitsInRadarAndLos(unitArray);


	if (numEnemies) {
		// build vector of enemies

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -