Example #1
0
/*
// Callback Clone Functions
const int SQUARE_SIZE = 8;
#include <algorithm>
// Stolen directly from ALCallback.cpp
struct SearchOffset {
	int dx,dy;
	int qdist; // dx*dx+dy*dy
};
// Stolen directly from ALCallback.cpp
bool SearchOffsetComparator (const SearchOffset& a, const SearchOffset& b)
{	return a.qdist < b.qdist;	}
// Stolen directly from ALCallback.cpp
const vector<SearchOffset>& GetSearchOffsetTable (int radius)
{	static vector <SearchOffset> searchOffsets;
	int size = radius*radius*4;
	if (size > searchOffsets.size()) {
		searchOffsets.resize (size);
		for (int y=0;y<radius*2;y++)
			for (int x=0;x<radius*2;x++)
			{	SearchOffset& i = searchOffsets[y*radius*2+x];
				i.dx = x-radius;
				i.dy = y-radius;
				i.qdist = i.dx*i.dx+i.dy*i.dy;
			}
		sort (searchOffsets.begin(), searchOffsets.end(), SearchOffsetComparator);
	}
	return searchOffsets;
}
float3 cBuilderPlacement::ClosestBuildSite(const UnitDef* ud, float3 p, float sRadius, int facing)
{
	if (!ud) return float3(-1.0f,0.0f,0.0f);
	int endr = (int)(sRadius/(SQUARE_SIZE*2));
	const vector<SearchOffset>& ofs = GetSearchOffsetTable (endr);
	for(int so=0;so<endr*endr*4;so++)
	{
		float x = p.x+ofs[so].dx*SQUARE_SIZE*2;
		float z = p.z+ofs[so].dy*SQUARE_SIZE*2;
		if( cb->CanBuildAt(ud,float3(x,0,z),facing) )
		{
			return float3(x,0,z);
		}
	}
	return float3(-1.0f,0.0f,0.0f);
}
*/
bool cBuilderPlacement::FindWeaponPlacement(UnitInfo *U, float3& position)
{
	if( U->BuildQ->creationUD->WeaponGuardRange == 0 )
		return false;

	if( U->BuildQ->creationUD->ud->minWaterDepth < 0 && U->BuildQ->creationUD->WeaponSeaEff.BestRange > 0 )
	{
		int iS = G->TM->GetSectorIndex(position);
		if( !G->TM->sector[iS].isWater )
			position = G->TM->GetClosestSector(G->TM->waterSectorType,iS)->position;
		return true;
	}

	int BID = -1;
	float3 buildPosition;
	for(map<int,UnitInfo*>::iterator i=G->UImmobile.begin(); i!=G->UImmobile.end(); ++i )
	{
		buildPosition = cb->GetUnitPos(i->first);
		if( i->second->udr->WeaponGuardRange == 0 && int(i->second->UDefences.size()) == 0 &&
			CanBuildAt(U,position,buildPosition) && CanBeBuiltAt(U->BuildQ->creationUD,buildPosition,i->second->udr->WeaponGuardRange) )
			if( BID == -1 || position.distance2D(buildPosition) < position.distance2D(cb->GetUnitPos(BID)) )
				BID = i->first;
	}

	if( BID > 0 )
	{
		position = cb->GetUnitPos(BID);
		return true;
	}

	return false;
}
Example #2
0
// give move orders to units along previously generated pathToTarget
void CAttackGroup::MoveAlongPath(float3& groupPosition, int numUnits) {
	const int maxStepsAhead = 8;
	int pathMaxIndex = (int) pathToTarget.size() - 1;
	int step1 = std::min(pathIterator + maxStepsAhead / 2, pathMaxIndex);
	int step2 = std::min(pathIterator + maxStepsAhead, pathMaxIndex);

	const float3& moveToHereFirst = pathToTarget[step1];
	const float3& moveToHere = pathToTarget[step2];

	// if we aren't there yet
	if (groupPosition.distance2D(pathToTarget[pathMaxIndex]) > GROUP_DESTINATION_SLACK) {
		// TODO: give a group the order instead of each unit
		assert(numUnits >= 0);

		for (unsigned int i = 0; i < (unsigned int)numUnits; i++) {
			CUNIT* unit = ai->GetUnit(units[i]);

			if (ai->cb->GetUnitDef(unit->uid) != NULL) {
				// TODO: when they are near target, change this so they eg. line up
				// while some are here and some aren't, there's also something that
				// should be done with the units in front that are given the same
				// order+shiftorder and skittle around back and forth meanwhile if
				// the single unit isn't there yet
				if ((unit->pos()).distance2D(pathToTarget[pathMaxIndex]) > UNIT_DESTINATION_SLACK) {
					unit->Move(moveToHereFirst);

					if (moveToHere != moveToHereFirst) {
						unit->MoveShift(moveToHere);
					}
				}
			}
		}

		// if group is as close as the pathiterator-indicated target
		// is to the end of the path, increase pathIterator

		pathIterator = 0;
		float3 endOfPathPos = pathToTarget[pathMaxIndex];
		float groupDistanceToEnemy = groupPosition.distance2D(endOfPathPos);
		float pathIteratorTargetDistanceToEnemy = pathToTarget[pathIterator].distance2D(endOfPathPos);
		int increment = maxStepsAhead / 2;

		while (groupDistanceToEnemy <= pathIteratorTargetDistanceToEnemy && pathIterator < pathMaxIndex) {
			pathIterator = std::min(pathIterator + increment, pathMaxIndex);
			pathIteratorTargetDistanceToEnemy = pathToTarget[pathIterator].distance2D(endOfPathPos);
		}

		pathIterator = std::min(pathIterator, pathMaxIndex);
	}
	else {
		// group thinks it has arrived at the destination
		this->ClearTarget();
	}
}
float CAttackHandler::DistanceToBase(float3 pos) {
	float closestDistance = FLT_MAX;
	for(int i = 0; i < this->kMeansK; i++) {
		float3 mean = this->kMeansBase[i];
		float distance = pos.distance2D(mean);
		closestDistance = min(distance, closestDistance);
	}
	return closestDistance;
}
/*
Removes and return the next waypoint in the multipath corresponding to given id.
*/
float3 CPathManager::NextWaypoint(unsigned int pathId, float3 callerPos, float minDistance, int numRetries) {
	SCOPED_TIMER("AI:PFS");

	//0 indicate a no-path id.
	if(pathId == 0)
		return float3(-1,-1,-1);

	if(numRetries>4)
		return float3(-1,-1,-1);

	//Find corresponding multipath.
	std::map<unsigned int, MultiPath*>::iterator pi = pathMap.find(pathId);
	if(pi == pathMap.end())
		return float3(-1,-1,-1);
	MultiPath* multiPath = pi->second;

	if(callerPos==ZeroVector){
		if(!multiPath->detailedPath.path.empty())
			callerPos=multiPath->detailedPath.path.back();
	}

	//check if detailed path need bettering
	if(!multiPath->estimatedPath.path.empty()
	&& (multiPath->estimatedPath.path.back().distance2D(callerPos) < MIN_DETAILED_DISTANCE * SQUARE_SIZE
	|| multiPath->detailedPath.path.size() <= 2)){

		if(!multiPath->estimatedPath2.path.empty()		//if so check if estimated path also need bettering
			&& (multiPath->estimatedPath2.path.back().distance2D(callerPos) < MIN_ESTIMATE_DISTANCE * SQUARE_SIZE
			|| multiPath->estimatedPath.path.size() <= 2)){
				Estimate2ToEstimate(*multiPath, callerPos);
		}

		if(multiPath->caller)
			multiPath->caller->UnBlock();
		EstimateToDetailed(*multiPath, callerPos);
		if(multiPath->caller)
			multiPath->caller->Block();
	}

	//Repeat until a waypoint distant enought are found.
	float3 waypoint;
	do {
		//Get next waypoint.
		if(multiPath->detailedPath.path.empty()) {
			if(multiPath->estimatedPath2.path.empty() && multiPath->estimatedPath.path.empty())
				return multiPath->finalGoal;
			else
				return NextWaypoint(pathId,callerPos,minDistance,numRetries+1);
		} else {
			waypoint = multiPath->detailedPath.path.back();
			multiPath->detailedPath.path.pop_back();
		}
	} while(callerPos.distance2D(waypoint) < minDistance && waypoint != multiPath->detailedPath.pathGoal);

	return waypoint;
}
Example #5
0
void CUnitHandler::TaskPlanCreate(int builder, float3 pos, const UnitDef* builtdef) {
	UnitCategory category = ai->ut->GetCategory(builtdef);

	// HACK
	if (category >= CAT_LAST) {
		return;
	}

	// find this builder
	BuilderTracker* builderTracker = GetBuilderTracker(builder);

	// make sure this builder is free
	bool b1 = (builderTracker->taskPlanId == 0);
	bool b2 = (builderTracker->buildTaskId == 0);
	bool b3 = (builderTracker->factoryId == 0);

	if (!b1 || !b2 || !b3) {
		return;
	}


	bool existingTP = false;
	for (std::list<TaskPlan>::iterator i = TaskPlans[category].begin(); i != TaskPlans[category].end(); i++) {
		if (pos.distance2D(i->pos) < 20.0f && builtdef == i->def) {
			// make sure there are no other TaskPlans
			if (!existingTP) {
				existingTP = true;
				TaskPlanAdd(&*i, builderTracker);
			} else {
				std::stringstream msg;
					msg << "[CUnitHandler::TaskPlanCreate()][frame=" << ai->cb->GetCurrentFrame() << "]\n";
					msg << "\ttask-plan for \"" << builtdef->humanName << "\" already present";
					msg << " at position <" << pos.x << ", " << pos.y << ", " << pos.z << ">\n";
				ai->GetLogger()->Log(msg.str());
			}
		}
	}
	if (!existingTP) {
		TaskPlan tp;
		tp.pos = pos;
		tp.def = builtdef;
		tp.defName = builtdef->name;
		tp.currentBuildPower = 0;
		tp.id = taskPlanCounter++;
		TaskPlanAdd(&tp, builderTracker);

		if (category == CAT_DEFENCE)
			ai->dm->AddDefense(pos, builtdef);

		TaskPlans[category].push_back(tp);
	}
}
float3 CAttackHandler::GetClosestBaseSpot(float3 pos) {
	float closestDistance = FLT_MAX;
	int index = 0;
	for(int i = 0; i < this->kMeansK; i++) {
		float3 mean = this->kMeansBase[i];
		float distance = pos.distance2D(mean);
		if (distance < closestDistance) {
			closestDistance = distance, closestDistance;
			index = i;
		}
	}
	return kMeansBase[index];
}
Example #7
0
bool cBuilderPlacement::CanBuildAt(UnitInfo *U, const float3& position, const float3& destination)
{
	if( U->udr->immobileType != 0 ) // A hub or factory
		return position.distance2D(destination) < U->ud->buildDistance;
	if( U->area == 0 ) // A flying unit
		return true;
	int iS = G->TM->GetSectorIndex(destination);
	if( U->area->sector.find(iS) != U->area->sector.end() )
		return true;
	if( G->TM->GetClosestSector(U->area,iS)->S->position.distance2D(destination) < U->ud->buildDistance - G->TM->convertStoP )
		return true;
	return false;
}
void CUnitHandler::TaskPlanCreate(int builder, float3 pos, const UnitDef* builtdef) {
	int category = ai->ut->GetCategory(builtdef);

	// HACK
	if (category == -1)
		return;

	assert(category >= 0);
	assert(category < LASTCATEGORY);

	// find this builder
	BuilderTracker* builderTracker = GetBuilderTracker(builder);

	// make sure this builder is free
	// KLOOTNOTE: no longer use assertions
	// since new code for extractor upgrading
	// (in CBuildUp) seems to trigger them?
	bool b1 = (builderTracker->taskPlanId == 0);
	bool b2 = (builderTracker->buildTaskId == 0);
	bool b3 = (builderTracker->factoryId == 0);
	bool b4 = (builderTracker->customOrderId == 0);

	if (!b1 || !b2 || !b3 || !b4) {
		return;
	}


	bool existingtp = false;
	for (list<TaskPlan>::iterator i = TaskPlans[category].begin(); i != TaskPlans[category].end(); i++) {
		if (pos.distance2D(i->pos) < 20 && builtdef == i->def) {
			// make sure there are no other TaskPlans
			assert(!existingtp);
			existingtp = true;
			TaskPlanAdd(&*i, builderTracker);
		}
	}
	if (!existingtp) {
		TaskPlan tp;
		tp.pos = pos;
		tp.def = builtdef;
		tp.defName = builtdef->name;
		tp.currentBuildPower = 0;
		tp.id = taskPlanCounter++;
		TaskPlanAdd(&tp, builderTracker);

		if (category == CAT_DEFENCE)
			ai->dm->AddDefense(pos,builtdef);

		TaskPlans[category].push_back(tp);
	}
}
	bool CGridManager::ValidMapPos(float3 MapPos){
		bool rvalue = true;
		if (MapPos.z > MapDimensions.z){
			rvalue = false;
		}else if (MapPos.x > MapDimensions.x){
			rvalue=false;
		}else if (MapPos.z < 0){
			rvalue=false;
		}else if (MapPos.x < 0){
			rvalue=false;
		}else if (MapPos == UpVector){
			rvalue=false;
		}else if (MapPos==ZeroVector){
			rvalue=false;
		}else if(MapPos.distance2D(ZeroVector)<50){
			rvalue=false;
		}
		return rvalue;
	}
