コード例 #1
0
CvPlot* CvArmyAI::CheckTargetReached(PlayerTypes eEnemy, bool bNavalOp, int iMaxDistance)
{
	//check if we're at the target
	CvPlot *pTargetPlot = GetGoalPlot();
	CvPlot *pCenterOfMass = GetCenterOfMass(NO_DOMAIN);
	if(pCenterOfMass && pTargetPlot && plotDistance(*pCenterOfMass,*pTargetPlot) <= iMaxDistance)
		return pTargetPlot;

	//check early termination if we ran into the enemy
	if(GetArmyAIState() == ARMYAISTATE_MOVING_TO_DESTINATION)
	{
		CvPlot*	pEnemyPlot = DetectNearbyEnemy(eEnemy, bNavalOp);
		if(pEnemyPlot != NULL)
		{
			CvCity* pCity = pEnemyPlot->getWorkingCity();
			if(pCity != NULL)
			{
				if (bNavalOp && pCity->isCoastal() && pCity->waterArea()==pTargetPlot->area())
					pEnemyPlot = pCity->plot();

				if (!bNavalOp && pCity->area()==pTargetPlot->area())
					pEnemyPlot = pCity->plot();

				if (pEnemyPlot!=GetGoalPlot())
				{
					if(GC.getLogging() && GC.getAILogging())
					{
						CvString strMsg;
						strMsg.Format("Switching target from %d,%d to closest city at %d,%d", GetGoalX(), GetGoalY(), pEnemyPlot->getX(), pEnemyPlot->getY() );
						GET_PLAYER(m_eOwner).getAIOperation(m_iOperationID)->LogOperationSpecialMessage(strMsg);
					}
				}

				return pEnemyPlot;
			}
		}
	}

	return NULL;
}
コード例 #2
0
/// Get center of mass of units in army (account for world wrap!)
CvPlot* CvArmyAI::GetCenterOfMass(float* pfVarX, float* pfVarY)
{
	int iTotalX = 0;
	int iTotalY = 0;
	int iNumUnits = 0;

	UnitHandle pUnit = GetFirstUnit();
	if (!pUnit)
		return NULL;

	int iTotalX2 = 0;
	int iTotalY2 = 0;
	int iWorldWidth = GC.getMap().getGridWidth();
	int iWorldHeight = GC.getMap().getGridHeight();

	//the first unit is our reference ...
	int iRefX = pUnit->getX();
	int iRefY = pUnit->getY();
	iNumUnits++;
	pUnit = GetNextUnit();

	while(pUnit)
	{
		int iDX = pUnit->getX() - iRefX;
		int iDY = pUnit->getY() - iRefY;

		if (GC.getMap().isWrapX())
		{
			if( iDX > +(iWorldWidth / 2))
				iDX -= iWorldWidth;
			if( iDX < -(iWorldWidth / 2))
				iDX += iWorldWidth;
		}
		if (GC.getMap().isWrapY())
		{
			if( iDY > +(iWorldHeight / 2))
				iDY -= iWorldHeight;
			if( iDY < -(iWorldHeight / 2))
				iDY += iWorldHeight;
		}

		iTotalX += iDX;
		iTotalY += iDY;
		iTotalX2 += iDX*iDX;
		iTotalY2 += iDY*iDY;
		iNumUnits++;

		pUnit = GetNextUnit();
	}

	if (iNumUnits==0)
		return NULL;

	//this is for debugging
	float fVarX = (iTotalX2 / (float)iNumUnits) - (iTotalX/(float)iNumUnits)*(iTotalX/(float)iNumUnits);
	float fVarY = (iTotalY2 / (float)iNumUnits) - (iTotalY/(float)iNumUnits)*(iTotalY/(float)iNumUnits);

	//finally, compute average (with rounding)
	int iAvgX = (iTotalX + (iNumUnits / 2)) / iNumUnits + iRefX;
	int iAvgY = (iTotalY + (iNumUnits / 2)) / iNumUnits + iRefY;

	if (fVarX > 64 || fVarY > 64)
	{
		CvString msg = CvString::format("Warning: Army %d with %d units Center of Mass (%d,%d) has a large variance (%.2f,%.2f)\n", GetID(), iNumUnits, iAvgX, iAvgY, fVarX, fVarY);
		OutputDebugString( msg.c_str() );
	}

	//this handles wrapped coordinates
	CvPlot* pCOM = GC.getMap().plot(iAvgX, iAvgY);

	if (!pCOM)
		return NULL;

	if (pfVarX)
		*pfVarX = fVarX;
	if (pfVarY)
		*pfVarY = fVarY;

	//don't return it directly but use the plot of the closest unit
	pUnit = GetFirstUnit();
	std::vector<SPlotWithScore> vPlots;
	while (pUnit)
	{
		if (pUnit->plot()->getDomain()==GetDomainType())
		{
			int iDistToCOM = plotDistance(*pUnit->plot(),*pCOM);
			int iDistToTarget = plotDistance(pUnit->getX(),pUnit->getY(),GetGoalX(),GetGoalY());
			vPlots.push_back( SPlotWithScore(pUnit->plot(),iDistToCOM*100+iDistToTarget) );
		}

		pUnit = GetNextUnit();
	}

	if (vPlots.empty())
		return NULL;

	//this sorts ascending!
	std::sort(vPlots.begin(),vPlots.end());
	return vPlots.front().pPlot;
}