Example #10
0
	float3 CMap::distfrom(float3 Start, float3 Target, float distance){
		NLOG("CMap::distfrom");

		if(!CheckFloat3(Start)){
			return UpVector;
		}

		if(!CheckFloat3(Target)){
			return UpVector;
		}

		float p = distance/Start.distance2D(Target);
		if(p < 0) p *= -1;

		float dx = Start.x-Target.x;
		if(dx < 0) dx *= -1;

		float dz = Start.z-Target.z;
		if(dz < 0) dz *= -1;

		dz *= p;
		dx *= p;

		float x = Target.x;

		if(Start.x > Target.x){
			x += dx;
		} else{
			x -= dx;
		}

		float z = Target.z;

		if(Start.z > Target.z){
			z += dz;
		}else{
			z -= dz;
		}

		return float3(x,0,z);

	}
Example #11
0
int CAttackGroup::SelectEnemy(int numEnemies, const float3& groupPos) {
	int enemySelected = -1;
	float shortestDistanceFound = MY_FLT_MAX;
	float temp;

	for (int i = 0; i < numEnemies; i++) {
		// my range not considered in picking the closest one
		// TODO: is it air? is it cloaked?
		bool b1 = ((temp = groupPos.distance2D(ai->cheat->GetUnitPos(ai->unitIDs[i]))) < shortestDistanceFound);
		bool b2 = (ai->cheat->GetUnitDef(ai->unitIDs[i]) != NULL);
		bool b3 = CloakedFix(ai->unitIDs[i]);
		bool b4 = ai->cheat->GetUnitDef(ai->unitIDs[i])->canfly;

		if (b1 && b2 && b3 && !b4) {
			enemySelected = i;
			shortestDistanceFound = temp;
		}
	}

	return enemySelected;
}
Example #12
0
void CCoverageCell::update(std::list<CUnit*>& uncovered) {
	if (isVacant())	return;

	float newRange = ai->coverage->getCoreRange(type, unit->type);
	if (newRange < range) {
		const float3 center = getCenter();
		for (std::map<int, CUnit*>::iterator it = units.begin(); it != units.end(); ) {
			const float3 pos = it->second->pos();
			if (center.distance2D(pos) > newRange) {
				uncovered.push_back(it->second);
				it->second->unreg(*this);
				units.erase(it++);
			}
			else
				++it;
		}

		range = newRange;
	}

	// TODO: if core is mobile then update it when position has changed
}
Example #13
0
	bool CMap::CheckFloat3(float3 pos){
		NLOG("CMap::CheckFloat3");
		if(pos == UpVector){ //error codes
			return false;
		}else if(pos == ZeroVector){ //error codes
			return false;
		}else if(pos == float3(-1,0,0)){ //error codes
			return false;
		}else if(pos.distance2D(UpVector) <50){ // top corner!!!!!
			return false;
		}/*else if(pos.x > G->cb->GetMapWidth()*SQUARE_SIZE){ // offmap
			return false;
		}else if(pos.z > G->cb->GetMapHeight()*SQUARE_SIZE){ // offmap
			return false;
		}else if(pos.x < 0){ // offmap
			return false;
		}else if(pos.z < 0){ // offmap
			return false;
		}*/else{
			return true;
		}
	}
void  CUnitHandler::TaskPlanCreate(int builder, float3 pos, const UnitDef* builtdef)
{
	int category = ai->ut->GetCategory(builtdef);
	// TODO: Temp hack
	if(category == -1)
		return;
	assert(category >= 0);
	assert(category < LASTCATEGORY);
	
	// Find this builder:
	BuilderTracker * builderTracker = GetBuilderTracker(builder);
	// Make shure this builder is free:
	assert(builderTracker->buildTaskId == 0);
	assert(builderTracker->taskPlanId == 0);
	assert(builderTracker->factoryId == 0);
	assert(builderTracker->customOrderId == 0);
	
	bool existingtp = false;
	for(list<TaskPlan>::iterator i = TaskPlans[category]->begin(); i != TaskPlans[category]->end(); i++){
		if(pos.distance2D(i->pos) < 20 && builtdef == i->def){
			assert(!existingtp); // Make shure there are no other TaskPlan there
			existingtp = true;
			TaskPlanAdd(&*i, builderTracker);
		}
	}
	if(!existingtp){
		TaskPlan tp;
		tp.pos = pos;
		tp.def = builtdef;
		tp.currentBuildPower = 0;
		tp.id = taskPlanCounter++;
		TaskPlanAdd(&tp, builderTracker);
		
		if(category == CAT_DEFENCE)
				ai->dm->AddDefense(pos,builtdef);
		TaskPlans[category]->push_back(tp);
	}
}
float3 CDefenseMatrix::GetDefensePos(const UnitDef* def, float3 builderpos) {
	ai -> ut -> UpdateChokePointArray();
	int f3multiplier = 8 * THREATRES;
	int Range = int(ai -> ut -> GetMaxRange(def) / f3multiplier);
	int bestspotx = 0;
	int bestspoty = 0;
	// L("GetDefensePos: Range: " << Range);
	float averagemapsize = sqrt(float(ai -> pather -> PathMapXSize*ai -> pather -> PathMapYSize)) * f3multiplier;
	float bestscore_fast = 0;
	int bestspotx_fast = 0;
	int bestspoty_fast = 0;
	ai -> math -> TimerStart();

	spotFinder -> SetRadius(Range);
	float* sumMap = spotFinder -> GetSumMap();

	// hack to find a good start
	{
		int x = (int) (builderpos.x / f3multiplier);
		int y = (int) (builderpos.z / f3multiplier);
		float fastSumMap = sumMap[y * ai -> pather -> PathMapXSize + x];
		float3 spotpos = float3(x*f3multiplier,0,y*f3multiplier);
		float myscore = fastSumMap/(builderpos.distance2D(spotpos) + averagemapsize / 8) * ((ai -> pather -> HeightMap[y * ai -> pather -> PathMapXSize + x] + 200) / (ai -> pather -> AverageHeight + 10)) / (ai -> tm -> ThreatAtThisPoint(spotpos)+0.01);
		bestscore_fast = myscore;
		bestspotx_fast = x;
		bestspoty_fast = y;
		// L("Starting with bestscore_fast: " << bestscore_fast);
	}



	// L("ai -> pather -> PathMapXSize: " << ai -> pather -> PathMapXSize);
	// L("ai -> pather -> PathMapYSize: " << ai -> pather -> PathMapYSize);
	// L("ai -> pather -> PathMapXSize / CACHEFACTOR: " << ai -> pather -> PathMapXSize / CACHEFACTOR);
	// L("ai -> pather -> PathMapYSize / CACHEFACTOR: " << ai -> pather -> PathMapYSize / CACHEFACTOR);

	int skipCount = 0;
	int testCount = 0;
	for (int x = 0; x < ai -> pather -> PathMapXSize / CACHEFACTOR; x++) {
		for (int y = 0; y < ai -> pather -> PathMapYSize / CACHEFACTOR; y++) {
			// L("x: " << x << ", y: " << y);

			CachePoint* cachePoint = spotFinder -> GetBestCachePoint(x, y);
			float bestScoreInThisBox = cachePoint -> maxValueInBox;

			// guess that this point is as good as posible

			// make best posible build spot (nearest to builder)
			float bestX = builderpos.x / f3multiplier;
			float bestY = builderpos.z / f3multiplier;

			if (bestX > x * CACHEFACTOR) {
				if (bestX > (x * CACHEFACTOR + CACHEFACTOR)) {
					bestX = x * CACHEFACTOR + CACHEFACTOR;
				}
			}
			else {
				bestX = x * CACHEFACTOR;
			}

			if (bestY > y * CACHEFACTOR) {
				if (bestY > (y * CACHEFACTOR + CACHEFACTOR)) {
					bestY = y * CACHEFACTOR + CACHEFACTOR;
				}
			}
			else {
				bestY = y * CACHEFACTOR;
			}

			// L("bestX: " << bestX << ", bestY: " << bestY);

			float3 bestPosibleSpotpos = float3(bestX*f3multiplier,0,bestY*f3multiplier);
 			// this must be guessed, set it to the best posible (slow)
			float bestThreatAtThisPoint = 0.01 + ai -> tm -> GetAverageThreat() - 1;
			// L("bestThreatAtThisPoint: " << bestThreatAtThisPoint);
			float bestDistance = builderpos.distance2D(bestPosibleSpotpos);
			// L("bestDistance: " << bestDistance);
			// L("cachePoint -> maxValueInBox: " << cachePoint -> maxValueInBox << ", cachePoint -> x: " << cachePoint -> x << ", cachePoint -> y: " << cachePoint -> y);
			float bestHeight = ai -> pather -> HeightMap[cachePoint -> y * ai -> pather -> PathMapXSize + cachePoint -> x] + 200;
			// L("bestHeight: " << bestHeight);
			float bestPosibleMyScore = bestScoreInThisBox / (bestDistance + averagemapsize / 4) * (bestHeight + 200) / bestThreatAtThisPoint;
			// L("bestPosibleMyScore: " << bestPosibleMyScore);
			// have a best posible score for all points inside the size of the cache box
			// if this is better than the current known best, test if any point inside the box is better
			// L("bestscore_fast: " << bestscore_fast);

			if (bestPosibleMyScore > bestscore_fast) {
				testCount++;
				// must test all the points inside this box
				for (int sx = x * CACHEFACTOR; sx < ai -> pather -> PathMapXSize && sx < (x * CACHEFACTOR + CACHEFACTOR); sx++) {
					for (int sy = y * CACHEFACTOR; sy < ai -> pather -> PathMapYSize && sy < (y * CACHEFACTOR + CACHEFACTOR); sy++) {
						float fastSumMap = sumMap[sy * ai -> pather -> PathMapXSize + sx];
						float3 spotpos = float3(sx * f3multiplier, 0, sy * f3multiplier);
						float myscore = fastSumMap / (builderpos.distance2D(spotpos) + averagemapsize / 4) * (ai -> pather -> HeightMap[sy * ai -> pather -> PathMapXSize + sx]+200) / (ai -> tm -> ThreatAtThisPoint(spotpos) + 0.01);
						// L("Checking defense spot. fastSumMap: " << fastSumMap << ", Distance: " << builderpos.distance2D(spotpos) << " Height: " << ai -> pather -> HeightMap[sy * ai -> pather -> PathMapXSize + sx] << " Threat " << ai -> tm -> ThreatAtThisPoint(spotpos)<< " Score: " << myscore);
						// THIS COULD BE REALLY SLOW!
						if (myscore > bestscore_fast && BuildMaskArray[sy * ai -> pather -> PathMapXSize + sx] == 0 && ai -> cb -> CanBuildAt(def, spotpos)) {
							bestscore_fast = myscore;
							bestspotx_fast = sx;
							bestspoty_fast = sy;
							// L("new bestscore_fast: " << myscore << "sx: " << sx << ", sy: " << sy);
						}
					}
				}
			}
			else {
				// L("Skiping box");
				skipCount++;
			}
		}
	}

	// L("spotFinder new time:" << ai -> math -> TimerSecs());
	// L("skipCount: " << skipCount << ", testCount: " << testCount);
	bestspotx = bestspotx_fast;
	bestspoty = bestspoty_fast;

	return float3(bestspotx * f3multiplier, 0, bestspoty * f3multiplier);
}
float3 CDefenseMatrix::GetDefensePos(const UnitDef* def, float3 builderpos, float heightK, CCoverageHandler *ch)
{
	ai->math->StartTimer(getDefensePosTime);
	ai->ut->UpdateChokePointArray();  // TODO: UpdateChokePointArray() needs fixing.
	int f3multiplier = 8*THREATRES;
	int Range = int(ai->ut->GetMaxRange(def) / f3multiplier);

	//super hack by firenu (shouldnt happen anyway):
	if (Range <= 0) {
		L("GetDefensePos: Range was zero for a defense building: " << def->humanName);
		Range = 1;
	}


	int bestspotx = 0;
	int bestspoty = 0;
	L("GetDefensePos: Range: " << Range);
	float averagemapsize = sqrt(float(ai->pather->PathMapXSize*ai->pather->PathMapYSize)) * f3multiplier;
	/*
	ai->math->TimerStart();
	spotFinder->SetRadius(Range);
	float* sumMap = spotFinder->GetSumMap();
	for(int x = 0; x < ai->pather->PathMapXSize; x++){
		for(int y = 0; y < ai->pather->PathMapYSize; y++){
			
			float myscore = 0;
			for (int myx = x - Range; myx <= x + Range; myx++){
				if (myx >= 0 && myx < ai->pather->PathMapXSize){
					for (int myy = y - Range; myy <= y + Range; myy++){
						int distance = (x - myx)*(x - myx) + (y - myy)*(y - myy);// - 0.5;
						if (myy >= 0 && myy < ai->pather->PathMapYSize && (distance) <= squarerange){							
							myscore += Chokepointmap[myy * ai->pather->PathMapXSize + myx];
						}
					}
				}
			}
			
			// Test how large the dif is between sumMap and myscore:
			
			float fastSumMap = sumMap[y * ai->pather->PathMapXSize + x];
			float delta = fastSumMap - myscore;
			float errorSize = abs(delta /myscore);
			if(delta != 0)
				L("fastSumMap: " << fastSumMap << ", myscore: " << myscore << ", errorSize: " << errorSize << ", delta: " << delta);
			
			
			float3 spotpos = float3(x*f3multiplier,0,y*f3multiplier);		
			myscore = myscore/(builderpos.distance2D(spotpos) + averagemapsize / 4) * (ai->pather->HeightMap[y * ai->pather->PathMapXSize + x]+200) / (ai->tm->ThreatAtThisPoint(spotpos)+0.01);
			//L("Checking defense spot. Distance: " << builderpos.distance2D(spotpos) << " Height: " << ai->pather->HeightMap[y * ai->pather->PathMapXSize + x] << " Threat " << ai->tm->ThreatAtThisPoint(spotpos)<< " Score: " << myscore);
			if(myscore> bestscore && ai->pather->VehicleArray[y * ai->pather->PathMapXSize + x]){
				bestscore = myscore;
				bestspotx = x;
				bestspoty = y;
			}
		}
	}
	L("old:" << ai->math->TimerSecs());
	*/
	float bestscore_fast = 0;
	int bestspotx_fast = 0;
	int bestspoty_fast = 0;
	ai->math->TimerStart();
	
	spotFinder->SetRadius(Range);
	float* sumMap = spotFinder->GetSumMap();
	// Hack to find a good start: 
	{
		int x = (int) (builderpos.x / f3multiplier);
		int y = (int) (builderpos.z / f3multiplier);
		if (x<0) x=0;
		if (y<0) y=0;
		if (x>ai->pather->PathMapXSize-1) x=ai->pather->PathMapXSize-1;
		if (y>ai->pather->PathMapYSize-1) y=ai->pather->PathMapYSize-1;
		float fastSumMap = sumMap[y * ai->pather->PathMapXSize + x];
		float3 spotpos = float3(x*f3multiplier,0,y*f3multiplier);
		float myscore = fastSumMap/(builderpos.distance2D(spotpos) + averagemapsize / 8) * ((ai->pather->HeightMap[y * ai->pather->PathMapXSize + x]*heightK + 200) / (ai->pather->AverageHeight + 10)) / (ai->tm->ThreatAtThisPoint(spotpos)+0.01);
		bestscore_fast = myscore;
		bestspotx_fast = x;
		bestspoty_fast = y;
		//L("Starting with bestscore_fast: " << bestscore_fast);
	}
	
	
	
	//L("ai->pather->PathMapXSize: " << ai->pather->PathMapXSize);
	//L("ai->pather->PathMapYSize: " << ai->pather->PathMapYSize);
	//L("ai->pather->PathMapXSize / CACHEFACTOR: " << ai->pather->PathMapXSize / CACHEFACTOR);
	//L("ai->pather->PathMapYSize / CACHEFACTOR: " << ai->pather->PathMapYSize / CACHEFACTOR);
	int skipCount = 0;
	int testCount = 0;
	for(int x = 0; x < ai->pather->PathMapXSize / CACHEFACTOR; x++){
		for(int y = 0; y < ai->pather->PathMapYSize / CACHEFACTOR; y++){
			//L("x: " << x << ", y: " << y);
			
			CachePoint *cachePoint = spotFinder->GetBestCachePoint(x, y);
			float bestScoreInThisBox = cachePoint->maxValueInBox;
			
			// Guess that this point is as good as posible:
			
			// Make the best posible build spot (the one nearest to the builder):
			float bestX = builderpos.x / f3multiplier;
			float bestY = builderpos.z / f3multiplier;
			if(bestX > x * CACHEFACTOR)
			{
				if(bestX > (x * CACHEFACTOR + CACHEFACTOR))
				{
					bestX = x * CACHEFACTOR + CACHEFACTOR;
				}
			} else {
				bestX = x * CACHEFACTOR;
			}
			
			if(bestY > y * CACHEFACTOR)
			{
				if(bestY > (y * CACHEFACTOR + CACHEFACTOR))
				{
					bestY = y * CACHEFACTOR + CACHEFACTOR;
				}
			} else {
				bestY = y * CACHEFACTOR;
			}
			
			//L("bestX: " << bestX << ", bestY: " << bestY);
			
			float3 bestPosibleSpotpos = float3(bestX*f3multiplier,0,bestY*f3multiplier);
			float bestThreatAtThisPoint = 0.01 + ai->tm->GetAverageThreat() -1; // This must be guessed atm, set it to the best posible (slow)
			//L("bestThreatAtThisPoint: " << bestThreatAtThisPoint);
			float bestDistance = builderpos.distance2D(bestPosibleSpotpos);
			//L("bestDistance: " << bestDistance);
			//L("cachePoint->maxValueInBox: " << cachePoint->maxValueInBox << ", cachePoint->x: " << cachePoint->x << ", cachePoint->y: " << cachePoint->y);
			float bestHeight = ai->pather->HeightMap[cachePoint->y * ai->pather->PathMapXSize + cachePoint->x]*heightK + 200; // This must be guessed atm
			//L("bestHeight: " << bestHeight);
			float bestPosibleMyScore = bestScoreInThisBox / (bestDistance + averagemapsize / 8) * (bestHeight + 200) / bestThreatAtThisPoint;
			//L("bestPosibleMyScore: " << bestPosibleMyScore);
			// Have a best posible score for all points inside the size of the cache box.
			// If this is better than the current known best, test if any points inside the box is better:
			//L("bestscore_fast: " << bestscore_fast);
			if(bestPosibleMyScore > bestscore_fast)
			{
				testCount++;
				// Must test all the points inside this box:
				for(int sx = x * CACHEFACTOR; sx < ai->pather->PathMapXSize && sx < (x * CACHEFACTOR + CACHEFACTOR); sx++){
					for(int sy = y * CACHEFACTOR; sy < ai->pather->PathMapYSize && sy < (y * CACHEFACTOR + CACHEFACTOR); sy++){
						if (ai->uh->Distance2DToNearestFactory(sx*f3multiplier,sy*f3multiplier)>DEFCBS_RADIUS) continue;
						if (ch && ch->GetCoverage(float3(sx*f3multiplier,0,sy*f3multiplier))!=0) continue;
						float fastSumMap = sumMap[sy * ai->pather->PathMapXSize + sx];
						float3 spotpos = float3(sx*f3multiplier,0,sy*f3multiplier);
						float myscore = fastSumMap/(builderpos.distance2D(spotpos) + averagemapsize / 4) *
						(ai->pather->HeightMap[sy * ai->pather->PathMapXSize + sx]*heightK+200) / (ai->tm->ThreatAtThisPoint(spotpos)+0.01);
						//L("Checking defense spot. fastSumMap: " << fastSumMap << ", Distance: " << builderpos.distance2D(spotpos) << " Height: " << ai->pather->HeightMap[sy * ai->pather->PathMapXSize + sx] << " Threat " << ai->tm->ThreatAtThisPoint(spotpos)<< " Score: " << myscore);
						if(myscore > bestscore_fast && BuildMaskArray[sy * ai->pather->PathMapXSize + sx] == 0 && ai->cb->CanBuildAt(def,spotpos)){ // COULD BE REALLY SLOW!
							bestscore_fast = myscore;
							bestspotx_fast = sx;
							bestspoty_fast = sy;
							//L("new bestscore_fast: " << myscore << "sx: " << sx << ", sy: " << sy);
						}
					}
				}
			}
			else
			{
				//L("Skiping box");
				skipCount++;
			}	
			

		}
	}
	L("spotFinder new time:" << ai->math->TimerSecs());
	L("skipCount: " << skipCount << ", testCount: " << testCount);
	/*
	if(bestspotx_fast != bestspotx || bestspoty_fast != bestspoty || bestscore_fast != bestscore)
	{
		L("ERROR: bestscore_fast: " << bestscore_fast << ", bestscore: "  << bestscore_fast);
		L("bestspotx_fast: " << bestspotx_fast << ", bestspotx: "  << bestspotx << ", bestspoty_fast: " << bestspoty_fast << ", bestspoty: "  << bestspoty );
	}*/
	bestspotx = bestspotx_fast;
	bestspoty = bestspoty_fast;
	
	
	/*
	ai->math->TimerStart();
	//spotFinder->BackingArrayChanged();
	spotFinder->SetRadius(Range);
	float* sumMap = spotFinder->GetSumMap();
	//L("GetSumMap:" << ai->math->TimerSecs());
	ai->math->TimerStart();
	bestscore = 0;
	bestspotx = 0;
	bestspoty = 0;
	for(int x = 0; x < ai->pather->PathMapXSize; x++){
		for(int y = 0; y < ai->pather->PathMapYSize; y++){
			float myscore = sumMap[y * ai->pather->PathMapXSize + x];
			float3 spotpos = float3(x*f3multiplier,0,y*f3multiplier);		
			myscore = myscore/(builderpos.distance2D(spotpos) + averagemapsize / 4) * (ai->pather->HeightMap[y * ai->pather->PathMapXSize + x]+200) / (ai->tm->ThreatAtThisPoint(spotpos)+0.01);
			//L("Checking defense spot. Distance: " << builderpos.distance2D(spotpos) << " Height: " << ai->pather->HeightMap[y * ai->pather->PathMapXSize + x] << " Threat " << ai->tm->ThreatAtThisPoint(spotpos)<< " Score: " << myscore);
			if(myscore> bestscore && ai->pather->VehicleArray[y * ai->pather->PathMapXSize + x]){
				bestscore = myscore;
				bestspotx = x;
				bestspoty = y;
			}
		}
	}
	
	L("spotFinder new time:" << ai->math->TimerSecs());
	*/
	ai->math->StopTimer(getDefensePosTime);
	return float3(bestspotx*f3multiplier,0,bestspoty*f3multiplier);
}
void CMapDamage::Explosion(const float3& pos, float strength,float radius)
{
	if(pos.x<0 || pos.z<0 || pos.x>gs->mapx*SQUARE_SIZE || pos.z>gs->mapy*SQUARE_SIZE){
//		info->AddLine("Map damage explosion outside map %.0f %.0f",pos.x,pos.z);
		return;
	}
	if(strength<10 || radius<8)
		return;

	radius*=1.5;

	Explo* e=new Explo;
	e->pos=pos;
	e->strength=strength;
	e->ttl=10;
	e->x1=max((int)(pos.x-radius)/SQUARE_SIZE,2);
	e->x2=min((int)(pos.x+radius)/SQUARE_SIZE,gs->mapx-3);
	e->y1=max((int)(pos.z-radius)/SQUARE_SIZE,2);
	e->y2=min((int)(pos.z+radius)/SQUARE_SIZE,gs->mapy-3);

	float baseStrength=-pow(strength,0.6f)*3/mapHardness;
	float invRadius=1.0/radius;
	for(int y=e->y1;y<=e->y2;++y){
		for(int x=e->x1;x<=e->x2;++x){
			if(readmap->groundBlockingObjectMap[y*gs->mapx+x] && readmap->groundBlockingObjectMap[y*gs->mapx+x]->blockHeightChanges){			//dont change squares with building on them here
				e->squares.push_back(0);
				continue;
			}
			float dist=pos.distance2D(float3(x*SQUARE_SIZE,0,y*SQUARE_SIZE));							//calculate the distance
			float relDist=dist*invRadius;																					//normalize distance
			float dif=baseStrength*craterTable[int(relDist*200)]*invHardness[readmap->typemap[(y/2)*gs->hmapx+x/2]];

			float prevDif=readmap->heightmap[y*(gs->mapx+1)+x]-readmap->orgheightmap[y*(gs->mapx+1)+x];

//			prevDif+=dif*5;

			if(prevDif*dif>0)
				dif/=fabs(prevDif)*0.1+1;
			e->squares.push_back(dif);
			if(dif<-0.3 && strength>200)
				treeDrawer->RemoveGrass(x,y);
		}
	}
	std::vector<CUnit*> units=qf->GetUnitsExact(pos,radius);
	for(std::vector<CUnit*>::iterator ui=units.begin();ui!=units.end();++ui){		//calculate how much to offset the buildings in the explosion radius with (while still keeping the ground under them flat
		if((*ui)->blockHeightChanges && (*ui)->isMarkedOnBlockingMap){
			CUnit* unit=*ui;
			float3& upos=(*ui)->pos;

			float totalDif=0;
			for(int z=unit->mapPos.y; z<unit->mapPos.y+unit->ysize; z++){
				for(int x=unit->mapPos.x; x<unit->mapPos.x+unit->xsize; x++){
					float dist=pos.distance2D(float3(x*SQUARE_SIZE,0,z*SQUARE_SIZE));							//calculate the distance
					float relDist=dist*invRadius;																					//normalize distance
					float dif=baseStrength*craterTable[int(relDist*200)]*invHardness[readmap->typemap[(z/2)*gs->hmapx+x/2]];
					float prevDif=readmap->heightmap[z*(gs->mapx+1)+x]-readmap->orgheightmap[z*(gs->mapx+1)+x];

					if(prevDif*dif>0)
						dif/=fabs(prevDif)*0.1+1;
					totalDif+=dif;
				}
			}
			totalDif/=unit->xsize*unit->ysize;
			if(totalDif!=0){
				ExploBuilding eb;
				eb.id=(*ui)->id;
				eb.dif=totalDif;
				eb.tx1=unit->mapPos.x;
				eb.tx2=unit->mapPos.x+unit->xsize;
				eb.tz1=unit->mapPos.y;
				eb.tz2=unit->mapPos.y+unit->ysize;
				e->buildings.push_back(eb);
			}
		}
	}

	explosions.push_back(e);

	readmap->Explosion(pos.x,pos.z,strength);
}
Example #18
0
void CUnitHandler::BuildTaskCreate(int id) {
	const UnitDef* newUnitDef = ai->cb->GetUnitDef(id);
	const UnitCategory category = ai->ut->GetCategory(id);
	const float3 pos = ai->cb->GetUnitPos(id);

	if ((!newUnitDef->movedata || category == CAT_DEFENCE) && !newUnitDef->canfly && category != CAT_LAST) {
		// this needs to change, so that it can make more stuff
		if (category >= CAT_LAST) {
			return;
		}

		BuildTask bt;
		bt.id = -1;

		std::list<TaskPlan>::iterator i;

		for (i = TaskPlans[category].begin(); i != TaskPlans[category].end(); i++) {
			if (pos.distance2D(i->pos) < 1.0f && newUnitDef == i->def) {
				bt.category = category;
				bt.id       = id;
				bt.pos      = i->pos;
				bt.def      = newUnitDef;

				std::list<BuilderTracker*> moveList;

				for (std::list<BuilderTracker*>::iterator builder = i->builderTrackers.begin(); builder != i->builderTrackers.end(); builder++) {
					moveList.push_back(*builder);
				}

				for (std::list<BuilderTracker*>::iterator builder = moveList.begin(); builder != moveList.end(); builder++) {
					TaskPlanRemove(*builder);
					BuildTaskAddBuilder(&bt, *builder);
				}

				// there can not be more than one found TaskPlan
				break;
			}
		}

		if (bt.id == -1) {
			// buildtask creation error (can happen if builder manages
			// to restart a dead building, or a human has taken control),
			// make one anyway
			std::stringstream msg;
				msg << "[CUnitHandler::BuildTaskCreate()][frame=" << ai->cb->GetCurrentFrame() << "]\n";
				msg << "\tBuildTask Creation Error for task with ID " << id << "\n";
			ai->GetLogger()->Log(msg.str());

			if (category == CAT_DEFENCE) {
				ai->dm->AddDefense(pos, newUnitDef);
			}

			bt.category = category;
			bt.id = id;
			bt.pos = pos;
			bt.def = newUnitDef;

			// if we have any friendly builders
			for (std::list<BuilderTracker*>::iterator i = BuilderTrackers.begin(); i != BuilderTrackers.end(); i++) {
				BuilderTracker* builderTracker = *i;

				// check what builder is doing
				const CCommandQueue* cq = ai->cb->GetCurrentUnitCommands(builderTracker->builderID);

				if (!cq->empty()) {
					Command c = cq->front();

					const bool b0 = (c.id == -newUnitDef->id && c.params[0] == pos.x && c.params[2] == pos.z); // at this pos
					const bool b1 = (c.id == CMD_REPAIR && c.params[0] == id); // at this unit (id)
					const bool b2 = (c.id == CMD_GUARD  && c.params[0] == id); // at this unit (id)
					const bool b3 = b0 || b1 || b2;

					if (b3) {
						if (builderTracker->buildTaskId != 0) {
							BuildTask* buildTask = GetBuildTask(builderTracker->buildTaskId);

							if (buildTask->builderTrackers.size() > 1) {
								BuildTaskRemove(builderTracker);
							} else {
								// only builder of this thing, and now idle
								BuildTaskRemove(builderTracker);
							}
						}

						if (builderTracker->taskPlanId != 0) {
							GetTaskPlan(builderTracker->taskPlanId);
							TaskPlanRemove(builderTracker);
						}
						if (builderTracker->factoryId != 0) {
							FactoryBuilderRemove(builderTracker);
						}

						// this builder is now free
						if (builderTracker->idleStartFrame == -2) {
							IdleUnitRemove(builderTracker->builderID);
						}

						// add it to this task
						BuildTaskAddBuilder(&bt, builderTracker);

						msg.str("");
							msg << "\tadded builder " << builderTracker->builderID << " to";
							msg << " build-task with ID " << builderTracker->buildTaskId << "\n";
						ai->GetLogger()->Log(msg.str());
					}
				}
			}

			// add the task anyway
			BuildTasks[category].push_back(bt);
		}
		else {
			if (category == CAT_DEFENCE)
				ai->dm->AddDefense(pos,newUnitDef);

			BuildTasks[category].push_back(bt);
		}
	}
}
Example #19
0
void CBasicMapDamage::Explosion(const float3& pos, float strength, float radius)
{
	if ((pos.x < 0.0f) || (pos.x > gs->mapx * SQUARE_SIZE)) {
		return;
	}
	if ((pos.z < 0.0f) || (pos.z > gs->mapy * SQUARE_SIZE)) {
		return;
	}

	if (strength < 10.0f || radius < 8.0f) {
		return;
	}

	radius *= 1.5f;

	Explo* e = new Explo;
	e->pos = pos;
	e->strength = strength;
	e->ttl = 10;
	e->x1 = std::max((int) (pos.x - radius) / SQUARE_SIZE,            2);
	e->x2 = std::min((int) (pos.x + radius) / SQUARE_SIZE, gs->mapx - 3);
	e->y1 = std::max((int) (pos.z - radius) / SQUARE_SIZE,            2);
	e->y2 = std::min((int) (pos.z + radius) / SQUARE_SIZE, gs->mapy - 3);
	e->squares.reserve((e->y2 - e->y1 + 1) * (e->x2 - e->x1 + 1));

	const float* curHeightMap = readMap->GetCornerHeightMapSynced();
	const float* orgHeightMap = readMap->GetOriginalHeightMapSynced();
	const unsigned char* typeMap = readMap->GetTypeMapSynced();
	const float baseStrength = -math::pow(strength, 0.6f) * 3 / mapHardness;
	const float invRadius = 1.0f / radius;

	for (int y = e->y1; y <= e->y2; ++y) {
		for (int x = e->x1; x <= e->x2; ++x) {
			const CSolidObject* so = groundBlockingObjectMap->GroundBlockedUnsafe(y * gs->mapx + x);

			// do not change squares with buildings on them here
			if (so && so->blockHeightChanges) {
				e->squares.push_back(0.0f);
				continue;
			}

			// calculate the distance and normalize it
			const float expDist = pos.distance2D(float3(x * SQUARE_SIZE, 0, y * SQUARE_SIZE));
			const float relDist = std::min(1.0f, expDist * invRadius);
			const unsigned int tableIdx = relDist * CRATER_TABLE_SIZE;

			float dif =
					baseStrength * craterTable[tableIdx] *
					invHardness[typeMap[(y / 2) * gs->hmapx + x / 2]];

			// FIXME: compensate for flattened ground under dead buildings
			const float prevDif =
				curHeightMap[y * gs->mapxp1 + x] -
				orgHeightMap[y * gs->mapxp1 + x];

			if (prevDif * dif > 0.0f) {
				dif /= math::fabs(prevDif) * 0.1f + 1;
			}

			e->squares.push_back(dif);

			if (dif < -0.3f && strength > 200.0f) {
				treeDrawer->RemoveGrass(float3(x * SQUARE_SIZE, 0.0f, y * SQUARE_SIZE));
			}
		}
	}

	// calculate how much to offset the buildings in the explosion radius with
	// (while still keeping the ground below them flat)
	const std::vector<CUnit*>& units = quadField->GetUnitsExact(pos, radius);
	for (std::vector<CUnit*>::const_iterator ui = units.begin(); ui != units.end(); ++ui) {
		CUnit* unit = *ui;

		if (!unit->blockHeightChanges) { continue; }
		if (!unit->IsBlocking()) { continue; }

		float totalDif = 0.0f;

		for (int z = unit->mapPos.y; z < unit->mapPos.y + unit->zsize; z++) {
			for (int x = unit->mapPos.x; x < unit->mapPos.x + unit->xsize; x++) {
				// calculate the distance and normalize it
				const float expDist = pos.distance2D(float3(x * SQUARE_SIZE, 0, z * SQUARE_SIZE));
				const float relDist = std::min(1.0f, expDist * invRadius);
				const unsigned int tableIdx = relDist * CRATER_TABLE_SIZE;

				float dif =
						baseStrength * craterTable[tableIdx] *
						invHardness[typeMap[(z / 2) * gs->hmapx + x / 2]];
				const float prevDif =
						curHeightMap[z * gs->mapxp1 + x] -
						orgHeightMap[z * gs->mapxp1 + x];

				if (prevDif * dif > 0.0f) {
					dif /= math::fabs(prevDif) * 0.1f + 1;
				}

				totalDif += dif;
			}
		}

		totalDif /= (unit->xsize * unit->zsize);

		if (totalDif != 0.0f) {
			ExploBuilding eb;
			eb.id = (*ui)->id;
			eb.dif = totalDif;
			eb.tx1 = unit->mapPos.x;
			eb.tx2 = unit->mapPos.x + unit->xsize;
			eb.tz1 = unit->mapPos.y;
			eb.tz2 = unit->mapPos.y + unit->zsize;
			e->buildings.push_back(eb);
		}
	}

	explosions.push_back(e);
}
float3 CDefenseMatrix::GetDefensePos(const UnitDef* def, float3 builderpos) {
	ai->ut->UpdateChokePointArray();
	int f3multiplier = 8 * THREATRES;
	int Range = int(ai->ut->GetMaxRange(def) / f3multiplier);
	int bestspotx = 0;
	int bestspoty = 0;
	float averagemapsize = sqrt(float(ai->pather->PathMapXSize * ai->pather->PathMapYSize)) * f3multiplier;
	float bestscore_fast = 0.0f;
	int bestspotx_fast = 0;
	int bestspoty_fast = 0;
	ai->math->TimerStart();

	spotFinder->SetRadius(Range);
	float* sumMap = spotFinder->GetSumMap();

	// hack to find a good start
	{
		int x = (int) (builderpos.x / f3multiplier);
		int y = (int) (builderpos.z / f3multiplier);
		float fastSumMap = sumMap[y * ai->pather->PathMapXSize + x];
		float3 spotpos = float3(x * f3multiplier, 0, y * f3multiplier);
		float myscore = fastSumMap / (builderpos.distance2D(spotpos) + averagemapsize / 8) * ((ai->pather->HeightMap[y * ai->pather->PathMapXSize + x] + 200) / (ai->pather->AverageHeight + 10)) / (ai->tm->ThreatAtThisPoint(spotpos) + 0.01);
		bestscore_fast = myscore;
		bestspotx_fast = x;
		bestspoty_fast = y;
	}

	int skipCount = 0;
	int testCount = 0;

	for (int x = 0; x < ai->pather->PathMapXSize / CACHEFACTOR; x++) {
		for (int y = 0; y < ai->pather->PathMapYSize / CACHEFACTOR; y++) {
			// KLOOTNOTE: SOMETIMES RETURNS UNINITIALIZED CRAP?
			// (gdb) print cachePoint->y   $2 = 219024104
			// (gdb) print cachePoint->x   $3 = -1215908928
			CachePoint* cachePoint = spotFinder->GetBestCachePoint(x, y);

			if (!cachePoint) {
				return ZeroVector;
			}

			float bestScoreInThisBox = cachePoint->maxValueInBox;

			// guess that this point is as good as posible
			// make best posible build spot (nearest to builder)
			float bestX = builderpos.x / f3multiplier;
			float bestY = builderpos.z / f3multiplier;

			if (bestX > x * CACHEFACTOR) {
				if (bestX > (x * CACHEFACTOR + CACHEFACTOR)) {
					bestX = x * CACHEFACTOR + CACHEFACTOR;
				}
			}
			else {
				bestX = x * CACHEFACTOR;
			}

			if (bestY > y * CACHEFACTOR) {
				if (bestY > (y * CACHEFACTOR + CACHEFACTOR)) {
					bestY = y * CACHEFACTOR + CACHEFACTOR;
				}
			}
			else {
				bestY = y * CACHEFACTOR;
			}

			float3 bestPosibleSpotpos = float3(bestX * f3multiplier, 0, bestY * f3multiplier);
 			// this must be guessed, set it to the best possible (slow)
			float bestThreatAtThisPoint = 0.01 + ai->tm->GetAverageThreat() - 1;
			float bestDistance = builderpos.distance2D(bestPosibleSpotpos);
			float bestHeight = ai->pather->HeightMap[cachePoint->y * ai->pather->PathMapXSize + cachePoint->x] + 200;
			float bestPosibleMyScore = bestScoreInThisBox / (bestDistance + averagemapsize / 4) * (bestHeight + 200) / bestThreatAtThisPoint;
			// have a best posible score for all points inside the size of the cache box
			// if this is better than the current known best, test if any point inside the box is better

			if (bestPosibleMyScore > bestscore_fast) {
				testCount++;
				// must test all the points inside this box
				for (int sx = x * CACHEFACTOR; sx < ai->pather->PathMapXSize && sx < (x * CACHEFACTOR + CACHEFACTOR); sx++) {
					for (int sy = y * CACHEFACTOR; sy < ai->pather->PathMapYSize && sy < (y * CACHEFACTOR + CACHEFACTOR); sy++) {
						float fastSumMap = sumMap[sy * ai->pather->PathMapXSize + sx];
						float3 spotpos = float3(sx * f3multiplier, 0, sy * f3multiplier);
						float myscore = fastSumMap / (builderpos.distance2D(spotpos) + averagemapsize / 4) * (ai->pather->HeightMap[sy * ai->pather->PathMapXSize + sx]+200) / (ai->tm->ThreatAtThisPoint(spotpos) + 0.01);
						// THIS COULD BE REALLY SLOW!
						if (myscore > bestscore_fast && BuildMaskArray[sy * ai->pather->PathMapXSize + sx] == 0 && ai->cb->CanBuildAt(def, spotpos)) {
							bestscore_fast = myscore;
							bestspotx_fast = sx;
							bestspoty_fast = sy;
						}
					}
				}
			}
			else {
				// skip box
				skipCount++;
			}
		}
	}

	bestspotx = bestspotx_fast;
	bestspoty = bestspoty_fast;

	return float3(bestspotx * f3multiplier, 0, bestspoty * f3multiplier);
}